Skip to content

Commit 320d292

Browse files
committed
Remove dependency on serde_derive
serde_derive was used in the flattened_maybe macro. It was used because the macro needed access to a buffered deserializer for the flattened representation. serde_with has since added the Content type from serde, such that relying on private serde APIs is no longer necessary. This commit removes serde_derive by inlining the macro expansion and cleaning it up. DeserializeSeed is used to pass in the field name of the non-flattened field into the deserialization code. This allows most of the code to be part of serde_with and flattned_maybe! macro only needs to invoke the deserializer. Some extra code is necessary to handle the flattened Content buffer.
1 parent dca6df8 commit 320d292

File tree

5 files changed

+564
-32
lines changed

5 files changed

+564
-32
lines changed

Cargo.lock

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

serde_with/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,6 @@ schemars_0_8 = { package = "schemars", version = "0.8.16", optional = true, defa
162162
schemars_0_9 = { package = "schemars", version = "0.9.0", optional = true, default-features = false }
163163
schemars_1 = { package = "schemars", version = "1.0.2", optional = true, default-features = false }
164164
serde = { version = "1.0.152", default-features = false }
165-
serde_derive = "1.0.152"
166165
serde_json = { version = "1.0.45", optional = true, default-features = false }
167166
serde_with_macros = { path = "../serde_with_macros", version = "=3.14.1", optional = true }
168167
time_0_3 = { package = "time", version = "~0.3.36", optional = true, default-features = false }

serde_with/src/content/de.rs

Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1926,3 +1926,294 @@ where
19261926
self
19271927
}
19281928
}
1929+
1930+
// Copied from serde, licensed under MIT OR Apache-2.0
1931+
// https://github.com/serde-rs/serde/blob/179954784683f35942ac2e1f076e0361b47f8178/serde/src/private/de.rs#L3183-L3447
1932+
#[cfg(feature = "std")]
1933+
pub(crate) struct FlatMapDeserializer<'a, 'de, E>(
1934+
pub &'a mut Vec<Option<(Content<'de>, Content<'de>)>>,
1935+
pub PhantomData<E>,
1936+
pub bool, // is_human_readable
1937+
);
1938+
1939+
#[cfg(feature = "std")]
1940+
impl<'a, 'de, E> FlatMapDeserializer<'a, 'de, E>
1941+
where
1942+
E: DeError,
1943+
{
1944+
fn deserialize_other<V>() -> Result<V, E> {
1945+
Err(DeError::custom("can only flatten structs and maps"))
1946+
}
1947+
}
1948+
1949+
#[cfg(feature = "std")]
1950+
macro_rules! forward_to_deserialize_other {
1951+
($($func:ident ($($arg:ty),*))*) => {
1952+
$(
1953+
fn $func<V>(self, $(_: $arg,)* _visitor: V) -> Result<V::Value, Self::Error>
1954+
where
1955+
V: Visitor<'de>,
1956+
{
1957+
Self::deserialize_other()
1958+
}
1959+
)*
1960+
}
1961+
}
1962+
1963+
#[cfg(feature = "std")]
1964+
impl<'a, 'de, E> Deserializer<'de> for FlatMapDeserializer<'a, 'de, E>
1965+
where
1966+
E: DeError,
1967+
{
1968+
type Error = E;
1969+
1970+
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
1971+
where
1972+
V: Visitor<'de>,
1973+
{
1974+
self.deserialize_map(visitor)
1975+
}
1976+
1977+
fn deserialize_enum<V>(
1978+
self,
1979+
name: &'static str,
1980+
variants: &'static [&'static str],
1981+
visitor: V,
1982+
) -> Result<V::Value, Self::Error>
1983+
where
1984+
V: Visitor<'de>,
1985+
{
1986+
for entry in self.0 {
1987+
if let Some((key, value)) = flat_map_take_entry(entry, variants) {
1988+
return visitor.visit_enum(EnumDeserializer::new(key, Some(value), self.2));
1989+
}
1990+
}
1991+
1992+
Err(DeError::custom(format_args!(
1993+
"no variant of enum {} found in flattened data",
1994+
name
1995+
)))
1996+
}
1997+
1998+
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value, Self::Error>
1999+
where
2000+
V: Visitor<'de>,
2001+
{
2002+
visitor.visit_map(FlatMapAccess {
2003+
is_human_readable: self.2,
2004+
iter: self.0.iter(),
2005+
pending_content: None,
2006+
_marker: PhantomData,
2007+
})
2008+
}
2009+
2010+
fn deserialize_struct<V>(
2011+
self,
2012+
_: &'static str,
2013+
fields: &'static [&'static str],
2014+
visitor: V,
2015+
) -> Result<V::Value, Self::Error>
2016+
where
2017+
V: Visitor<'de>,
2018+
{
2019+
visitor.visit_map(FlatStructAccess {
2020+
is_human_readable: self.2,
2021+
iter: self.0.iter_mut(),
2022+
pending_content: None,
2023+
fields,
2024+
_marker: PhantomData,
2025+
})
2026+
}
2027+
2028+
fn deserialize_newtype_struct<V>(self, _name: &str, visitor: V) -> Result<V::Value, Self::Error>
2029+
where
2030+
V: Visitor<'de>,
2031+
{
2032+
visitor.visit_newtype_struct(self)
2033+
}
2034+
2035+
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Self::Error>
2036+
where
2037+
V: Visitor<'de>,
2038+
{
2039+
match visitor.__private_visit_untagged_option(self) {
2040+
Ok(value) => Ok(value),
2041+
Err(()) => Self::deserialize_other(),
2042+
}
2043+
}
2044+
2045+
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value, Self::Error>
2046+
where
2047+
V: Visitor<'de>,
2048+
{
2049+
visitor.visit_unit()
2050+
}
2051+
2052+
fn deserialize_unit_struct<V>(
2053+
self,
2054+
_name: &'static str,
2055+
visitor: V,
2056+
) -> Result<V::Value, Self::Error>
2057+
where
2058+
V: Visitor<'de>,
2059+
{
2060+
visitor.visit_unit()
2061+
}
2062+
2063+
fn deserialize_ignored_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
2064+
where
2065+
V: Visitor<'de>,
2066+
{
2067+
visitor.visit_unit()
2068+
}
2069+
2070+
forward_to_deserialize_other! {
2071+
deserialize_bool()
2072+
deserialize_i8()
2073+
deserialize_i16()
2074+
deserialize_i32()
2075+
deserialize_i64()
2076+
deserialize_u8()
2077+
deserialize_u16()
2078+
deserialize_u32()
2079+
deserialize_u64()
2080+
deserialize_f32()
2081+
deserialize_f64()
2082+
deserialize_char()
2083+
deserialize_str()
2084+
deserialize_string()
2085+
deserialize_bytes()
2086+
deserialize_byte_buf()
2087+
deserialize_seq()
2088+
deserialize_tuple(usize)
2089+
deserialize_tuple_struct(&'static str, usize)
2090+
deserialize_identifier()
2091+
}
2092+
}
2093+
2094+
#[cfg(feature = "std")]
2095+
struct FlatMapAccess<'a, 'de, E> {
2096+
is_human_readable: bool,
2097+
iter: core::slice::Iter<'a, Option<(Content<'de>, Content<'de>)>>,
2098+
pending_content: Option<&'a Content<'de>>,
2099+
_marker: PhantomData<E>,
2100+
}
2101+
2102+
#[cfg(feature = "std")]
2103+
impl<'a, 'de, E> MapAccess<'de> for FlatMapAccess<'a, 'de, E>
2104+
where
2105+
E: DeError,
2106+
{
2107+
type Error = E;
2108+
2109+
fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
2110+
where
2111+
T: DeserializeSeed<'de>,
2112+
{
2113+
for item in &mut self.iter {
2114+
// Items in the vector are nulled out when used by a struct.
2115+
if let Some((ref key, ref content)) = *item {
2116+
// Do not take(), instead borrow this entry. The internally tagged
2117+
// enum does its own buffering so we can't tell whether this entry
2118+
// is going to be consumed. Borrowing here leaves the entry
2119+
// available for later flattened fields.
2120+
self.pending_content = Some(content);
2121+
return seed
2122+
.deserialize(ContentRefDeserializer::new(key, self.is_human_readable))
2123+
.map(Some);
2124+
}
2125+
}
2126+
Ok(None)
2127+
}
2128+
2129+
fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error>
2130+
where
2131+
T: DeserializeSeed<'de>,
2132+
{
2133+
match self.pending_content.take() {
2134+
Some(value) => {
2135+
seed.deserialize(ContentRefDeserializer::new(value, self.is_human_readable))
2136+
}
2137+
None => Err(DeError::custom("value is missing")),
2138+
}
2139+
}
2140+
}
2141+
2142+
#[cfg(feature = "std")]
2143+
struct FlatStructAccess<'a, 'de, E> {
2144+
is_human_readable: bool,
2145+
iter: core::slice::IterMut<'a, Option<(Content<'de>, Content<'de>)>>,
2146+
pending_content: Option<Content<'de>>,
2147+
fields: &'static [&'static str],
2148+
_marker: PhantomData<E>,
2149+
}
2150+
2151+
#[cfg(feature = "std")]
2152+
impl<'a, 'de, E> MapAccess<'de> for FlatStructAccess<'a, 'de, E>
2153+
where
2154+
E: DeError,
2155+
{
2156+
type Error = E;
2157+
2158+
fn next_key_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
2159+
where
2160+
T: DeserializeSeed<'de>,
2161+
{
2162+
for entry in self.iter.by_ref() {
2163+
if let Some((key, content)) = flat_map_take_entry(entry, self.fields) {
2164+
self.pending_content = Some(content);
2165+
return seed
2166+
.deserialize(ContentDeserializer::new(key, self.is_human_readable))
2167+
.map(Some);
2168+
}
2169+
}
2170+
Ok(None)
2171+
}
2172+
2173+
fn next_value_seed<T>(&mut self, seed: T) -> Result<T::Value, Self::Error>
2174+
where
2175+
T: DeserializeSeed<'de>,
2176+
{
2177+
match self.pending_content.take() {
2178+
Some(value) => {
2179+
seed.deserialize(ContentDeserializer::new(value, self.is_human_readable))
2180+
}
2181+
None => Err(DeError::custom("value is missing")),
2182+
}
2183+
}
2184+
}
2185+
2186+
/// Claims one key-value pair from a [`FlatMapDeserializer`]'s field buffer if the
2187+
/// field name matches any of the recognized ones.
2188+
#[cfg(feature = "std")]
2189+
fn flat_map_take_entry<'de>(
2190+
entry: &mut Option<(Content<'de>, Content<'de>)>,
2191+
recognized: &[&str],
2192+
) -> Option<(Content<'de>, Content<'de>)> {
2193+
// Entries in the FlatMapDeserializer buffer are nulled out as they get
2194+
// claimed for deserialization. We only use an entry if it is still present
2195+
// and if the field is one recognized by the current data structure.
2196+
let is_recognized = match entry {
2197+
None => false,
2198+
Some((k, _v)) => content_as_str(k).is_some_and(|name| recognized.contains(&name)),
2199+
};
2200+
2201+
if is_recognized {
2202+
entry.take()
2203+
} else {
2204+
None
2205+
}
2206+
}
2207+
2208+
// Copied from serde, licensed under MIT OR Apache-2.0
2209+
// https://github.com/serde-rs/serde/blob/179954784683f35942ac2e1f076e0361b47f8178/serde/src/private/de.rs#L222-L230
2210+
#[cfg(feature = "std")]
2211+
fn content_as_str<'a, 'de>(content: &'a Content<'de>) -> Option<&'a str> {
2212+
match *content {
2213+
Content::Str(x) => Some(x),
2214+
Content::String(ref x) => Some(x),
2215+
Content::Bytes(x) => core::str::from_utf8(x).ok(),
2216+
Content::ByteBuf(ref x) => core::str::from_utf8(x).ok(),
2217+
_ => None,
2218+
}
2219+
}

0 commit comments

Comments
 (0)