How to serialise only name of variant and ignore value for enum field in struct (serde) - serialization

Given the definitions:
#[derive(Serialize, Deserialize)]
enum Bar {
A(i64),
B(u64),
}
#[derive(Serialize, Deserialize)]
struct Foo {
bar: Bar,
}
the JSON serialisation for
Foo {
bar: Bar::A(123),
}
would be:
{
"bar": "A"
}
It would be ideal to add an attribute to the field in the struct instead of inside the enum definition (the enum will be reused in a struct field where the value needs to be serialised too)

The attribute #[serde(skip)] can be used on tuple variant fields:
use serde::{Serialize, Deserialize}; // 1.0.126
use serde_json; // 1.0.64
#[derive(Serialize, Deserialize)]
enum Bar {
A(#[serde(skip)] i64),
B(#[serde(skip)] u64),
}
#[derive(Serialize, Deserialize)]
struct Foo {
bar: Bar,
}
fn main() {
let foo = Foo { bar: Bar::A(123) };
println!("{}", serde_json::to_string(&foo).unwrap());
}
{"bar":"A"}
If modifying Bar isn't an option, you'll have to do it a bit more manually via #[serde(with = ...)] or #[serde(serialize_with = ...)]:
use serde::{Serialize, Deserialize, ser::Serializer}; // 1.0.126
use serde_json; // 1.0.64
#[derive(Serialize, Deserialize)]
enum Bar {
A(i64),
B(u64),
}
#[derive(Serialize, Deserialize)]
struct Foo {
#[serde(serialize_with = "bar_name_only")]
bar: Bar,
}
fn bar_name_only<S>(bar: &Bar, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let name = match bar {
Bar::A(_) => "A",
Bar::B(_) => "B",
};
serializer.serialize_str(name)
}
fn main() {
let foo = Foo { bar: Bar::A(123) };
println!("{}", serde_json::to_string(&foo).unwrap());
}
{"bar":"A"}

Related

How to properly handle empty, null and valid JSON?

I need to deserialize a JSON file into either None or Some(T) in Rust. The source we are using will provide null or empty, '{}', JSON fields when no values are present. I want to handle both as the None case and only deserialize when the JSON field is not null or empty.
input: {"test": null} -> output: {"test": None}
input: {"test": {}} -> output: {"test": None}
input: {"test": {"valid_json": 42}} -> output: {"test": {"valid_json": 42}}
All of the answers I could find address one case or another but not both.
use serde::{Deserialize, Deserializer};
#[derive(Deserialize, Debug, PartialEq)]
struct Foo {
#[serde(deserialize_with = "object_empty_as_none")]
bar: Option<Bar>,
}
#[derive(Deserialize, Debug, PartialEq)]
struct Bar {
inner: u32,
}
pub fn object_empty_as_none<'de, D, T>(deserializer: D) -> Result<Option<T>, D::Error>
where
D: Deserializer<'de>,
for<'a> T: Deserialize<'a>,
{
#[derive(Deserialize, Debug)]
#[serde(deny_unknown_fields)]
struct Empty {}
#[derive(Deserialize, Debug)]
#[serde(untagged)]
enum Aux<T> {
T(T),
Empty(Empty),
Null,
}
match Deserialize::deserialize(deserializer)? {
Aux::T(t) => Ok(Some(t)),
Aux::Empty(_) | Aux::Null => Ok(None),
}
}
fn main() {
let data = r#"{"bar": null}"#;
let v: Foo = serde_json::from_str(data).unwrap();
assert_eq!(v, Foo { bar: None });
let data = r#"{"bar": {}}"#;
let v: Foo = serde_json::from_str(data).unwrap();
assert_eq!(v, Foo { bar: None });
let data = r#"{"bar": {"inner": 42}}"#;
let v: Foo = serde_json::from_str(data).unwrap();
assert_eq!(
v,
Foo {
bar: Some(Bar { inner: 42 })
}
);
let data = r#"{"bar": {"not_inner": 42}}"#;
let v: Result<Foo, _> = serde_json::from_str(data);
assert!(v.is_err());
}
Should be enough for most case. Remove #[serde(deny_unknown_fields)] on Empty if you want to.
This page tells you how to implement a custom map deserializer, which requires customizing how visit_map produces key-value pairs from the input data. I've basically copied that page and produced a minimal example that implements what you're looking for. Link to playground.
use std::fmt;
use std::marker::PhantomData;
use serde::de::{Deserialize, Deserializer, MapAccess, Visitor};
use serde_json::Value as JsonValue;
use std::collections::HashMap;
#[derive(Debug)]
struct MyMap(HashMap<String, JsonValue>);
impl MyMap {
fn with_capacity(capacity: usize) -> Self {
Self(HashMap::with_capacity(capacity))
}
}
struct MyMapVisitor {
marker: PhantomData<fn() -> MyMap>,
}
impl MyMapVisitor {
fn new() -> Self {
MyMapVisitor {
marker: PhantomData,
}
}
}
impl<'de> Visitor<'de> for MyMapVisitor {
// The type that our Visitor is going to produce.
type Value = MyMap;
// Format a message stating what data this Visitor expects to receive.
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a very special map")
}
// Deserialize MyMap from an abstract "map" provided by the
// Deserializer. The MapAccess input is a callback provided by
// the Deserializer to let us see each entry in the map.
fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let mut map = MyMap::with_capacity(access.size_hint().unwrap_or(0));
// While there are entries remaining in the input, add them
// into our map. Empty Objects get turned into Null.
while let Some((key, value)) = access.next_entry()? {
let value = match value {
JsonValue::Object(o) if o.is_empty() => JsonValue::Null,
_ => value,
};
map.0.insert(key, value);
}
Ok(map)
}
}
// This is the trait that informs Serde how to deserialize MyMap.
impl<'de> Deserialize<'de> for MyMap {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
// Instantiate our Visitor and ask the Deserializer to drive
// it over the input data, resulting in an instance of MyMap.
deserializer.deserialize_map(MyMapVisitor::new())
}
}
fn main() -> serde_json::Result<()> {
let json_str = r#"{"a": null, "b": {}, "c": {"valid_json": 42}}"#;
let v: MyMap = serde_json::from_str(json_str)?;
println!("{:?}", v);
Ok(())
}
This prints MyMap({"b": Null, "c": Object({"valid_json": Number(42)}), "a": Null}) which I believe is what you're after.

