miniserde

repository·master·Indexed 21 days ago

https://github.com/dtolnay/miniserde

A high-performance, minimal JSON serialization/deserialization library for Rust. Designed as a lightweight alternative to Serde, it prioritizes fast compilation, small executable size, and safety against stack overflows by avoiding recursion. It provides Serialize and Deserialize derive macros for braced structs and C-style unit variant enums, and includes a Value enum for generic JSON data.

Tokens
3.5K
Snippets
14
Records
17
Agent score
74%

What's inside miniserde

  1. Supported data structures for miniserde

    master

    Miniserde's derive macros are intentionally minimal and only support a subset of Rust data structures:

    • Structs: Braced structs with named fields.
    • Enums: Enums with C-style unit variants.

    Unsupported structures include:

    • Tuple structs.
    • Enums with data in their variants (e.g., enums with fields).
    • Types that might cause serialization to fail (e.g., Mutex).
  2. Understand miniserde's design trade-offs

    master

    Miniserde is designed for performance and minimal binary size by making specific architectural choices that differ from Serde:

    • No Monomorphization: Serialization and deserialization happen via trait objects. This results in extremely fast compile times and smaller executable sizes because code is not duplicated for every generic parameter.
    • No Recursion: Neither serialization nor deserialization uses recursion. This makes the library safe against stack overflow errors even when processing deeply nested data.
    • Minimal Error Messages: Deserialization errors are returned as a unit struct containing no information. This avoids polluting the instruction cache with error-handling logic in performance-critical paths. If detailed errors are needed, it is recommended to pass the input to serde_json for debugging.
    • Infallible Serialization: json::to_string always succeeds. It does not support types that might fail during serialization (like a poisoned Mutex) and only targets String output rather than fallible I/O streams.
    • JSON Only: The current implementation is specialized for JSON.
  3. How to ignore unknown or unwanted data fields

    master

    In miniserde, when deserializing data, you can use the Visitor::ignore() method to handle fields that are not part of your target data structure. The ignore() method returns a &'static mut dyn Visitor that effectively consumes any incoming data (nulls, booleans, strings, numbers, sequences, or maps) without performing any operations or returning errors. This is useful for making your deserialization logic resilient to extra fields in the input JSON.

    // While the direct usage is typically internal to the deserialization engine,
    // the concept allows the parser to skip unknown keys or values.
    // The Visitor::ignore() method is the mechanism used to discard data.
  4. Serialize and deserialize data with miniserde

    master

    Miniserde provides Serialize and Deserialize derive macros for strongly typed data structures. Use miniserde::json::to_string to convert a type to a JSON string, and miniserde::json::from_str to parse a JSON string back into a type.

    Note that serialization is infallible (always succeeds) and returns a String. Deserialization returns a miniserde::Result, where errors are represented by a unit struct containing no specific error information.

    use miniserde::{json, Serialize, Deserialize};
    
    #[derive(Serialize, Deserialize, Debug)]
    struct Example {
        code: u32,
        message: String,
    }
    
    fn main() -> miniserde::Result<()> {
        let example = Example {
            code: 200,
            message: "reminiscent of Serde".to_owned(),
        };
    
        // Serialize to JSON string
        let j = json::to_string(&example);
        println!("{}", j);
    
        // Deserialize from JSON string
        let out: Example = json::from_str(&j)?;
        println!("{:?}", out);
    
        Ok(())
    }
  5. Customize field names with the `rename` attribute

    master
    Miniserde provides very limited customization compared to Serde. The only supported attribute for the derive macros is rename, which allows you to change the name of a field or variant during serialization/deserialization.
  6. Handle deserialization errors in miniserde

    master

    When using miniserde's deserialization functions, errors are returned via the miniserde::Result<T> type.

    Important Limitation: The miniserde::Error type is an opaque unit struct. It contains no information about why deserialization failed (e.g., missing fields, type mismatches, or syntax errors). If your application requires detailed error messages or diagnostic information to recover from or report specific failures, you should use Serde instead of miniserde.

    // Deserialization returns a Result<T, miniserde::Error>
    // Note that the error provides no context on the failure.
    match miniserde::json::from_str::<MyStruct>(json_data) {
        Ok(data) => println!("Success: {:?}", data),
        Err(e) => println!("Deserialization failed: {}", e), // Prints "miniserde error"
    }
  7. Serialize any serializable type into a JSON string with `json::to_string`

    master

    Use miniserde::json::to_string to convert any type that implements the Serialize trait into a JSON-formatted String. This is the primary way to perform JSON serialization in miniserde.

    use miniserde::{json, Serialize};
    
    #[derive(Serialize, Debug)]
    struct Example {
        code: u32,
        message: String,
    }
    
    fn main() {
        let example = Example {
            code: 200,
            message: "reminiscent of Serde".to_owned(),
        };
    
        let j = json::to_string(&example);
        println!("{}", j);
    }
  8. Use json::to_string to serialize to JSON

    master

    Convert any type implementing the Serialize trait into a JSON String. Serialization in miniserde is infallible, meaning it always succeeds and returns a String rather than a Result.

    let j = json::to_string(&your_struct);
  9. Deserialize a JSON string with json::from_str

    master

    Use miniserde::json::from_str to deserialize a JSON string into a type that implements the Deserialize trait. This function returns a miniserde::Result<T>, which will return Err(Error) if the JSON is malformed or does not match the target type structure.

    use miniserde::{json, Deserialize};
    
    #[derive(Deserialize, Debug)]
    struct Example {
        code: u32,
        message: String,
    }
    
    fn main() -> miniserde::Result<()> {
        let j = r#" {"code": 200, "message": "reminiscent of Serde"} "#;
    
        let out: Example = json::from_str(&j)?;
        println!("{:?}", out);
    
        Ok(())
    }
  10. Implement the Seq trait for sequences

    master

    To serialize a sequence (like a Vec), implement the Seq trait. The next method should return an Option<&dyn Serialize>, providing the next element in the sequence. This is typically used inside a Fragment::Seq(Box<dyn Seq>) returned by Serialize::begin.

    use miniserde::ser::{Fragment, Seq, Serialize};
    
    struct MyVec<T>(Vec<T>);
    
    impl<T> Serialize for MyVec<T>
    where
        T: Serialize,
    {
        fn begin(&self) -> Fragment {
            Fragment::Seq(Box::new(SliceStream { iter: self.0.iter() }))
        }
    }
    
    struct SliceStream<'a, T: 'a> {
        iter: std::slice::Iter<'a, T>,
    }
    
    impl<'a, T> Seq for SliceStream<'a, T>
    where
        T: Serialize,
    {
        fn next(&mut self) -> Option<&dyn Serialize> {
            let element = self.iter.next()?;
            Some(element)
        }
    }