Skip to content

j-g00da/serde-more

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

14 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

serde_more

A Rust procedural macro to add arbitrary computed fields when serializing structs with serde.

Crate Docs CI Deps

Examples

Basic Usage

use serde_more::SerializeMore;
use serde_json::json;

#[derive(SerializeMore)]
#[more(key="next")]
#[more(key="previous", position="front")]
struct Index {
    current: u32,
}

impl Index {
    fn next(&self) -> u32 {
        self.current.saturating_add(1)
    }
    fn previous(&self) -> u32 {
        self.current.saturating_sub(1)
    }
}

fn main() {
    let idx = Index { current: 5 };
    let value = serde_json::to_value(&idx).unwrap();
    assert_eq!(value, json!({
        "previous": 4,
        "current": 5,
        "next": 6
    }));
}

Multiple Extra Fields

You can add multiple #[more(...)] attributes to include several computed fields:

use serde_more::SerializeMore;
use serde_json::json;

#[derive(SerializeMore)]
#[more(k="next", v="get_next")]
#[more(k="description", v="get_description")]
#[more(k="name")]
struct Index {
    current: u32,
}

impl Index {
    fn get_next(&self) -> u32 {
        self.current + 1
    }
    
    fn get_description(&self) -> &str {
        "Index struct"
    }
    
    fn name(&self) -> &str {
        "Index"
    }
}

fn main() {
    let idx = Index { current: 5 };
    let value = serde_json::to_value(&idx).unwrap();
    assert_eq!(value, json!({
        "current": 5,
        "next": 6,
        "description": "Index struct",
        "name": "Index"
    }));
}

Works with Serde Attributes

The macro is fully compatible with serde attributes:

use serde_more::SerializeMore;
use serde_json::json;

#[derive(SerializeMore)]
#[serde(rename_all = "kebab-case")]
#[more(k="extraVal", v="extra_val")]
struct WithSerdeAttrs {
    field_name: u32,
    #[serde(skip_serializing_if = "Option::is_none")]
    opt_value: Option<u8>,
}

impl WithSerdeAttrs {
    fn extra_val(&self) -> &'static str {
        "ok"
    }
}

fn main() {
    let data = WithSerdeAttrs {
        field_name: 1,
        opt_value: None
    };
    let value = serde_json::to_value(&data).unwrap();
    assert_eq!(value, json!({
        "field-name": 1,
        "extraVal": "ok"
    }));
}

Works with serde_as

The macro also works with serde_with::serde_as:

use serde_more::SerializeMore;
use serde_with::serde_as;
use serde_json::json;

#[serde_as]
#[derive(SerializeMore)]
#[more(k="payload_len")]
struct WithSerdeAsAttrs {
    #[serde_as(as = "serde_with::hex::Hex")]
    payload: Vec<u8>,
}

impl WithSerdeAsAttrs {
    fn payload_len(&self) -> usize {
        self.payload.len()
    }
}

fn main() {
    let data = WithSerdeAsAttrs {
        payload: vec![0x0a, 0xff]
    };
    let value = serde_json::to_value(&data).unwrap();
    assert_eq!(value, json!({
        "payload": "0aff",
        "payload_len": 2
    }));
}

Attribute Syntax

The #[more(...)] attribute supports the following syntax:

// Full form
#[more(key="field_name", value="method_name")]

// Shorthand (k and v)
#[more(k="field_name", v="method_name")]

// If value/v is omitted, method name is assumed to be the same as key
#[more(k="field_name")]

// Use position="front" to serialize the computed field before the struct fields
#[more(key="field_name", position="front")]

Limitations

Currently only supports structs with named fields.

License

License MIT License Apache 2.0

serde-more is dual-licensed under Apache 2.0 and MIT terms.

About

Procedural macro to add arbitrary data when serializing using serde

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •  

Languages