Is there a way to tell Serde to use a struct field as a map's key?

I have a map of items that I would like to serialize to a list of structs, each having a field for the corresponding key.
Imagine having a YAML file like this:
name_a:
some_field: 0
name_b:
some_field: 0
name_c:
some_field: 0
And a corresponding structure like this:
struct Item {
name: String,
some_field: usize,
}
I would like to deserialize the named items into a Vec<Item> instead of a Map<String, Item>. The item names (name_a, ...) are put into the name field of the Item objects.
I've attempted the following:
extern crate serde_yaml;
use std::fs::read_to_string;
let contents = read_to_string("file.yml").unwrap();
let items: Vec<Item> = serde_yaml::from_str(&contents).unwrap();
This however doesn't work and produces the invalid type: map, expected a sequence error.
I'd prefer to avoid creating a transient Map<String, PartialItem> that is converted to a Vec, and I would also prefer not to implement an additional PartialItem struct. Using an Option<String> as name would be possible, although I don't think this is optimal.
One way is to deserialize the map yourself:
use std::fmt;
use serde::de::{Deserialize, Deserializer, MapAccess, Visitor};
use serde_derive::Deserialize;
struct ItemMapVisitor {}
impl ItemMapVisitor {
fn new() -> Self {
Self {}
}
}
#[derive(Debug, Deserialize)]
struct SomeField {
some_field: u32,
}
#[derive(Debug)]
struct Item {
name: String,
some_field: u32,
}
#[derive(Debug)]
struct VecItem(Vec<Item>);
impl Item {
fn new(name: String, some_field: u32) -> Self {
Self { name, some_field }
}
}
impl<'de> Visitor<'de> for ItemMapVisitor {
type Value = VecItem;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("name: somefield:")
}
fn visit_map<M>(self, mut access: M) -> Result<Self::Value, M::Error>
where
M: MapAccess<'de>,
{
let mut items = Vec::with_capacity(access.size_hint().unwrap_or(0));
while let Some((key, value)) = access.next_entry::<String, SomeField>()? {
items.push(Item::new(key, value.some_field));
}
Ok(VecItem(items))
}
}
impl<'de> Deserialize<'de> for VecItem {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_map(ItemMapVisitor::new())
}
}
fn main() {
let contents = r#"
name_a:
some_field: 0
name_b:
some_field: 1
name_c:
some_field: 2
"#;
let items: VecItem = serde_yaml::from_str(&contents).unwrap();
println!("{:#?}", items);
}
Output:
VecItem(
[
Item {
name: "name_a",
some_field: 0
},
Item {
name: "name_b",
some_field: 1
},
Item {
name: "name_c",
some_field: 2
}
]
)
If you don't want of Somefield structure. You could also use this:
#[derive(Debug, Deserialize)]
struct Item {
#[serde(skip)]
name: String,
some_field: u32,
}
while let Some((key, value)) = access.next_entry::<String, Item>()? {
items.push(Item::new(key, value.some_field));
}
But this could add some useless copy.
Define a default value for Item::name field
#[derive(Debug, Serialize, Deserialize)]
struct Item {
#[serde(default)]
name: String,
some_field: usize,
}
With this trick Itemcan be used both for deserializing and for transforming to a Vec of Items:
let contents = read_to_string("file.yml").unwrap();
let items: HashMap<String, Item> = serde_yaml::from_str(&contents).unwrap();
let slist: Vec<Item> = items
.into_iter()
.map(|(k, v)| Item {
name: k,
some_field: v.some_field,
})
.collect();

