Add value of a method to serde serialization output - rust

Is there a way to add the value of a method to the serialization output of serde when the struct derives Serialize? I'm looking for something like a "virtual field".
I know I can define my own Serializer / Visitor or use serde_json::builder to get a Value, I just wanted to check first if there was any way to do this using serde_macro magic.
To be clear I want something like this:
#[derive(Serialize, Deserialize, Debug)]
struct Foo {
bar: String,
#[serde(call="Foo::baz")]
baz: i32 // but this is not a real field
}
impl Foo {
fn baz(&self) -> i32 { self.bar.len() as i32 }
}

Here is what I am using now. It's still verbose, and I don't know if it is the best way to handle this, but I thought I would add it here for the record:
#[derive(Deserialize, Debug)]
struct Foo {
bar: String
}
impl Foo {
fn baz(&self) -> i32 { self.bar.len() as i32 }
}
impl ::serde::Serialize for Foo {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer {
#[derive(Serialize)]
struct Extended<'a> {
bar: &'a String,
baz: i32
}
let ext = Extended {
bar: &self.bar,
baz: self.baz()
};
Ok(ext.serialize(serializer)?)
}
}

Related

Late type in Rust

I'm working with two crates: A and B. I control both. I'd like to create a struct in A that has a field whose type is known only to B (i.e., A is independent of B, but B is dependent on A).
crate_a:
#[derive(Clone)]
pub struct Thing {
pub foo: i32,
pub bar: *const i32,
}
impl Thing {
fn new(x: i32) -> Self {
Thing { foo: x, bar: &0 }
}
}
crate_b:
struct Value {};
fn func1() {
let mut x = A::Thing::new(1);
let y = Value {};
x.bar = &y as *const Value as *const i32;
...
}
fn func2() {
...
let y = unsafe { &*(x.bar as *const Value) };
...
}
This works, but it doesn't feel very "rusty". Is there a cleaner way to do this? I thought about using a trait object, but ran into issues with Clone.
Note: My reason for splitting these out is that the dependencies in B make compilation very slow. Value above is actually from llvm_sys. I'd rather not leak that into A, which has no other dependency on llvm.
The standard way to implement something like this is with generics, which are kind of like type variables: they can be "assigned" a particular type, possibly within some constraints. This is how the standard library can provide types like Vec that work with types that you declare in your crate.
Basically, generics allow Thing to be defined in terms of "some unknown type that will become known later when this type is actually used."
Given the example in your code, it looks like Thing's bar field may or may not be set, which suggests that the built-in Option enum should be used. All you have to do is put a type parameter on Thing and pass that through to Option, like so:
pub mod A {
#[derive(Clone)]
pub struct Thing<T> {
pub foo: i32,
pub bar: Option<T>,
}
impl<T> Thing<T> {
pub fn new(x: i32) -> Self {
Thing { foo: x, bar: None }
}
}
}
pub mod B {
use crate::A;
struct Value;
fn func1() {
let mut x = A::Thing::new(1);
let y = Value;
x.bar = Some(y);
// ...
}
fn func2(x: &A::Thing<Value>) {
// ...
let y: &Value = x.bar.as_ref().unwrap();
// ...
}
}
(Playground)
Here, the x in B::func1() has the type Thing<Value>. You can see with this syntax how Value is substituted for T, which makes the bar field Option<Value>.
If Thing's bar isn't actually supposed to be optional, just write pub bar: T instead, and accept a T in Thing::new() to initialize it:
pub mod A {
#[derive(Clone)]
pub struct Thing<T> {
pub foo: i32,
pub bar: T,
}
impl<T> Thing<T> {
pub fn new(x: i32, y: T) -> Self {
Thing { foo: x, bar: y }
}
}
}
pub mod B {
use crate::A;
struct Value;
fn func1() {
let mut x = A::Thing::new(1, Value);
// ...
}
fn func2(x: &A::Thing<Value>) {
// ...
let y: &Value = &x.bar;
// ...
}
}
(Playground)
Note that the definition of Thing in both of these cases doesn't actually require that T implement Clone; however, Thing<T> will only implement Clone if T also does. #[derive(Clone)] will generate an implementation like:
impl<T> Clone for Thing<T> where T: Clone { /* ... */ }
This can allow your type to be more flexible -- it can now be used in contexts that don't require T to implement Clone, while also being cloneable when T does implement Clone. You get the best of both worlds this way.

How to rename `start` and `end` range values with serde?

