Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for #[serde(flatten)] #223

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 95 additions & 18 deletions src/serializer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,12 +205,7 @@ impl<'a, 'w, W: io::Write> Serializer for &'a mut SeRecord<'w, W> {
self,
_len: Option<usize>,
) -> Result<Self::SerializeMap, Self::Error> {
// The right behavior for serializing maps isn't clear.
Err(Error::custom(
"serializing maps is not supported, \
if you have a use case, please file an issue at \
https://github.com/BurntSushi/rust-csv",
))
Ok(self)
}

fn serialize_struct(
Expand Down Expand Up @@ -300,22 +295,34 @@ impl<'a, 'w, W: io::Write> SerializeMap for &'a mut SeRecord<'w, W> {
type Ok = ();
type Error = Error;

fn serialize_entry<K, V>(
&mut self,
_key: &K,
value: &V,
) -> Result<(), Self::Error>
where
K: ?Sized + Serialize,
V: ?Sized + Serialize,
{
value.serialize(&mut **self)
}

fn serialize_key<T: ?Sized + Serialize>(
&mut self,
_key: &T,
) -> Result<(), Self::Error> {
unreachable!()
Ok(())
}

fn serialize_value<T: ?Sized + Serialize>(
&mut self,
_value: &T,
) -> Result<(), Self::Error> {
unreachable!()
Ok(())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementation of these is required, and calling serialize_key then serialize_value should produce the same results as calling serialize_entry, as documented here: https://docs.rs/serde/latest/serde/ser/trait.SerializeMap.html#method.serialize_entry
Shouldn't this do:

Suggested change
Ok(())
value.serialize(&mut **self)

The serialize_entry overload can then be removed, as it's equivalent to this.

}

fn end(self) -> Result<Self::Ok, Self::Error> {
unreachable!()
Ok(())
}
}

Expand Down Expand Up @@ -655,12 +662,7 @@ impl<'a, 'w, W: io::Write> Serializer for &'a mut SeHeader<'w, W> {
self,
_len: Option<usize>,
) -> Result<Self::SerializeMap, Self::Error> {
// The right behavior for serializing maps isn't clear.
Err(Error::custom(
"serializing maps is not supported, \
if you have a use case, please file an issue at \
https://github.com/BurntSushi/rust-csv",
))
Ok(self)
}

fn serialize_struct(
Expand Down Expand Up @@ -750,22 +752,51 @@ impl<'a, 'w, W: io::Write> SerializeMap for &'a mut SeHeader<'w, W> {
type Ok = ();
type Error = Error;

fn serialize_entry<K, V>(
&mut self,
key: &K,
value: &V,
) -> Result<(), Self::Error>
where
K: ?Sized + Serialize,
V: ?Sized + Serialize,
{
// Grab old state and update state to `EncounteredStructField`.
let old_state =
mem::replace(&mut self.state, HeaderState::EncounteredStructField);
if let HeaderState::ErrorIfWrite(err) = old_state {
return Err(err);
}

let mut serializer = SeRecord {
wtr: self.wtr,
};
key.serialize(&mut serializer)?;

// Check that there aren't any containers in the value.
self.state = HeaderState::InStructField;
value.serialize(&mut **self)?;
self.state = HeaderState::EncounteredStructField;

Ok(())
}

fn serialize_key<T: ?Sized + Serialize>(
&mut self,
_key: &T,
) -> Result<(), Self::Error> {
unreachable!()
Ok(())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementation of these is required, and calling serialize_key then serialize_value should produce the same results as calling serialize_entry, as documented here: https://docs.rs/serde/latest/serde/ser/trait.SerializeMap.html#method.serialize_entry
Shouldn't this do:

Suggested change
Ok(())
let old_state =
mem::replace(&mut self.state, HeaderState::EncounteredStructField);
if let HeaderState::ErrorIfWrite(err) = old_state {
return Err(err);
}
let mut serializer = SeRecord {
wtr: self.wtr,
};
key.serialize(&mut serializer)?;
self.state = /* some new state representing this */;
Ok(())

}

fn serialize_value<T: ?Sized + Serialize>(
&mut self,
_value: &T,
) -> Result<(), Self::Error> {
unreachable!()
Ok(())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implementation of these is required, and calling serialize_key then serialize_value should produce the same results as calling serialize_entry, as documented here: https://docs.rs/serde/latest/serde/ser/trait.SerializeMap.html#method.serialize_entry
Shouldn't this do:

Suggested change
Ok(())
if !matches!(self.state, /* the new sate for serialize_value */) {
return Err(/* some error of incorrect impl of Serialize for the container */);
}
// Check that there aren't any containers in the value.
self.state = HeaderState::InStructField;
value.serialize(&mut **self)?;
self.state = HeaderState::EncounteredStructField;
Ok(())

}

fn end(self) -> Result<Self::Ok, Self::Error> {
unreachable!()
Ok(())
}
}

Expand Down Expand Up @@ -1338,4 +1369,50 @@ mod tests {
assert!(wrote);
assert_eq!(got, "label,num,label2,value,empty,label,num");
}

#[test]
fn struct_nested() {
#[derive(Clone, Serialize)]
struct Inner {
inner_a: i32,
inner_b: i32,
}

#[derive(Clone, Serialize)]
struct Middle {
#[serde(flatten)]
inner: Inner,
middle_a: i32,
middle_b: i32,
}

#[derive(Clone, Serialize)]
struct Outer {
// arbitrary structure nesting.
#[serde(flatten)]
middle: Middle,
outer_a: i32,
outer_b: i32,
}

let outer = Outer {
middle: Middle {
inner: Inner {
inner_a: 0,
inner_b: 1
},
middle_a: 2,
middle_b: 3,
},
outer_a: 4,
outer_b: 5,
};

let (wrote, got) = serialize_header(outer.clone());
assert!(wrote);
assert_eq!(got, "inner_a,inner_b,middle_a,middle_b,outer_a,outer_b");

let got = serialize(outer);
assert_eq!(got, "0,1,2,3,4,5\n");
}
}