How do I serialize an enum without including the name of the enum variant?

I am trying to serialize an enum to a JSON string. I implemented Serialize trait for my enum as it is described in the docs, but I always get {"offset":{"Int":0}} instead of the desired {"offset":0}.
extern crate serde;
extern crate serde_json;
use std::collections::HashMap;
use serde::ser::{Serialize, Serializer};
#[derive(Debug)]
enum TValue<'a> {
String(&'a str),
Int(&'a i32),
}
impl<'a> Serialize for TValue<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
TValue::String(ref s) => serializer.serialize_newtype_variant("TValue", 0, "String", s),
TValue::Int(i) => serializer.serialize_newtype_variant("TValue", 1, "Int", &i),
}
}
}
fn main() {
let offset: i32 = 0;
let mut request_body = HashMap::new();
request_body.insert("offset", TValue::Int(&offset));
let serialized = serde_json::to_string(&request_body).unwrap();
println!("{}", serialized); // {"offset":{"Int":0}}
}
You can use the untagged attribute which will produce the desired output. You won't need to implement Serialize yourself with this:
#[derive(Debug, Serialize)]
#[serde(untagged)]
enum TValue<'a> {
String(&'a str),
Int(&'a i32),
}
If you wanted to implement Serialize yourself, I believe you want to skip your variant so you should not use serialize_newtype_variant() as it exposes your variant. You should use serialize_str() and serialize_i32() directly:
impl<'a> Serialize for TValue<'a> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
TValue::String(s) => serializer.serialize_str(s),
TValue::Int(i) => serializer.serialize_i32(*i),
}
}
}
It produces the desired output:
{"offset":0}

How can I return an iterator over a locked struct member in Rust?

Here is as far as I could get, using rental, partly based on How can I store a Chars iterator in the same struct as the String it is iterating on?. The difference here is that the get_iter method of the locked member has to take a mutable self reference.
I'm not tied to using rental: I'd be just as happy with a solution using reffers or owning_ref.
The PhantomData is present here just so that MyIter bears the normal lifetime relationship to MyIterable, the thing being iterated over.
I also tried changing #[rental] to #[rental(deref_mut_suffix)] and changing the return type of MyIterable.get_iter to Box<Iterator<Item=i32> + 'a> but that gave me other lifetime errors originating in the macro that I was unable to decipher.
#[macro_use]
extern crate rental;
use std::marker::PhantomData;
pub struct MyIterable {}
impl MyIterable {
// In the real use-case I can't remove the 'mut'.
pub fn get_iter<'a>(&'a mut self) -> MyIter<'a> {
MyIter {
marker: PhantomData,
}
}
}
pub struct MyIter<'a> {
marker: PhantomData<&'a MyIterable>,
}
impl<'a> Iterator for MyIter<'a> {
type Item = i32;
fn next(&mut self) -> Option<i32> {
Some(42)
}
}
use std::sync::Mutex;
rental! {
mod locking_iter {
pub use super::{MyIterable, MyIter};
use std::sync::MutexGuard;
#[rental]
pub struct LockingIter<'a> {
guard: MutexGuard<'a, MyIterable>,
iter: MyIter<'guard>,
}
}
}
use locking_iter::LockingIter;
impl<'a> Iterator for LockingIter<'a> {
type Item = i32;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.rent_mut(|iter| iter.next())
}
}
struct Access {
shared: Mutex<MyIterable>,
}
impl Access {
pub fn get_iter<'a>(&'a self) -> Box<Iterator<Item = i32> + 'a> {
Box::new(LockingIter::new(self.shared.lock().unwrap(), |mi| {
mi.get_iter()
}))
}
}
fn main() {
let access = Access {
shared: Mutex::new(MyIterable {}),
};
let iter = access.get_iter();
let contents: Vec<i32> = iter.take(2).collect();
println!("contents: {:?}", contents);
}
As user rodrigo has pointed out in a comment, the solution is simply to change #[rental] to #[rental_mut].