I have JSON objects with the following format:
{
"name": "foo",
"value": 1234,
"upper_bound": 5000,
"lower_bound": 1000
}
I'd like to use serde to work with these objects, with a struct like
struct MyObject {
name: String,
value: i32,
bound: Range<i32>,
}
Without any modifications, serializing one of these structs yields
{
"name": "foo",
"value": 1234,
"bound": {
"start": 1000,
"end": 5000
}
}
I can apply #[serde(flatten)] to get closer, yielding
{
"name": "foo",
"value": 1234,
"start": 1000,
"end": 5000
}
But adding #[serde(rename...)] doesn't seem to change anything, no matter what kind of arguments I try giving to the rename. Is it possible to flatten the range, and rename the args?
You can use serde attribute with and just use a intermediate structure letting the real implementation to serde:
use core::ops::Range;
use serde::{Deserialize, Serialize};
use serde_json::Error;
#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
struct Foo {
name: String,
value: i32,
#[serde(with = "range_aux", flatten)]
bound: Range<i32>,
}
mod range_aux {
use core::ops::Range;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[derive(Serialize, Deserialize)]
struct RangeAux {
upper_bound: i32,
lower_bound: i32,
}
pub fn serialize<S>(range: &Range<i32>, ser: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
RangeAux::serialize(
&RangeAux {
upper_bound: range.end,
lower_bound: range.start,
},
ser,
)
}
pub fn deserialize<'de, D>(d: D) -> Result<Range<i32>, D::Error>
where
D: Deserializer<'de>,
{
let range_aux: RangeAux = RangeAux::deserialize(d)?;
Ok(Range {
start: range_aux.lower_bound,
end: range_aux.upper_bound,
})
}
}
fn main() -> Result<(), Error> {
let data = r#"{"name":"foo","value":1234,"upper_bound":5000,"lower_bound":1000}"#;
let foo: Foo = serde_json::from_str(data)?;
assert_eq!(
foo,
Foo {
name: "foo".to_string(),
value: 1234,
bound: 1000..5000
}
);
let output = serde_json::to_string(&foo)?;
assert_eq!(data, output);
Ok(())
}
That very close to remote pattern but this doesn't work with generic see serde#1844.
A possible generic version:
use core::ops::Range;
use serde::{Deserialize, Serialize};
use serde_json::Error;
#[derive(Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
struct Foo {
name: String,
value: i32,
#[serde(with = "range_aux", flatten)]
bound: Range<i32>,
}
mod range_aux {
use core::ops::Range;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub fn serialize<S, Idx: Serialize>(range: &Range<Idx>, ser: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
// could require Idx to be Copy or Clone instead of borrowing Idx
#[derive(Serialize)]
struct RangeAux<'a, Idx> {
upper_bound: &'a Idx,
lower_bound: &'a Idx,
}
RangeAux::serialize(
&RangeAux {
upper_bound: &range.end,
lower_bound: &range.start,
},
ser,
)
}
pub fn deserialize<'de, D, Idx: Deserialize<'de>>(d: D) -> Result<Range<Idx>, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
struct RangeAux<Idx> {
upper_bound: Idx,
lower_bound: Idx,
}
let range_aux: RangeAux<Idx> = RangeAux::deserialize(d)?;
Ok(Range {
start: range_aux.lower_bound,
end: range_aux.upper_bound,
})
}
}
fn main() -> Result<(), Error> {
let data = r#"{"name":"foo","value":1234,"upper_bound":5000,"lower_bound":1000}"#;
let foo: Foo = serde_json::from_str(data)?;
assert_eq!(
foo,
Foo {
name: "foo".to_string(),
value: 1234,
bound: 1000..5000
}
);
let output = serde_json::to_string(&foo)?;
assert_eq!(data, output);
Ok(())
}
Not necessarily more concise than a custom serializer, but certainly a good bit more trivial is a solution with [serde(from and into)]. (I feel like I'm posting this on every serde question. :/)
You define an auxiliary, serializable struct that has the JSON structure you want:
#[derive(Deserialize, Serialize, Clone)]
struct AuxMyObject {
name: String,
value: i32,
upper_bound: i32,
lower_bound: i32,
}
Then you explain to rust how your auxiliary struct relates to the original struct. It's a bit tedious (but easy), there may be some macro crates that help lessen the typing load:
impl From<MyObject> for AuxMyObject {
fn from(from: MyObject) -> Self {
Self {
name: from.name,
value: from.value,
lower_bound: from.bound.start,
upper_bound: from.bound.end,
}
}
}
impl From<AuxMyObject> for MyObject {
fn from(from: AuxMyObject) -> Self {
Self {
name: from.name,
value: from.value,
bound: Range {
start: from.lower_bound,
end: from.upper_bound,
},
}
}
}
Lastly, you tell serde to replace your main struct with the auxiliary struct when serializing:
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
#[serde(from = "AuxMyObject", into = "AuxMyObject")]
struct MyObject { … }
Playground

How to both implement deserialize and derive it

I have a struct Foo which I want to be serialised as a single two-part string in JSON, e.g. "01abcdef:42", but as normal in bincode.
(I need it to be serialized normally in bincode for size reasons. In some cases Bar or Baz are large arrays of bytes which take up more than twice the space in hex.)
My current code does just what I want:
pub struct Foo {
pub bar: Bar,
pub baz: Baz
}
impl<'de> ::serde::Deserialize<'de> for Foo {
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<Foo, D::Error> {
use ::serde::de::Error;
use core::str::FromStr;
if d.is_human_readable() {
let sl: &str = ::serde::Deserialize::deserialize(d)?;
Foo::from_str(sl).map_err(D::Error::custom)
} else {
let clone: FooClone = FooClone::deserialize(d)?;
Ok(Foo { bar: clone.bar, baz: clone.baz })
}
}
}
#[derive(Deserialize)]
pub struct FooClone {
pub bar: Bar,
pub baz: Baz
}
I need to manually maintain FooClone as an identical copy of Foo.
I have read this but that have significantly more code to maintain than this struct clone.
How can I both manually implement Deserialize (to handle the JSON two-part string) and yet derive Deserialize for the same struct (to eliminate FooClone)?
Something like this should work. You still use the derive to generate a deserialize function. But since it is a remote derive the type will not implement Deserialize, but gain an inherent function, which you can call inside the manual Deserialize implementation.
#[derive(serde::Deserialize)]
#[serde(remote = "Self")]
pub struct Foo {
pub bar: Bar,
pub baz: Baz,
}
impl<'de> ::serde::Deserialize<'de> for Foo {
fn deserialize<D: ::serde::Deserializer<'de>>(d: D) -> Result<Foo, D::Error> {
use ::serde::de::Error;
use core::str::FromStr;
if d.is_human_readable() {
let sl: &str = ::serde::Deserialize::deserialize(d)?;
Foo::from_str(sl).map_err(D::Error::custom)
} else {
Foo::deserialize(d)
}
}
}