Lifetime for Iterator field

In learning this new fascinating language I wrote this code which outputs 0 through 10 multiplied by 3:
pub struct Multiplier {
factor : int,
current : int
}
impl Multiplier {
pub fn new(factor : int) -> Multiplier {
Multiplier {
factor: factor,
current: 0
}
}
}
impl Iterator<int> for Multiplier {
fn next(&mut self) -> Option<int> {
if self.current > 10 {
None
}
else {
let current = self.current;
self.current += 1;
Some(current * self.factor)
}
}
}
struct Holder {
x : Multiplier
}
impl Holder {
pub fn new(factor : int) -> Holder {
Holder {
x : Multiplier::new(factor)
}
}
fn get_iterator(&self) -> Multiplier {
self.x
}
}
fn main() {
let mut three_multiplier = Holder::new(3).get_iterator();
for item in three_multiplier {
println!("{}", item);
}
}
If I change Holder from this
struct Holder {
x : Multiplier
}
to this:
struct Holder {
x : Iterator<int>
}
I get a compilation warning:
<anon>:27:9: 27:22 error: explicit lifetime bound required
<anon>:27 x : Iterator<int>
^~~~~~~~~~~~~
Can anyone explain why changing the field type requires an explicit lifetime? I know how to mark the lifetimes but I'm not sure why the compiler wants me to do this.
You can add a lifetime bound this way:
struct Holder<'a> {
x: Iterator<int>+'a
}
Note however that this way, the Holder struct is unsized, because it contains a trait object, which is unsized. This severely limits what you can do with the type: for example, you can not return a Holder directly.
You can fix this by making Holder accept a type parameter:
struct Holder<T> where T: Iterator<int> {
x : T
}
Let's change get_iterator to use the type parameter:
impl<T> Holder<T> where T: Iterator<int>+Copy {
fn get_iterator(&self) -> T {
self.x
}
}
Note: I added the Copy bound here because get_iterator currently returns a copy. You could avoid the bound by making get_iterator return a &T instead.
As for new, you'll have to completely redesign it. If we keep it as is, the compiler gives error if we call it as Holder::new because Holder now has a type parameter, and the compiler cannot infer a type because new doesn't use any. To solve this, we can make new generic by using a trait to provide the constructor:
trait FactorCtor {
fn new(factor: int) -> Self;
}
And then changing new to use that trait:
impl<T> Holder<T> where T: Iterator<int>+FactorCtor {
pub fn new(factor : int) -> Holder<T> {
Holder {
x : FactorCtor::new(factor)
}
}
}
Because we have only one implementation of FactorCtor in this program, the compiler manages to infer T when calling Holder::new. If we add another implementation, e.g. Adder:
pub struct Adder {
factor : int,
current : int
}
impl FactorCtor for Adder {
fn new(factor: int) -> Adder {
Adder {
factor: factor,
current: 0
}
}
}
impl Iterator<int> for Adder {
fn next(&mut self) -> Option<int> {
if self.current > 10 {
None
}
else {
let current = self.current;
self.current += 1;
Some(current + self.factor)
}
}
}
Then we get a compiler error:
<anon>:72:9: 72:29 error: unable to infer enough type information about `_`; type annotations required
<anon>:72 let mut three_multiplier = Holder::new(3).get_iterator();
^~~~~~~~~~~~~~~~~~~~
We can fix this by specifying T explicitly:
fn main() {
let mut three_multiplier = Holder::<Multiplier>::new(3).get_iterator();
for item in three_multiplier {
println!("{}", item);
}
}