How can I make all the fields of structs publicly readable while enforcing the use of a "new" constructor

Many structs need to enforce the use of a constructor for object creation, but I want to have public read access to all of the fields.
I need to access several levels deep with bish.bash.bosh.wibble.wobble - bish.get_bash().get_bosh().get_wibble().get_wobble() is not somewhere I want to go, for readability and possibly performance reasons.
This horrible kludge is what I'm using:
#[derive(Debug)]
pub struct Foo {
pub bar: u8,
pub baz: u16,
dummy: bool,
}
impl Foo {
pub fn new(bar: u8, baz: u16) -> Foo {
Foo {bar, baz, dummy: true}
}
}
This is obviously wasting a small amount of space, and dummy is causing inconvenience elsewhere.
How should I do this?
Thanks to #hellow I now have a working solution:
use serde::{Serialize, Deserialize}; // 1.0.115
#[derive(Serialize, Deserialize, Debug)]
pub struct Foo {
pub bar: u8,
pub baz: u16,
#[serde(skip)]
_private: (),
}
impl Foo {
pub fn new(bar: u8, baz: u16) -> Foo {
Foo {bar, baz, _private: ()}
}
}

How to write a generic function in Rust that can accept any struct that implements a specific property?

I am trying to understand generics in Rust and have attempted to write a generic function that can multiple any struct that has the property foo by 10. When I use this code, I get the error, no field foo on type T.
struct A {
foo: i8,
bar: String,
}
struct B {
foo: i8,
}
fn go<T>(v: T) {
v.foo * 10
}
fn main() {
let a = A {foo: 1, bar: "bar".to_string()};
let b = B {foo: 2};
println!("{:?},{:?}", go(a), go(b))
}
How can I write a generic function that can accept any struct that implements a foo: i8 property?
Rust doesn't have properties in the way that JavaScript does, so you need to do things a little differently. You'll want to use a trait to expose the foo functionality as a method, and then implement that trait for A and B:
trait Foo {
fn foo(&self) -> i8;
}
struct A {
foo: i8,
bar: String,
}
impl Foo for A {
fn foo(&self) -> i8 {
self.foo
}
}
struct B {
foo: i8,
}
impl Foo for B {
fn foo(&self) -> i8 {
self.foo
}
}
fn go<T: Foo>(v: T) -> i8 {
v.foo() * 10
}
fn main() {
let a = A {
foo: 1,
bar: "bar".to_string(),
};
let b = B { foo: 2 };
println!("{:?},{:?}", go(a), go(b))
}
(Note that I also made go return a value above.)
This provides a Foo trait that exposes foo as a method, implements it for A and B, and then makes go require T to implement Foo. That's the easiest and most straightforward way to accomplish this goal.

Resources