serde_bser-0.4.0/.cargo_vcs_info.json0000644000000001660000000000100131550ustar { "git": { "sha1": "c3536143cab534cdd9696eb3e2d03c4ac1e2f883" }, "path_in_vcs": "watchman/rust/serde_bser" }serde_bser-0.4.0/Cargo.toml0000644000000023240000000000100111510ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "serde_bser" version = "0.4.0" authors = [ "Rain ", "Wez Furlong", ] description = "Implements the Watchman BSER encoding for serde. https://facebook.github.io/watchman/docs/bser.html" documentation = "https://docs.rs/serde_bser" readme = "README.md" license = "MIT" repository = "https://github.com/facebook/watchman/" [dependencies.anyhow] version = "1.0" [dependencies.byteorder] version = "1.3" [dependencies.bytes] version = "1.0" features = ["serde"] [dependencies.serde] version = "1.0.126" features = [ "derive", "rc", ] [dependencies.serde_bytes] version = "0.11" [dependencies.thiserror] version = "1.0" [dev-dependencies.maplit] version = "1.0" [features] debug_bytes = [] default = [] serde_bser-0.4.0/Cargo.toml.orig000064400000000000000000000011540072674642500146620ustar 00000000000000[package] name = "serde_bser" version = "0.4.0" authors = ["Rain ", "Wez Furlong"] edition = "2021" description = "Implements the Watchman BSER encoding for serde. https://facebook.github.io/watchman/docs/bser.html" documentation = "https://docs.rs/serde_bser" repository = "https://github.com/facebook/watchman/" license = "MIT" [dependencies] anyhow = "1.0" byteorder = "1.3" bytes = { version = "1.0", features = ["serde"] } serde = { version = "1.0.126", features = ["derive", "rc"] } serde_bytes = "0.11" thiserror = "1.0" [dev-dependencies] maplit = "1.0" [features] debug_bytes = [] default = [] serde_bser-0.4.0/LICENSE000064400000000000000000000021040072674642500127740ustar 00000000000000MIT License Copyright (c) Meta Platforms, Inc. and its affiliates. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. serde_bser-0.4.0/README.md000064400000000000000000000003640072674642500132540ustar 00000000000000# Work in Progress! This is work in progress on a BSER implementation that is compatible with serde. It is not complete! If you're reading this and want to help move it closer to completion, please don't be afraid to work up a pull request! serde_bser-0.4.0/src/bytestring.rs000064400000000000000000000146300072674642500153250ustar 00000000000000/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ use std::ffi::OsString; use std::fmt::Write; use std::path::PathBuf; use serde::Deserialize; use serde::Serialize; /// The ByteString type represents values encoded using BSER_BYTESTRING. /// The purpose of this encoding is to represent bytestrings with an arbitrary /// encoding. /// /// In practice, as used by watchman, bytestrings have the filesystem encoding /// on posix systems (which is usually utf8 on linux, guaranteed utf8 on macos) /// and when they appear as file names in file results are guaranteed to be utf8 /// on Windows systems. /// /// When it comes to interoperating with Rust code, ByteString is nominally /// equivalent to `OsString`/`PathBuf` and is convertible to and from those values. /// /// It is worth noting that on Windows sytems the conversion from ByteString to OsString is /// potentially lossy: while convention is that bytestring holds utf8 in the common case in /// watchman, that isn't enforced by its serializer and we may potentially encounter an error /// during conversion. Converting from OsString to ByteString can potentially fail on windows /// because Watchman and thus ByteString doesn't have a way to represent the poorly formed /// surrogate pairs that Windows allows in its filenames. #[derive(Serialize, Deserialize, Clone, PartialEq, Eq)] #[serde(transparent)] pub struct ByteString(#[serde(with = "serde_bytes")] Vec); impl std::fmt::Debug for ByteString { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { let escaped = self.as_escaped_string(); write!(fmt, "\"{}\"", escaped.escape_debug()) } } impl std::fmt::Display for ByteString { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { let escaped = self.as_escaped_string(); write!(fmt, "\"{}\"", escaped.escape_default()) } } impl std::ops::Deref for ByteString { type Target = [u8]; fn deref(&self) -> &[u8] { &self.0 } } impl std::ops::DerefMut for ByteString { fn deref_mut(&mut self) -> &mut [u8] { &mut self.0 } } impl ByteString { /// Returns the raw bytes as a slice. pub fn as_bytes(&self) -> &[u8] { self.0.as_slice() } /// Consumes ByteString yielding bytes. pub fn into_bytes(self) -> Vec { self.0 } /// Returns a version of the bytestring encoded as a mostly-utf-8 /// string, with invalid sequences escaped using `\xXX` hex notation. /// This is for diagnostic and display purposes. pub fn as_escaped_string(&self) -> String { let mut input = self.0.as_slice(); let mut output = String::new(); loop { match ::std::str::from_utf8(input) { Ok(valid) => { output.push_str(valid); break; } Err(error) => { let (valid, after_valid) = input.split_at(error.valid_up_to()); unsafe { output.push_str(::std::str::from_utf8_unchecked(valid)) } if let Some(invalid_sequence_length) = error.error_len() { for b in &after_valid[..invalid_sequence_length] { write!(output, "\\x{:x}", b).unwrap(); } input = &after_valid[invalid_sequence_length..]; } else { break; } } } } output } } /// Guaranteed conversion from an owned byte vector to a ByteString impl From> for ByteString { fn from(vec: Vec) -> Self { Self(vec) } } /// Guaranteed conversion from a UTF-8 string to a ByteString impl From for ByteString { fn from(s: String) -> Self { Self(s.into_bytes()) } } impl From<&str> for ByteString { fn from(s: &str) -> Self { Self(s.as_bytes().to_vec()) } } /// Attempt to convert a ByteString into a UTF-8 String impl TryInto for ByteString { type Error = std::string::FromUtf8Error; fn try_into(self) -> Result { String::from_utf8(self.0) } } /// Conversion to OsString is guaranteed to succeed on unix systems /// but can potentially fail on Windows systems. impl TryInto for ByteString { type Error = std::string::FromUtf8Error; #[cfg(unix)] fn try_into(self) -> Result { Ok(std::os::unix::ffi::OsStringExt::from_vec(self.0)) } #[cfg(windows)] fn try_into(self) -> Result { let s = String::from_utf8(self.0)?; Ok(s.into()) } } /// Conversion to PathBuf is subject to the same rules as conversion /// to OsString impl TryInto for ByteString { type Error = std::string::FromUtf8Error; fn try_into(self) -> Result { let os: OsString = self.try_into()?; Ok(os.into()) } } /// Conversion from OsString -> ByteString is guaranteed to succeed on unix /// systems but can potentially fail on Windows systems. impl TryInto for OsString { type Error = &'static str; #[cfg(unix)] fn try_into(self) -> Result { Ok(ByteString(std::os::unix::ffi::OsStringExt::into_vec(self))) } #[cfg(windows)] fn try_into(self) -> Result { let s = self .into_string() .map_err(|_| "OsString is not representible as UTF-8")?; Ok(ByteString(s.into_bytes())) } } /// Conversion from PathBuf -> ByteString is subject to the same rules /// as conversion from OsString impl TryInto for PathBuf { type Error = &'static str; fn try_into(self) -> Result { self.into_os_string().try_into() } } #[cfg(test)] mod tests { use super::ByteString; use crate::from_slice; use crate::ser::serialize; #[test] fn test_serde() { let bs = ByteString::from(vec![1, 2, 3, 4]); let out = serialize(Vec::::new(), &bs).unwrap(); assert_eq!( out, b"\x00\x02\x00\x00\x00\x00\x03\x07\x02\x03\x04\x01\x02\x03\x04" ); let got: ByteString = from_slice(&out).unwrap(); assert_eq!(bs, got); } } serde_bser-0.4.0/src/de/bunser.rs000064400000000000000000000115360072674642500150230ustar 00000000000000/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ //! Internal stateless code for handling BSER deserialization. use anyhow::Context as _; use byteorder::ByteOrder; use byteorder::NativeEndian; use crate::de::read::DeRead; use crate::de::read::Reference; use crate::errors::*; use crate::header::*; #[derive(Debug)] pub struct Bunser { read: R, scratch: Vec, } pub struct PduInfo { pub bser_capabilities: u32, pub len: i64, pub start: i64, } impl<'de, R> Bunser where R: DeRead<'de>, { pub fn new(read: R) -> Self { Bunser { read, scratch: Vec::with_capacity(128), } } /// Read the PDU off the stream. This should be called in the beginning. pub fn read_pdu(&mut self) -> Result { { let magic = self.read_bytes(2)?; if magic.get_ref() != &EMPTY_HEADER[..2] { return Err(Error::DeInvalidMagic { magic: Vec::from(magic.get_ref()), }); } } let bser_capabilities = self .read .next_u32(&mut self.scratch) .map_err(Error::de_reader_error)?; let len = self.check_next_int()?; let start = self.read_count(); Ok(PduInfo { bser_capabilities, len, start, }) } pub fn read_count(&self) -> i64 { self.read.read_count() as i64 } pub fn end(&self, pdu_info: &PduInfo) -> Result<()> { let expected = (pdu_info.start + pdu_info.len) as usize; if self.read.read_count() != expected { return Err(Error::DeEof { expected, read: self.read.read_count(), }); } Ok(()) } #[inline] pub fn peek(&mut self) -> Result { self.read.peek().map_err(Error::de_reader_error) } #[inline] pub fn discard(&mut self) { self.read.discard(); } /// Return a borrowed or copied version of the next n bytes. #[inline] pub fn read_bytes<'s>(&'s mut self, len: i64) -> Result> { let len = len as usize; self.read .next_bytes(len, &mut self.scratch) .map_err(Error::de_reader_error) } /// Return the next i8 value. This assumes the caller already knows the next /// value is an i8. pub fn next_i8(&mut self) -> Result { self.read.discard(); let bytes = self .read_bytes(1) .context("error while reading i8") .map_err(Error::de_reader_error)? .get_ref(); Ok(bytes[0] as i8) } /// Return the next i16 value. This assumes the caller already knows the /// next value is an i16. pub fn next_i16(&mut self) -> Result { self.read.discard(); let bytes = self .read_bytes(2) .context("error while reading i16") .map_err(Error::de_reader_error)? .get_ref(); Ok(NativeEndian::read_i16(bytes)) } /// Return the next i32 value. This assumes the caller already knows the /// next value is an i32. pub fn next_i32(&mut self) -> Result { self.read.discard(); let bytes = self .read_bytes(4) .context("error while reading i32") .map_err(Error::de_reader_error)? .get_ref(); Ok(NativeEndian::read_i32(bytes)) } /// Return the next i64 value. This assumes the caller already knows the /// next value is an i64. pub fn next_i64(&mut self) -> Result { self.read.discard(); let bytes = self .read_bytes(8) .context("error while reading i64") .map_err(Error::de_reader_error)? .get_ref(); Ok(NativeEndian::read_i64(bytes)) } /// Check and return the next integer value. Errors out if the next value is /// not actually an int. pub fn check_next_int(&mut self) -> Result { let value = match self.peek()? { BSER_INT8 => self.next_i8()? as i64, BSER_INT16 => self.next_i16()? as i64, BSER_INT32 => self.next_i32()? as i64, BSER_INT64 => self.next_i64()?, ch => { return Err(Error::DeInvalidStartByte { kind: "integer".into(), byte: ch, }); } }; Ok(value) } pub fn next_f64(&mut self) -> Result { self.read.discard(); let bytes = self .read_bytes(8) .context("error while reading f64") .map_err(Error::de_reader_error)? .get_ref(); Ok(NativeEndian::read_f64(bytes)) } } serde_bser-0.4.0/src/de/map.rs000064400000000000000000000066770072674642500143140ustar 00000000000000/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ use serde::de; use serde::forward_to_deserialize_any; use super::read::DeRead; use super::reentrant::ReentrantGuard; use super::Deserializer; use crate::errors::*; use crate::header::*; pub struct MapAccess<'a, R> { de: &'a mut Deserializer, remaining: usize, } impl<'a, 'de, R> MapAccess<'a, R> where R: 'a + DeRead<'de>, { /// Create a new `MapAccess`. /// /// `_guard` makes sure the caller is accounting for the recursion limit. pub fn new(de: &'a mut Deserializer, nitems: usize, _guard: &ReentrantGuard) -> Self { MapAccess { de, remaining: nitems, } } } impl<'a, 'de, R> de::MapAccess<'de> for MapAccess<'a, R> where R: 'a + DeRead<'de>, { type Error = Error; fn next_key_seed(&mut self, seed: K) -> Result> where K: de::DeserializeSeed<'de>, { if self.remaining == 0 { Ok(None) } else { self.remaining -= 1; let key = seed.deserialize(MapKey { de: &mut *self.de })?; Ok(Some(key)) } } fn next_value_seed(&mut self, seed: V) -> Result where V: de::DeserializeSeed<'de>, { seed.deserialize(&mut *self.de) } } /// A deserializer that is specialized to deal with map keys. Specifically, map keys are always /// strings. struct MapKey<'a, R> { de: &'a mut Deserializer, } impl<'a, 'de, R> de::Deserializer<'de> for MapKey<'a, R> where R: DeRead<'de>, { type Error = Error; #[inline] fn deserialize_any(self, visitor: V) -> Result where V: de::Visitor<'de>, { match self.de.bunser.peek()? { // Both bytestrings and UTF-8 strings are treated as Unicode strings, since field // identifiers must be Unicode strings. BSER_BYTESTRING | BSER_UTF8STRING => self.de.visit_utf8string(visitor), other => Err(Error::DeInvalidStartByte { kind: "map key".into(), byte: other, }), } } #[inline] fn deserialize_option(self, visitor: V) -> Result where V: de::Visitor<'de>, { // Map keys cannot be null. visitor.visit_some(self) } #[inline] fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result where V: de::Visitor<'de>, { visitor.visit_newtype_struct(self) } #[inline] fn deserialize_enum( self, name: &'static str, variants: &'static [&'static str], visitor: V, ) -> Result where V: de::Visitor<'de>, { self.de.deserialize_enum(name, variants, visitor) } #[inline] fn deserialize_bytes(self, visitor: V) -> Result where V: de::Visitor<'de>, { self.de.deserialize_bytes(visitor) } #[inline] fn deserialize_byte_buf(self, visitor: V) -> Result where V: de::Visitor<'de>, { self.de.deserialize_bytes(visitor) } forward_to_deserialize_any! { bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string unit unit_struct seq tuple tuple_struct map struct identifier ignored_any } } serde_bser-0.4.0/src/de/mod.rs000064400000000000000000000202720072674642500143010ustar 00000000000000/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ mod bunser; mod map; mod read; mod reentrant; mod seq; mod template; #[cfg(test)] mod test; mod variant; use std::io; use std::str; use serde::de; use serde::forward_to_deserialize_any; pub use self::bunser::Bunser; pub use self::bunser::PduInfo; pub use self::read::DeRead; pub use self::read::Reference; pub use self::read::SliceRead; use self::reentrant::ReentrantLimit; use crate::errors::*; use crate::header::*; pub struct Deserializer { bunser: Bunser, pdu_info: PduInfo, remaining_depth: ReentrantLimit, } macro_rules! make_visit_num { ($fn:ident, $next:ident) => { #[inline] fn $fn(&mut self, visitor: V) -> Result where V: de::Visitor<'de>, { visitor.$fn(self.bunser.$next()?) } }; } fn from_trait<'de, R, T>(read: R) -> Result where R: DeRead<'de>, T: de::Deserialize<'de>, { let mut d = Deserializer::new(read)?; let value = de::Deserialize::deserialize(&mut d)?; // Make sure we saw the expected length. d.end()?; Ok(value) } pub fn from_slice<'de, T>(slice: &'de [u8]) -> Result where T: de::Deserialize<'de>, { from_trait(SliceRead::new(slice)) } pub fn from_reader(rdr: R) -> Result where R: io::Read, T: de::DeserializeOwned, { from_trait(read::IoRead::new(rdr)) } impl<'de, R> Deserializer where R: DeRead<'de>, { pub fn new(read: R) -> Result { let mut bunser = Bunser::new(read); let pdu_info = bunser.read_pdu()?; Ok(Deserializer { bunser, pdu_info, remaining_depth: ReentrantLimit::new(128), }) } /// This method must be called after a value has been fully deserialized. pub fn end(&self) -> Result<()> { self.bunser.end(&self.pdu_info) } #[inline] pub fn capabilities(&self) -> u32 { self.pdu_info.bser_capabilities } fn parse_value(&mut self, visitor: V) -> Result where V: de::Visitor<'de>, { match self.bunser.peek()? { BSER_ARRAY => { let guard = self.remaining_depth.acquire("array")?; self.bunser.discard(); let nitems = self.bunser.check_next_int()?; visitor.visit_seq(seq::SeqAccess::new(self, nitems as usize, &guard)) } BSER_OBJECT => { let guard = self.remaining_depth.acquire("object")?; self.bunser.discard(); let nitems = self.bunser.check_next_int()?; visitor.visit_map(map::MapAccess::new(self, nitems as usize, &guard)) } BSER_TRUE => self.visit_bool(visitor, true), BSER_FALSE => self.visit_bool(visitor, false), BSER_NULL => self.visit_unit(visitor), BSER_BYTESTRING => self.visit_bytestring(visitor), BSER_UTF8STRING => self.visit_utf8string(visitor), BSER_TEMPLATE => { let guard = self.remaining_depth.acquire("template")?; self.bunser.discard(); // TODO: handle possible IO interruption better here -- will // probably need some intermediate states. let keys = self.template_keys()?; let nitems = self.bunser.check_next_int()?; let template = template::Template::new(self, keys, nitems as usize, &guard); visitor.visit_seq(template) } BSER_REAL => self.visit_f64(visitor), BSER_INT8 => self.visit_i8(visitor), BSER_INT16 => self.visit_i16(visitor), BSER_INT32 => self.visit_i32(visitor), BSER_INT64 => self.visit_i64(visitor), ch => Err(Error::DeInvalidStartByte { kind: "next item".into(), byte: ch, }), } } make_visit_num!(visit_i8, next_i8); make_visit_num!(visit_i16, next_i16); make_visit_num!(visit_i32, next_i32); make_visit_num!(visit_i64, next_i64); make_visit_num!(visit_f64, next_f64); fn template_keys(&mut self) -> Result>> { // The list of keys is actually an array, so just use the deserializer // to process it. de::Deserialize::deserialize(self) } fn visit_bytestring(&mut self, visitor: V) -> Result where V: de::Visitor<'de>, { self.bunser.discard(); let len = self.bunser.check_next_int()?; match self.bunser.read_bytes(len)? { Reference::Borrowed(s) => visitor.visit_borrowed_bytes(s), Reference::Copied(s) => visitor.visit_bytes(s), } } fn visit_utf8string(&mut self, visitor: V) -> Result where V: de::Visitor<'de>, { self.bunser.discard(); let len = self.bunser.check_next_int()?; match self .bunser .read_bytes(len)? .map_result(str::from_utf8) .map_err(Error::de_reader_error)? { Reference::Borrowed(s) => visitor.visit_borrowed_str(s), Reference::Copied(s) => visitor.visit_str(s), } } #[inline] fn visit_bool(&mut self, visitor: V, value: bool) -> Result where V: de::Visitor<'de>, { self.bunser.discard(); visitor.visit_bool(value) } #[inline] fn visit_unit(&mut self, visitor: V) -> Result where V: de::Visitor<'de>, { self.bunser.discard(); visitor.visit_unit() } } impl<'de, 'a, R> de::Deserializer<'de> for &'a mut Deserializer where R: DeRead<'de>, { type Error = Error; #[inline] fn deserialize_any(self, visitor: V) -> Result where V: de::Visitor<'de>, { self.parse_value(visitor) } /// Parse a `null` as a None, and anything else as a `Some(...)`. #[inline] fn deserialize_option(self, visitor: V) -> Result where V: de::Visitor<'de>, { match self.bunser.peek()? { BSER_NULL => { self.bunser.discard(); visitor.visit_none() } _ => visitor.visit_some(self), } } #[inline] fn deserialize_newtype_struct(self, _name: &str, visitor: V) -> Result where V: de::Visitor<'de>, { // This is e.g. E(T). Ignore the E. visitor.visit_newtype_struct(self) } /// Parse an enum as an object like {key: value}, or a unit variant as just /// a value. #[inline] fn deserialize_enum( self, name: &'static str, _variants: &'static [&'static str], visitor: V, ) -> Result where V: de::Visitor<'de>, { match self.bunser.peek()? { BSER_BYTESTRING | BSER_UTF8STRING => { visitor.visit_enum(variant::UnitVariantAccess::new(self)) } BSER_OBJECT => { let guard = self .remaining_depth .acquire(format!("object-like enum '{}'", name))?; self.bunser.discard(); // For enum variants the object must have exactly one entry // (named the variant, but serde will perform that check). let nitems = self.bunser.check_next_int()?; if nitems != 1 { return Err(de::Error::invalid_value( de::Unexpected::Signed(nitems), &"integer `1`", )); } visitor.visit_enum(variant::VariantAccess::new(self, &guard)) } ch => Err(Error::DeInvalidStartByte { kind: format!("enum '{}'", name), byte: ch, }), } } forward_to_deserialize_any! { bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes byte_buf unit unit_struct seq tuple tuple_struct map struct identifier ignored_any } } serde_bser-0.4.0/src/de/read.rs000064400000000000000000000147310072674642500144400ustar 00000000000000/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #[cfg(feature = "debug_bytes")] use std::fmt; use std::io; use std::result; use anyhow::bail; use anyhow::Context as _; use byteorder::ByteOrder; use byteorder::NativeEndian; #[cfg(feature = "debug_bytes")] macro_rules! debug_bytes { ($($arg:tt)*) => { eprint!($($arg)*); } } #[cfg(not(feature = "debug_bytes"))] macro_rules! debug_bytes { ($($arg:tt)*) => {}; } #[cfg(feature = "debug_bytes")] struct ByteBuf<'a>(&'a [u8]); #[cfg(feature = "debug_bytes")] impl<'a> fmt::LowerHex for ByteBuf<'a> { fn fmt(&self, fmtr: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { for byte in self.0 { let val = byte.clone(); if (val >= b'-' && val <= b'9') || (val >= b'A' && val <= b'Z') || (val >= b'a' && val <= b'z') || val == b'_' { fmtr.write_fmt(format_args!("{}", val as char))?; } else { fmtr.write_fmt(format_args!(r"\x{:02x}", byte))?; } } Ok(()) } } pub trait DeRead<'de> { /// read next byte (if peeked byte not discarded return it) fn next(&mut self) -> anyhow::Result; /// peek next byte (peeked byte should come in next and next_bytes unless discarded) fn peek(&mut self) -> anyhow::Result; /// how many bytes have been read so far. /// this doesn't include the peeked byte fn read_count(&self) -> usize; /// discard peeked byte fn discard(&mut self); /// read next byte (if peeked byte not discarded include it) fn next_bytes<'s>( &'s mut self, len: usize, scratch: &'s mut Vec, ) -> anyhow::Result>; /// read u32 as native endian fn next_u32(&mut self, scratch: &mut Vec) -> anyhow::Result { let bytes = self .next_bytes(4, scratch) .context("error while parsing u32")? .get_ref(); Ok(NativeEndian::read_u32(bytes)) } } pub struct SliceRead<'a> { slice: &'a [u8], index: usize, } impl<'a> SliceRead<'a> { pub fn new(slice: &'a [u8]) -> Self { SliceRead { slice, index: 0 } } } pub struct IoRead where R: io::Read, { reader: R, read_count: usize, /// Temporary storage of peeked byte. peeked: Option, } impl IoRead where R: io::Read, { pub fn new(reader: R) -> Self { debug_bytes!("Read bytes:\n"); IoRead { reader, read_count: 0, peeked: None, } } } impl Drop for IoRead where R: io::Read, { fn drop(&mut self) { debug_bytes!("\n"); } } impl<'a> DeRead<'a> for SliceRead<'a> { fn next(&mut self) -> anyhow::Result { if self.index >= self.slice.len() { bail!("eof while reading next byte"); } let ch = self.slice[self.index]; self.index += 1; Ok(ch) } fn peek(&mut self) -> anyhow::Result { if self.index >= self.slice.len() { bail!("eof while peeking next byte"); } Ok(self.slice[self.index]) } #[inline] fn read_count(&self) -> usize { self.index } #[inline] fn discard(&mut self) { self.index += 1; } fn next_bytes<'s>( &'s mut self, len: usize, _scratch: &'s mut Vec, ) -> anyhow::Result> { // BSER has no escaping or anything similar, so just go ahead and return // a reference to the bytes. if self.index + len > self.slice.len() { bail!("eof while parsing bytes/string"); } let borrowed = &self.slice[self.index..(self.index + len)]; self.index += len; Ok(Reference::Borrowed(borrowed)) } } impl<'de, R> DeRead<'de> for IoRead where R: io::Read, { fn next(&mut self) -> anyhow::Result { match self.peeked.take() { Some(peeked) => Ok(peeked), None => { let mut buffer = [0; 1]; self.reader.read_exact(&mut buffer)?; debug_bytes!("{:x}", ByteBuf(&buffer)); self.read_count += 1; Ok(buffer[0]) } } } fn peek(&mut self) -> anyhow::Result { match self.peeked { Some(peeked) => Ok(peeked), None => { let mut buffer = [0; 1]; self.reader.read_exact(&mut buffer)?; debug_bytes!("{:x}", ByteBuf(&buffer)); self.peeked = Some(buffer[0]); self.read_count += 1; Ok(buffer[0]) } } } #[inline] fn read_count(&self) -> usize { match self.peeked { Some(_) => self.read_count - 1, None => self.read_count, } } #[inline] fn discard(&mut self) { self.peeked = None } fn next_bytes<'s>( &'s mut self, len: usize, scratch: &'s mut Vec, ) -> anyhow::Result> { scratch.resize(len, 0); let mut idx = 0; if self.peeked.is_some() { idx += 1; } if idx < len { self.reader.read_exact(&mut scratch[idx..len])?; debug_bytes!("{:x}", ByteBuf(&scratch[idx..len])); self.read_count += len - idx; } if let Some(peeked) = self.peeked.take() { scratch[0] = peeked; } Ok(Reference::Copied(&scratch[0..len])) } } #[derive(Debug)] pub enum Reference<'b, 'c, T: ?Sized> { Borrowed(&'b T), Copied(&'c T), } impl<'b, 'c, T> Reference<'b, 'c, T> where T: ?Sized, { pub fn map_result(self, f: F) -> anyhow::Result> where F: FnOnce(&T) -> result::Result<&U, E>, E: std::error::Error + Send + Sync + 'static, U: ?Sized + 'b + 'c, { match self { Reference::Borrowed(borrowed) => Ok(Reference::Borrowed(f(borrowed)?)), Reference::Copied(copied) => Ok(Reference::Copied(f(copied)?)), } } pub fn get_ref<'a>(&self) -> &'a T where 'b: 'a, 'c: 'a, { match *self { Reference::Borrowed(borrowed) => borrowed, Reference::Copied(copied) => copied, } } } serde_bser-0.4.0/src/de/reentrant.rs000064400000000000000000000023740072674642500155270ustar 00000000000000/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ //! Module to handle reentrant/recursion limits while deserializing. use std::cell::Cell; use std::rc::Rc; use crate::errors::*; /// Sets a limit on the amount of recursion during deserialization. This does /// not do any synchronization -- it is intended purely for single-threaded use. pub struct ReentrantLimit(Rc>); impl ReentrantLimit { /// Create a new reentrant limit. pub fn new(limit: usize) -> Self { ReentrantLimit(Rc::new(Cell::new(limit))) } /// Try to decrease the limit by 1. Return an RAII guard that when freed /// will increase the limit by 1. pub fn acquire>(&mut self, kind: S) -> Result { if self.0.get() == 0 { return Err(Error::DeRecursionLimitExceeded { kind: kind.into() }); } self.0.set(self.0.get() - 1); Ok(ReentrantGuard(self.0.clone())) } } /// RAII guard for reentrant limits. pub struct ReentrantGuard(Rc>); impl Drop for ReentrantGuard { fn drop(&mut self) { self.0.set(self.0.get() + 1); } } serde_bser-0.4.0/src/de/seq.rs000064400000000000000000000023110072674642500143040ustar 00000000000000/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ use serde::de; use super::read::DeRead; use super::reentrant::ReentrantGuard; use super::Deserializer; use crate::errors::*; pub struct SeqAccess<'a, R> { de: &'a mut Deserializer, remaining: usize, } impl<'a, 'de, R> SeqAccess<'a, R> where R: 'a + DeRead<'de>, { /// Create a new `MapAccess`. /// /// `_guard` makes sure the caller is accounting for the recursion limit. pub fn new(de: &'a mut Deserializer, nitems: usize, _guard: &ReentrantGuard) -> Self { SeqAccess { de, remaining: nitems, } } } impl<'a, 'de, R> de::SeqAccess<'de> for SeqAccess<'a, R> where R: 'a + DeRead<'de>, { type Error = Error; fn next_element_seed(&mut self, seed: T) -> Result> where T: de::DeserializeSeed<'de>, { if self.remaining == 0 { Ok(None) } else { self.remaining -= 1; let value = seed.deserialize(&mut *self.de)?; Ok(Some(value)) } } } serde_bser-0.4.0/src/de/template.rs000064400000000000000000000161060072674642500153360ustar 00000000000000/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ use std::borrow::Cow; use std::rc::Rc; use serde::de; use serde::forward_to_deserialize_any; use serde::Deserialize; use super::read::DeRead; use super::reentrant::ReentrantGuard; use super::Deserializer; use crate::errors::*; use crate::header::*; // This is ugly because #[serde(borrow)] can't be used with collections directly // at the moment. See // https://github.com/serde-rs/serde/issues/914#issuecomment-298801226 for more. // Note that keys are always ASCII, so treating them as str is fine, even if they're // serialized as BSER_BYTESTRING instances. (These keys are used as struct field // identifiers, which are Unicode strings so can't be directly matched up with // bytestrings.) #[derive(Clone, Debug, Deserialize)] pub struct Key<'a>(#[serde(borrow)] Cow<'a, str>); /// A BSER template is logically an array of objects, all with the same or /// similar keys. /// /// A template is serialized as /// `...` /// /// and gets deserialized as /// /// ```text /// [ /// {key1: obj1_value1, key2: obj1_value2, ...}, /// {key2: obj2_value1, key2: obj2_value2, ...}, /// ... /// ] /// ``` /// /// The special value BSER_SKIP is used if a particular object doesn't have a /// key. pub struct Template<'a, 'de, R> { de: &'a mut Deserializer, keys: Rc>>, remaining: usize, } impl<'a, 'de, R: 'a> Template<'a, 'de, R> { /// Create a new `Template`. /// /// `_guard` makes sure the caller is accounting for the recursion limit. pub fn new( de: &'a mut Deserializer, keys: Vec>, nitems: usize, _guard: &ReentrantGuard, ) -> Self { Template { de, keys: Rc::new(keys), remaining: nitems, } } } impl<'a, 'de, R> de::SeqAccess<'de> for Template<'a, 'de, R> where R: 'a + DeRead<'de>, { type Error = Error; fn next_element_seed(&mut self, seed: T) -> Result> where T: de::DeserializeSeed<'de>, { if self.remaining == 0 { Ok(None) } else { self.remaining -= 1; let obj_de = ObjectDeserializer { de: &mut *self.de, keys: self.keys.clone(), }; let value = seed.deserialize(obj_de)?; Ok(Some(value)) } } } struct ObjectDeserializer<'a, 'de, R> { de: &'a mut Deserializer, keys: Rc>>, } impl<'a, 'de, R> de::Deserializer<'de> for ObjectDeserializer<'a, 'de, R> where R: 'a + DeRead<'de>, { type Error = Error; #[inline] fn deserialize_any(self, visitor: V) -> Result where V: de::Visitor<'de>, { visitor.visit_map(TemplateObject::new(&mut *self.de, self.keys)) } #[inline] fn deserialize_newtype_struct(self, _name: &'static str, visitor: V) -> Result where V: de::Visitor<'de>, { // This is e.g. E(T). Ignore the E. visitor.visit_newtype_struct(self) } fn deserialize_enum( self, _name: &'static str, _variants: &'static [&'static str], visitor: V, ) -> Result where V: de::Visitor<'de>, { visitor.visit_map(TemplateObject::new(&mut *self.de, self.keys)) } forward_to_deserialize_any! { bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes byte_buf unit unit_struct seq tuple tuple_struct map struct identifier ignored_any option } } struct TemplateObject<'a, 'de, R> { de: &'a mut Deserializer, keys: Rc>>, cur: usize, } impl<'a, 'de, R> TemplateObject<'a, 'de, R> where R: 'a + DeRead<'de>, { fn new(de: &'a mut Deserializer, keys: Rc>>) -> Self { TemplateObject { de, keys, cur: 0 } } } impl<'a, 'de, R> de::MapAccess<'de> for TemplateObject<'a, 'de, R> where R: 'a + DeRead<'de>, { type Error = Error; fn next_key_seed(&mut self, seed: K) -> Result> where K: de::DeserializeSeed<'de>, { if self.cur == self.keys.len() { Ok(None) } else { let cur = self.cur; self.cur += 1; let obj_de = KeyDeserializer { key: &self.keys[cur], }; let value = seed.deserialize(obj_de)?; Ok(Some(value)) } } fn next_value_seed(&mut self, seed: V) -> Result where V: de::DeserializeSeed<'de>, { seed.deserialize(ValueDeserializer { de: &mut *self.de }) } } struct KeyDeserializer<'a, 'de> { key: &'a Key<'de>, } impl<'a, 'de: 'a> de::Deserializer<'de> for KeyDeserializer<'a, 'de> { type Error = Error; #[inline] fn deserialize_any(self, visitor: V) -> Result where V: de::Visitor<'de>, { match self.key.0 { Cow::Borrowed(s) => visitor.visit_borrowed_str(s), Cow::Owned(ref s) => visitor.visit_str(s), } } forward_to_deserialize_any! { bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes byte_buf unit unit_struct seq tuple tuple_struct map struct identifier ignored_any option enum newtype_struct } } struct ValueDeserializer<'a, R> { de: &'a mut Deserializer, } impl<'a, 'de, R> de::Deserializer<'de> for ValueDeserializer<'a, R> where R: 'a + DeRead<'de>, { type Error = Error; #[inline] fn deserialize_any(self, visitor: V) -> Result where V: de::Visitor<'de>, { // The only new thing here compared to the main Deserializer is that it // is possible to skip this value with BSER_SKIP. match self.de.bunser.peek()? { BSER_SKIP => { self.de.bunser.discard(); visitor.visit_none() } _ => self.de.deserialize_any(visitor), } } /// Parse a BSER_SKIP or a null as a None, and anything else as a /// `Some(...)`. #[inline] fn deserialize_option(self, visitor: V) -> Result where V: de::Visitor<'de>, { match self.de.bunser.peek()? { BSER_SKIP | BSER_NULL => { self.de.bunser.discard(); visitor.visit_none() } _ => visitor.visit_some(self), } } #[inline] fn deserialize_newtype_struct(self, _name: &str, visitor: V) -> Result where V: de::Visitor<'de>, { // This is e.g. E(T). Ignore the E. visitor.visit_newtype_struct(self) } // TODO: do we also need to do enum here? forward_to_deserialize_any! { bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char str string bytes byte_buf unit unit_struct seq tuple tuple_struct map struct identifier ignored_any enum } } serde_bser-0.4.0/src/de/test.rs000064400000000000000000000374010072674642500145030ustar 00000000000000/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ use std::borrow::Cow; use std::collections::HashMap; use std::io::Cursor; use maplit::hashmap; use serde::Deserialize; use crate::from_reader; use crate::from_slice; // For "from_reader" data in owned and for "from_slice" data is borrowed #[derive(Debug, Deserialize, Eq, Hash, PartialEq)] struct Bytestring<'a>(#[serde(borrow)] Cow<'a, [u8]>); impl<'a> From<&'a [u8]> for Bytestring<'a> { fn from(value: &'a [u8]) -> Self { Bytestring(Cow::Borrowed(value)) } } impl<'a, 'b> PartialEq<&'b [u8]> for Bytestring<'a> { fn eq(&self, rhs: &&'b [u8]) -> bool { self.0 == *rhs } } #[derive(Debug, Deserialize, Eq, PartialEq)] struct BytestringArray<'a>(#[serde(borrow)] Vec>); #[derive(Debug, Deserialize, Eq, PartialEq)] struct BytestringObject<'a>(#[serde(borrow)] HashMap, Bytestring<'a>>); #[derive(Debug, Deserialize, Eq, PartialEq)] struct TwoBytestrings<'a>( #[serde(borrow)] Bytestring<'a>, #[serde(borrow)] Bytestring<'a>, ); #[derive(Debug, Deserialize, Eq, PartialEq)] enum BytestringVariant<'a> { TestUnit, TestNewtype(Bytestring<'a>), TestTuple( #[serde(borrow)] Bytestring<'a>, #[serde(borrow)] Bytestring<'a>, ), TestStruct { #[serde(borrow)] abc: Bytestring<'a>, #[serde(borrow)] def: Bytestring<'a>, }, } #[derive(Debug, Deserialize, Eq, PartialEq)] enum StringVariant { TestUnit, TestNewtype(String), TestTuple(String, String), TestStruct { abc: String, def: String }, } #[test] fn test_basic_array() { let bser_v2 = b"\x00\x02\x00\x00\x00\x00\x05\x11\x00\x00\x00\x00\x03\x02\x02\x03\x03Tom\x02\x03\x05Jerry"; let decoded = from_slice::>(bser_v2).unwrap(); assert_eq!(decoded.0, vec![&b"Tom"[..], &b"Jerry"[..]]); let reader = Cursor::new(bser_v2.to_vec()); let decoded: Vec = from_reader(reader).unwrap(); let expected = vec!["Tom", "Jerry"]; assert_eq!(decoded, expected); } #[test] fn test_basic_object() { let bser_v2 = b"\x00\x02\x00\x00\x00\x00\x05\x0f\x00\x00\x00\x01\x03\x01\x02\x03\x03abc\x02\x03\x03def"; let decoded = from_slice::>(bser_v2).unwrap(); let expected = hashmap! { Bytestring::from(&b"abc"[..]) => Bytestring::from(&b"def"[..]) }; assert_eq!(decoded.0, expected); let reader = Cursor::new(bser_v2.to_vec()); let decoded: HashMap = from_reader(reader).unwrap(); let expected = hashmap! { "abc".into() => "def".into() }; assert_eq!(decoded, expected); } #[test] fn test_basic_tuple() { let bser_v2 = b"\x00\x02\x00\x00\x00\x00\x05\x11\x00\x00\x00\x00\x03\x02\x02\x03\x03Tom\x02\x03\x05Jerry"; let decoded = from_slice::>(bser_v2).unwrap(); assert_eq!(decoded.0, &b"Tom"[..]); assert_eq!(decoded.1, &b"Jerry"[..]); let reader = Cursor::new(bser_v2.to_vec()); let decoded: (String, String) = from_reader(reader).unwrap(); let expected: (String, String) = ("Tom".into(), "Jerry".into()); assert_eq!(decoded, expected); } #[test] fn test_bare_variant() { // "TestUnit" let bser_v2 = b"\x00\x02\x00\x00\x00\x00\x05\x0b\x00\x00\x00\x02\x03\x08TestUnit"; let decoded = from_slice::>(bser_v2).unwrap(); assert_eq!(decoded, BytestringVariant::TestUnit); let reader = Cursor::new(bser_v2.to_vec()); let decoded: StringVariant = from_reader(reader).unwrap(); assert_eq!(decoded, StringVariant::TestUnit); } #[test] fn test_unit_variant() { // {"TestUnit": null} let bser_v2 = b"\x00\x02\x00\x00\x00\x00\x05\x0f\x00\x00\x00\x01\x03\x01\x02\x03\x08TestUnit\n"; let decoded = from_slice::>(bser_v2).unwrap(); assert_eq!(decoded, BytestringVariant::TestUnit); let reader = Cursor::new(bser_v2.to_vec()); let decoded: StringVariant = from_reader(reader).unwrap(); assert_eq!(decoded, StringVariant::TestUnit); } #[test] fn test_newtype_variant() { // {"TestNewtype": "foobar"} let bser_v2 = b"\x00\x02\x00\x00\x00\x00\x05\x1a\x00\x00\x00\x01\x03\x01\x02\x03\x0bTestNewtype\ \x02\x03\x06foobar"; let decoded = from_slice::>(bser_v2).unwrap(); assert_eq!( decoded, BytestringVariant::TestNewtype((&b"foobar"[..]).into()) ); let reader = Cursor::new(bser_v2.to_vec()); let decoded: StringVariant = from_reader(reader).unwrap(); assert_eq!(decoded, StringVariant::TestNewtype("foobar".into())); } #[test] fn test_tuple_variant() { // {"TestTuple": ["foo", "bar"]} let bser_v2 = b"\x00\x02\x00\x00\x00\x00\x05\x1e\x00\x00\x00\x01\x03\x01\x02\x03\tTestTuple\ \x00\x03\x02\x02\x03\x03foo\x02\x03\x03bar"; let decoded = from_slice::>(bser_v2).unwrap(); assert_eq!( decoded, BytestringVariant::TestTuple((&b"foo"[..]).into(), (&b"bar"[..]).into()) ); let reader = Cursor::new(bser_v2.to_vec()); let decoded: StringVariant = from_reader(reader).unwrap(); assert_eq!( decoded, StringVariant::TestTuple("foo".into(), "bar".into()) ); } #[test] fn test_struct_variant() { // {"TestStruct": {"abc": "foo", "def": "bar"}} let bser_v2 = b"\x00\x02\x00\x00\x00\x00\x05+\x00\x00\x00\x01\x03\x01\x02\x03\nTestStruct\ \x01\x03\x02\x02\x03\x03abc\x02\x03\x03foo\x02\x03\x03def\x02\x03\x03bar"; let decoded = from_slice::>(bser_v2).unwrap(); assert_eq!( decoded, BytestringVariant::TestStruct { abc: (&b"foo"[..]).into(), def: (&b"bar"[..]).into(), } ); let reader = Cursor::new(bser_v2.to_vec()); let decoded: StringVariant = from_reader(reader).unwrap(); assert_eq!( decoded, StringVariant::TestStruct { abc: "foo".into(), def: "bar".into(), } ); } #[derive(Debug, Deserialize, Eq, PartialEq)] struct BytestringTemplateObject<'a> { abc: i32, #[serde(borrow)] def: Option>, ghi: Option, } #[derive(Debug, Deserialize, Eq, PartialEq)] struct TemplateObject { abc: i32, def: Option, ghi: Option, } #[test] fn test_template() { // Logical expansion of this template: // [ // {"abc": 123, "def": "bar", "ghi": null}, // {"abc": 456, "ghi": 789}, // ] // // The second "def" is skipped. let bser_v2 = b"\x00\x02\x00\x00\x00\x00\x05(\x00\x00\x00\x0b\x00\x03\x03\x02\x03\x03abc\x02\ \x03\x03def\x02\x03\x03ghi\x03\x02\x03{\x02\x03\x03bar\n\x04\xc8\x01\x0c\x04\ \x15\x03"; let decoded = from_slice::>>(bser_v2).unwrap(); assert_eq!( decoded, vec![ BytestringTemplateObject { abc: 123, def: Some((&b"bar"[..]).into()), ghi: None, }, BytestringTemplateObject { abc: 456, def: None, ghi: Some(789), }, ] ); let reader = Cursor::new(bser_v2.to_vec()); let decoded: Vec = from_reader(reader).unwrap(); assert_eq!( decoded, vec![ TemplateObject { abc: 123, def: Some("bar".into()), ghi: None, }, TemplateObject { abc: 456, def: None, ghi: Some(789), }, ] ); } #[derive(Debug, Deserialize, PartialEq)] #[serde(untagged)] pub enum RequestResult { Error(E), Ok(T), } #[derive(Debug, Deserialize, PartialEq)] pub struct FileInfo { name: String, size: u32, } #[derive(Debug, Deserialize, PartialEq)] pub struct Files { files: Vec, } #[derive(Debug, Deserialize, PartialEq)] pub struct RequestError { error: String, } #[derive(Debug, Deserialize, PartialEq)] pub struct BytestringFileInfo<'a> { #[serde(borrow)] name: Bytestring<'a>, size: u32, } #[derive(Debug, Deserialize, PartialEq)] pub struct BytestringFiles<'a> { #[serde(borrow)] files: Vec>, } #[derive(Debug, Deserialize, PartialEq)] pub struct BytestringRequestError<'a> { #[serde(borrow)] error: Bytestring<'a>, } #[test] fn test_compact_arrays() { // { // "files": [ // { // "name": "fbcode/scm/hg/lib/hg_watchman_client/tester/target/debug", // "size": 384 // }, // { // "name": "fbcode/scm/hg/lib/hg_watchman_client/tester/target/debug/deps", // "size": 3200 // }, // ] // } let bser_v2 = b"\x00\x02\x00\x00\x00\x00\x04\xeb\x00\x01\x03\x04\x02\x03\x05files\x0b\x00\x03\x02\x0d\x03\x04name\x0d\x03\x04size\x03\x02\x02\x038fbcode/scm/hg/lib/hg_watchman_client/tester/target/debug\x04\x80\x01\x02\x03\x3dfbcode/scm/hg/lib/hg_watchman_client/tester/target/debug/deps\x04\x80\x0c\x02\x03\x05clock\x0d\x03\x19c\x3a1525428959\x3a45796\x3a2\x3a7717\x02\x03\x11is_fresh_instance\x09\x02\x03\x07version\x0d\x03\x054.9.1"; let decoded = from_slice::>(bser_v2).unwrap(); assert_eq!( decoded, BytestringFiles { files: vec![ BytestringFileInfo { name: (&b"fbcode/scm/hg/lib/hg_watchman_client/tester/target/debug"[..]).into(), size: 384, }, BytestringFileInfo { name: (&b"fbcode/scm/hg/lib/hg_watchman_client/tester/target/debug/deps"[..]) .into(), size: 3200, }, ], } ); let reader = Cursor::new(bser_v2.to_vec()); let decoded: Files = from_reader(reader).unwrap(); assert_eq!( decoded, Files { files: vec![ FileInfo { name: "fbcode/scm/hg/lib/hg_watchman_client/tester/target/debug".into(), size: 384, }, FileInfo { name: "fbcode/scm/hg/lib/hg_watchman_client/tester/target/debug/deps".into(), size: 3200, }, ], } ); } #[test] fn test_compact_arrays_untagged_enum() { let bser_v2 = b"\x00\x02\x00\x00\x00\x00\x04\xeb\x00\x01\x03\x04\x02\x03\x05files\x0b\x00\x03\x02\x0d\x03\x04name\x0d\x03\x04size\x03\x02\x02\x038fbcode/scm/hg/lib/hg_watchman_client/tester/target/debug\x04\x80\x01\x02\x03\x3dfbcode/scm/hg/lib/hg_watchman_client/tester/target/debug/deps\x04\x80\x0c\x02\x03\x05clock\x0d\x03\x19c\x3a1525428959\x3a45796\x3a2\x3a7717\x02\x03\x11is_fresh_instance\x09\x02\x03\x07version\x0d\x03\x054.9.1"; let decoded = from_slice::, BytestringRequestError<'_>>>(bser_v2) .unwrap(); assert_eq!( decoded, RequestResult::Ok(BytestringFiles { files: vec![ BytestringFileInfo { name: (&b"fbcode/scm/hg/lib/hg_watchman_client/tester/target/debug"[..]).into(), size: 384, }, BytestringFileInfo { name: (&b"fbcode/scm/hg/lib/hg_watchman_client/tester/target/debug/deps"[..]) .into(), size: 3200, }, ], }) ); let reader = Cursor::new(bser_v2.to_vec()); let decoded: RequestResult = from_reader(reader).unwrap(); assert_eq!( decoded, RequestResult::Ok(Files { files: vec![ FileInfo { name: "fbcode/scm/hg/lib/hg_watchman_client/tester/target/debug".into(), size: 384, }, FileInfo { name: "fbcode/scm/hg/lib/hg_watchman_client/tester/target/debug/deps".into(), size: 3200, }, ], }) ); } #[test] // non compact arrays fn test_arrays() { // { // "files": [ // { // "name": "fbcode/scm/hg/lib/hg_watchman_client/tester/target/debug", // "size": 384 // }, // { // "name": "fbcode/scm/hg/lib/hg_watchman_client/tester", // "size": 224 // } // ] // } let bser_v2 = b"\x00\x02\x00\x00\x00\x00\x04\xea\x00\x01\x03\x04\x02\x03\x07version\x02\x03\x054.9.1\x02\x03\x11is_fresh_instance\x09\x02\x03\x05clock\x02\x03\x19c\x3a1525428959\x3a45796\x3a2\x3a9642\x02\x03\x05files\x00\x03\x02\x01\x03\x02\x02\x03\x04size\x04\x80\x01\x02\x03\x04name\x02\x038fbcode/scm/hg/lib/hg_watchman_client/tester/target/debug\x01\x03\x02\x02\x03\x04size\x04\xe0\x00\x02\x03\x04name\x02\x03\x2bfbcode/scm/hg/lib/hg_watchman_client/tester"; let decoded = from_slice::>(bser_v2).unwrap(); assert_eq!( decoded, BytestringFiles { files: vec![ BytestringFileInfo { name: (&b"fbcode/scm/hg/lib/hg_watchman_client/tester/target/debug"[..]).into(), size: 384, }, BytestringFileInfo { name: (&b"fbcode/scm/hg/lib/hg_watchman_client/tester"[..]).into(), size: 224, }, ], } ); let reader = Cursor::new(bser_v2.to_vec()); let decoded: Files = from_reader(reader).unwrap(); assert_eq!( decoded, Files { files: vec![ FileInfo { name: "fbcode/scm/hg/lib/hg_watchman_client/tester/target/debug".into(), size: 384, }, FileInfo { name: "fbcode/scm/hg/lib/hg_watchman_client/tester".into(), size: 224, }, ], } ); } #[test] // non compact arrays fn test_arrays_untagged_enum() { let bser_v2 = b"\x00\x02\x00\x00\x00\x00\x04\xea\x00\x01\x03\x04\x02\x03\x07version\x02\x03\x054.9.1\x02\x03\x11is_fresh_instance\x09\x02\x03\x05clock\x02\x03\x19c\x3a1525428959\x3a45796\x3a2\x3a9642\x02\x03\x05files\x00\x03\x02\x01\x03\x02\x02\x03\x04size\x04\x80\x01\x02\x03\x04name\x02\x038fbcode/scm/hg/lib/hg_watchman_client/tester/target/debug\x01\x03\x02\x02\x03\x04size\x04\xe0\x00\x02\x03\x04name\x02\x03\x2bfbcode/scm/hg/lib/hg_watchman_client/tester"; let decoded = from_slice::, BytestringRequestError<'_>>>(bser_v2) .unwrap(); assert_eq!( decoded, RequestResult::Ok(BytestringFiles { files: vec![ BytestringFileInfo { name: (&b"fbcode/scm/hg/lib/hg_watchman_client/tester/target/debug"[..]).into(), size: 384, }, BytestringFileInfo { name: (&b"fbcode/scm/hg/lib/hg_watchman_client/tester"[..]).into(), size: 224, }, ], }) ); let reader = Cursor::new(bser_v2.to_vec()); let decoded: RequestResult = from_reader(reader).unwrap(); assert_eq!( decoded, RequestResult::Ok(Files { files: vec![ FileInfo { name: "fbcode/scm/hg/lib/hg_watchman_client/tester/target/debug".into(), size: 384, }, FileInfo { name: "fbcode/scm/hg/lib/hg_watchman_client/tester".into(), size: 224, }, ], }) ); } serde_bser-0.4.0/src/de/variant.rs000064400000000000000000000064610072674642500151720ustar 00000000000000/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ use serde::de; use super::read::DeRead; use super::reentrant::ReentrantGuard; use super::Deserializer; use crate::errors::*; macro_rules! impl_enum_access { ($type:ident) => { impl<'a, 'de, R> de::EnumAccess<'de> for $type<'a, R> where R: 'a + DeRead<'de>, { type Error = Error; type Variant = Self; fn variant_seed(self, seed: V) -> Result<(V::Value, Self)> where V: de::DeserializeSeed<'de>, { let val = seed.deserialize(&mut *self.de)?; Ok((val, self)) } } }; } /// Deserialize access for unit, struct and tuple variants. pub struct VariantAccess<'a, R> { de: &'a mut Deserializer, } impl<'a, 'de, R> VariantAccess<'a, R> where R: 'a + DeRead<'de>, { /// Create a new `VariantAccess`. /// /// `_guard` makes sure the caller is accounting for the recursion limit. pub fn new(de: &'a mut Deserializer, _guard: &ReentrantGuard) -> Self { VariantAccess { de } } } impl_enum_access!(VariantAccess); impl<'a, 'de, R> de::VariantAccess<'de> for VariantAccess<'a, R> where R: 'a + DeRead<'de>, { type Error = Error; fn unit_variant(self) -> Result<()> { de::Deserialize::deserialize(self.de) } fn newtype_variant_seed(self, seed: T) -> Result where T: de::DeserializeSeed<'de>, { seed.deserialize(self.de) } fn tuple_variant(self, _len: usize, visitor: V) -> Result where V: de::Visitor<'de>, { de::Deserializer::deserialize_any(self.de, visitor) } fn struct_variant(self, _fields: &'static [&'static str], visitor: V) -> Result where V: de::Visitor<'de>, { de::Deserializer::deserialize_any(self.de, visitor) } } /// Deserialize access for plain unit variants. pub struct UnitVariantAccess<'a, R> { de: &'a mut Deserializer, } impl<'a, 'de, R> UnitVariantAccess<'a, R> where R: 'a + DeRead<'de>, { pub fn new(de: &'a mut Deserializer) -> Self { UnitVariantAccess { de } } } impl_enum_access!(UnitVariantAccess); impl<'a, 'de, R> de::VariantAccess<'de> for UnitVariantAccess<'a, R> where R: 'a + DeRead<'de>, { type Error = Error; fn unit_variant(self) -> Result<()> { Ok(()) } fn newtype_variant_seed(self, _seed: T) -> Result where T: de::DeserializeSeed<'de>, { Err(de::Error::invalid_type( de::Unexpected::UnitVariant, &"newtype variant", )) } fn tuple_variant(self, _len: usize, _visitor: V) -> Result where V: de::Visitor<'de>, { Err(de::Error::invalid_type( de::Unexpected::UnitVariant, &"tuple variant", )) } fn struct_variant(self, _fields: &'static [&'static str], _visitor: V) -> Result where V: de::Visitor<'de>, { Err(de::Error::invalid_type( de::Unexpected::UnitVariant, &"struct variant", )) } } serde_bser-0.4.0/src/errors.rs000064400000000000000000000035500072674642500144460ustar 00000000000000/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ use std::fmt; use serde::de; use serde::ser; use thiserror::Error; use crate::header::header_byte_desc; pub type Result = ::std::result::Result; #[derive(Error, Debug)] pub enum Error { #[error("while deserializing BSER: invalid start byte for {}: {}", .kind, header_byte_desc(*.byte))] DeInvalidStartByte { kind: String, byte: u8 }, #[error("error while deserializing BSER: {}", msg)] DeCustom { msg: String }, #[error("while deserializing BSER: recursion limit exceeded with {}", .kind)] DeRecursionLimitExceeded { kind: String }, #[error("Expected {} bytes read, but only read {} bytes", .expected, .read)] DeEof { expected: usize, read: usize }, #[error("Invalid magic header: {:?}", .magic)] DeInvalidMagic { magic: Vec }, #[error("reader error while deserializing")] DeReaderError { #[source] source: anyhow::Error, }, #[error("error while serializing BSER: {}", .msg)] SerCustom { msg: String }, #[error("while serializing BSER: need size of {}", .kind)] SerNeedSize { kind: &'static str }, #[error("while serializing BSER: integer too big: {}", .v)] SerU64TooBig { v: u64 }, #[error("IO Error")] Io(#[from] ::std::io::Error), } impl Error { pub fn de_reader_error(source: anyhow::Error) -> Self { Self::DeReaderError { source } } } impl de::Error for Error { fn custom(msg: T) -> Self { Error::DeCustom { msg: format!("{}", msg), } } } impl ser::Error for Error { fn custom(msg: T) -> Self { Error::SerCustom { msg: format!("{}", msg), } } } serde_bser-0.4.0/src/header.rs000064400000000000000000000033700072674642500143620ustar 00000000000000/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ //! Header constants for BSER. pub const EMPTY_HEADER: &[u8] = b"\x00\x02\x00\x00\x00\x00\x05\x00\x00\x00\x00"; pub const BSER_ARRAY: u8 = 0x00; pub const BSER_OBJECT: u8 = 0x01; pub const BSER_BYTESTRING: u8 = 0x02; pub const BSER_INT8: u8 = 0x03; pub const BSER_INT16: u8 = 0x04; pub const BSER_INT32: u8 = 0x05; pub const BSER_INT64: u8 = 0x06; pub const BSER_REAL: u8 = 0x07; pub const BSER_TRUE: u8 = 0x08; pub const BSER_FALSE: u8 = 0x09; pub const BSER_NULL: u8 = 0x0a; pub const BSER_TEMPLATE: u8 = 0x0b; pub const BSER_SKIP: u8 = 0x0c; pub const BSER_UTF8STRING: u8 = 0x0d; // Capabilities (we would ideally want to use EnumSet here, but // https://github.com/contain-rs/enum-set/issues/21 stops us) #[allow(unused)] pub const BSER_CAP_DISABLE_UNICODE: u8 = 0x01; #[allow(unused)] pub const BSER_CAP_DISABLE_UNICODE_FOR_ERRORS: u8 = 0x02; pub fn header_byte_desc(byte: u8) -> String { match byte { BSER_ARRAY => "BSER_ARRAY".into(), BSER_OBJECT => "BSER_OBJECT".into(), BSER_BYTESTRING => "BSER_BYTESTRING".into(), BSER_INT8 => "BSER_INT8".into(), BSER_INT16 => "BSER_INT16".into(), BSER_INT32 => "BSER_INT32".into(), BSER_INT64 => "BSER_INT64".into(), BSER_REAL => "BSER_REAL".into(), BSER_TRUE => "BSER_TRUE".into(), BSER_FALSE => "BSER_FALSE".into(), BSER_NULL => "BSER_NULL".into(), BSER_TEMPLATE => "BSER_TEMPLATE".into(), BSER_SKIP => "BSER_SKIP".into(), BSER_UTF8STRING => "BSER_UTF8STRING".into(), ch => format!("unknown byte '{:?}'", ch), } } serde_bser-0.4.0/src/lib.rs000064400000000000000000000006210072674642500136740ustar 00000000000000/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #![cfg_attr(fbcode_build, deny(warnings, rust_2018_idioms))] pub mod bytestring; pub mod de; mod errors; mod header; pub mod ser; pub mod value; pub use crate::de::from_reader; pub use crate::de::from_slice; serde_bser-0.4.0/src/ser/count_write.rs000064400000000000000000000013310072674642500162600ustar 00000000000000/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ use std::io; use std::io::Write; /// A writer that counts how many bytes were written. pub struct CountWrite { count: usize, } impl CountWrite { pub fn new() -> Self { CountWrite { count: 0 } } #[inline] pub fn count(&self) -> usize { self.count } } impl Write for CountWrite { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { self.count += buf.len(); Ok(buf.len()) } #[inline] fn flush(&mut self) -> io::Result<()> { Ok(()) } } serde_bser-0.4.0/src/ser/mod.rs000064400000000000000000000316010072674642500145000ustar 00000000000000/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ mod count_write; #[cfg(test)] mod test; use std::io; use bytes::BufMut; use serde::ser; use serde::ser::Serialize; use self::count_write::CountWrite; use crate::errors::*; use crate::header::*; // How full must the buffer get before we start flushing it? const HIGHWATER: usize = 4096; pub fn serialize(mut writer: W, value: T) -> Result where W: io::Write, T: ser::Serialize, { // For the PDU info we need to first count how many bytes it is going to be. let mut count_serializer = Serializer::new(CountWrite::new()); value.serialize(&mut count_serializer)?; let count_write = count_serializer.finish()?; let count = count_write.count(); // Now write out the first bits of PDU info. // TODO: make this tokio AsyncWrite compatible // TODO: support capabilities writer.write_all(b"\x00\x02\x00\x00\x00\x00")?; let mut serializer = Serializer::new(writer); count.serialize(&mut serializer)?; // Finally, serialize the value value.serialize(&mut serializer)?; Ok(serializer.finish()?) } pub struct Serializer { writer: W, scratch: Vec, offset: usize, } /// If the value fits in the size specified by `$to`, call the `$put` function. /// /// This works for all $val types except for `u64`. macro_rules! maybe_put_int { ($self:ident, $val:expr, $to:ident, $put:ident) => { let min = $to::min_value() as i64; let max = $to::max_value() as i64; let val = $val as i64; if val >= min && val <= max { return $self.$put($val as $to); } }; } impl Serializer where W: io::Write, { // Create a new BSER serializer without leading PDU info. fn new(writer: W) -> Self { Serializer { writer, scratch: Vec::with_capacity(HIGHWATER * 2), offset: 0, } } /// Write out any internally cached data through to the writer. #[inline] pub fn flush(&mut self) -> io::Result<()> { while self.offset < self.scratch.len() { match self.writer.write(&self.scratch[self.offset..]) { Ok(n) => self.offset += n, Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} Err(e) => return Err(e), }; } self.offset = 0; unsafe { self.scratch.set_len(0); } Ok(()) } /// Finish writing any buffered data and unwrap the inner `Write`. pub fn finish(mut self) -> io::Result { self.flush()?; Ok(self.writer) } /// Try flushing any buffered data. If successful, unwrap the inner /// `Write`. On failure, return `Self` and the error. #[inline] pub fn try_finish(mut self) -> ::std::result::Result { match self.flush() { Ok(()) => Ok(self.writer), Err(e) => Err((self, e)), } } #[inline] fn maybe_flush(&mut self) -> Result<()> { if self.scratch.len() > HIGHWATER { Ok(self.flush()?) } else { Ok(()) } } #[inline] fn put_i8(&mut self, v: i8) { self.scratch.push(BSER_INT8); self.scratch.push(v as u8); } #[inline] fn put_i16(&mut self, v: i16) { maybe_put_int!(self, v, i8, put_i8); self.scratch.push(BSER_INT16); #[cfg(target_endian = "little")] self.scratch.put_i16_le(v); #[cfg(target_endian = "big")] self.scratch.put_i16_be(v); } #[inline] fn put_i32(&mut self, v: i32) { maybe_put_int!(self, v, i16, put_i16); self.scratch.push(BSER_INT32); #[cfg(target_endian = "little")] self.scratch.put_i32_le(v); #[cfg(target_endian = "big")] self.scratch.put_i32_be(v); } #[inline] fn put_i64(&mut self, v: i64) { maybe_put_int!(self, v, i32, put_i32); self.scratch.push(BSER_INT64); #[cfg(target_endian = "little")] self.scratch.put_i64_le(v); #[cfg(target_endian = "big")] self.scratch.put_i64_be(v); } } macro_rules! write_val { ($self:ident, $val:expr) => {{ $self.maybe_flush()?; $self.scratch.push($val); Ok(()) }}; ($self:ident, $val:expr, $put:ident) => {{ $self.maybe_flush()?; $self.$put($val); Ok(()) }}; } impl<'a, W> ser::Serializer for &'a mut Serializer where W: io::Write, { type Ok = (); type Error = Error; type SerializeSeq = Compound<'a, W>; type SerializeTuple = Compound<'a, W>; type SerializeTupleStruct = Compound<'a, W>; type SerializeTupleVariant = Compound<'a, W>; type SerializeMap = Compound<'a, W>; type SerializeStruct = Compound<'a, W>; type SerializeStructVariant = Compound<'a, W>; #[inline] fn serialize_bool(self, value: bool) -> Result<()> { if value { write_val!(self, BSER_TRUE) } else { write_val!(self, BSER_FALSE) } } #[inline] fn serialize_i8(self, v: i8) -> Result<()> { write_val!(self, v, put_i8) } #[inline] fn serialize_i16(self, v: i16) -> Result<()> { write_val!(self, v, put_i16) } #[inline] fn serialize_i32(self, v: i32) -> Result<()> { write_val!(self, v, put_i32) } #[inline] fn serialize_i64(self, v: i64) -> Result<()> { write_val!(self, v, put_i64) } #[inline] fn serialize_u8(self, v: u8) -> Result<()> { maybe_put_int!(self, v, i8, serialize_i8); self.serialize_i16(v as i16) } #[inline] fn serialize_u16(self, v: u16) -> Result<()> { maybe_put_int!(self, v, i16, serialize_i16); self.serialize_i32(v as i32) } #[inline] fn serialize_u32(self, v: u32) -> Result<()> { maybe_put_int!(self, v, i32, serialize_i32); self.serialize_i64(v as i64) } #[inline] fn serialize_u64(self, v: u64) -> Result<()> { // maybe_put_int! doesn't work for u64 because it converts to i64 // internally. if v > (i64::max_value() as u64) { Err(Error::SerU64TooBig { v }) } else { self.serialize_i64(v as i64) } } #[inline] fn serialize_f32(self, v: f32) -> Result<()> { self.serialize_f64(v as f64) } #[inline] fn serialize_f64(self, v: f64) -> Result<()> { self.maybe_flush()?; self.scratch.push(BSER_REAL); #[cfg(target_endian = "little")] self.scratch.put_f64_le(v); #[cfg(target_endian = "big")] self.scratch.put_f64_be(v); Ok(()) } #[inline] fn serialize_char(self, v: char) -> Result<()> { self.serialize_str(&v.to_string()) } #[inline] fn serialize_str(self, v: &str) -> Result<()> { self.maybe_flush()?; self.scratch.push(BSER_UTF8STRING); self.put_i64(v.len() as i64); self.scratch.extend_from_slice(v.as_bytes()); Ok(()) } #[inline] fn serialize_bytes(self, v: &[u8]) -> Result<()> { self.maybe_flush()?; self.scratch.push(BSER_BYTESTRING); self.put_i64(v.len() as i64); self.scratch.extend_from_slice(v); Ok(()) } #[inline] fn serialize_unit(self) -> Result<()> { write_val!(self, BSER_NULL) } #[inline] fn serialize_unit_struct(self, _name: &'static str) -> Result<()> { self.serialize_unit() } #[inline] fn serialize_unit_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, ) -> Result<()> { self.serialize_str(variant) } #[inline] fn serialize_newtype_struct(self, _name: &'static str, value: &T) -> Result<()> where T: ?Sized + ser::Serialize, { // This is e.g. E(T). Ignore the E. value.serialize(self) } #[inline] fn serialize_newtype_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, value: &T, ) -> Result<()> where T: ?Sized + ser::Serialize, { use serde::ser::SerializeStruct; // This is e.g. E { N(T) }, where N is the variant. // Serialize this as {variant: value} let mut ser_struct = self.serialize_struct("", 1)?; ser_struct.serialize_field(variant, value)?; ser_struct.end() } #[inline] fn serialize_none(self) -> Result<()> { self.serialize_unit() } #[inline] fn serialize_some(self, value: &T) -> Result<()> where T: ?Sized + ser::Serialize, { value.serialize(self) } #[inline] fn serialize_seq(self, len: Option) -> Result { match len { None => Err(Error::SerNeedSize { kind: "sequence" }), Some(len) => self.serialize_tuple(len), } } #[inline] fn serialize_tuple(self, len: usize) -> Result { // (A, B, C) etc. Serialize this as an array. self.maybe_flush()?; self.scratch.push(BSER_ARRAY); self.put_i64(len as i64); Ok(Compound { ser: self }) } #[inline] fn serialize_tuple_struct( self, _name: &'static str, len: usize, ) -> Result { self.serialize_tuple(len) } #[inline] fn serialize_tuple_variant( self, _name: &'static str, _variant_index: u32, variant: &'static str, len: usize, ) -> Result { // This is e.g. E { N(A, B, C) }, where N is the variant. Serialize this // as { variant: [values] }. self.maybe_flush()?; self.scratch.push(BSER_OBJECT); self.put_i8(1); self.serialize_str(variant)?; self.serialize_tuple(len) } #[inline] fn serialize_map(self, len: Option) -> Result { match len { None => Err(Error::SerNeedSize { kind: "map" }), Some(len) => self.serialize_struct("", len), } } #[inline] fn serialize_struct(self, _name: &'static str, len: usize) -> Result { self.maybe_flush()?; // BSER objects are serialized as (...). self.scratch.push(BSER_OBJECT); self.put_i64(len as i64); Ok(Compound { ser: self }) } #[inline] fn serialize_struct_variant( self, name: &'static str, variant_index: u32, variant: &'static str, len: usize, ) -> Result { // This is e.g. E { N { foo: A, bar: B } }, where N is the // variant. Serialize this as { variant: { foo: valA, bar: valB } }. // That's really the same as serialize_tuple_variant. self.serialize_tuple_variant(name, variant_index, variant, len) } } #[doc(hidden)] pub struct Compound<'a, W> { ser: &'a mut Serializer, } macro_rules! impl_compound { ($trait:ty, [$($fns:ident),*]) => { impl<'a, W> $trait for Compound<'a, W> where W: io::Write { type Ok = (); type Error = Error; $( #[inline] fn $fns(&mut self, value: &T) -> Result<()> where T: ?Sized + ser::Serialize { value.serialize(&mut *self.ser) } )* #[inline] fn end(self) -> Result<()> { Ok(()) } } } } impl_compound!(ser::SerializeSeq, [serialize_element]); impl_compound!(ser::SerializeTuple, [serialize_element]); impl_compound!(ser::SerializeTupleStruct, [serialize_field]); impl_compound!(ser::SerializeTupleVariant, [serialize_field]); impl_compound!(ser::SerializeMap, [serialize_key, serialize_value]); macro_rules! impl_compound_struct { ($trait:ty) => { impl<'a, W> $trait for Compound<'a, W> where W: io::Write, { type Ok = (); type Error = Error; #[inline] fn serialize_field(&mut self, key: &'static str, value: &T) -> Result<()> where T: ?Sized + ser::Serialize, { // TODO: this can go wrong if writing out the key succeeds but // writing the value fails. ser::SerializeMap::serialize_key(self, key)?; ser::SerializeMap::serialize_value(self, value) } #[inline] fn end(self) -> Result<()> { ser::SerializeMap::end(self) } } }; } impl_compound_struct!(ser::SerializeStruct); impl_compound_struct!(ser::SerializeStructVariant); serde_bser-0.4.0/src/ser/test.rs000064400000000000000000000040130072674642500146750ustar 00000000000000/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ use std::f64::consts; use serde::Serialize; use super::serialize; #[derive(Debug, Serialize)] enum TestEnum { TestUnit, TestNewtype(#[serde(with = "serde_bytes")] &'static [u8]), TestTuple(i8, u64), TestStruct { abc: (), def: char }, } #[derive(Debug, Serialize)] struct SerializeStruct { test_list: Vec, test_tuple: (String, Option), test_enum: TestEnum, test_enum_list: Vec, } const BASIC_SERIALIZED: &[u8] = b"\x00\x02\x00\x00\x00\x00\x04\xcb\x00\x01\x03\x04\r\x03\t\ test_list\x00\x03\x05\x03\x03\x03\x04\x03*\x04\xdb\x03\x05\x00\ \x00\x08\x00\r\x03\ntest_tuple\x00\x03\x02\r\x03\x03foo\x07\ \x18-DT\xfb!\t@\r\x03\ttest_enum\r\x03\x08TestUnit\r\x03\x0e\ test_enum_list\x00\x03\x03\x01\x03\x01\r\x03\x0bTestNewtype\ \x02\x03\tBSER test\x01\x03\x01\r\x03\tTestTuple\x00\x03\x02\x03*\ \x06\xff\xff\xff\xff\xff\xff\xff\x7f\x01\x03\x01\r\x03\n\ TestStruct\x00\x03\x02\r\x03\x03abc\n\r\x03\x03\ def\r\x03\x04\xf0\x9f\x92\xa9"; #[test] fn test_basic_serialize() { let to_serialize = SerializeStruct { test_list: vec![3, 4, 42, 987, 2 << 18], test_tuple: ("foo".into(), Some(consts::PI)), test_enum: TestEnum::TestUnit, test_enum_list: vec![ TestEnum::TestNewtype(&b"BSER test"[..]), TestEnum::TestTuple(42, i64::max_value() as u64), TestEnum::TestStruct { abc: (), def: '\u{1f4a9}', }, ], }; let out = Vec::new(); let out = serialize(out, to_serialize).unwrap(); assert_eq!(out, BASIC_SERIALIZED); } serde_bser-0.4.0/src/value.rs000064400000000000000000000171170072674642500142520ustar 00000000000000/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ use std::collections::HashMap; use std::path::PathBuf; use serde::de::Deserialize; use serde::de::MapAccess; use serde::de::SeqAccess; use serde::de::Visitor; use serde::Serialize; use crate::bytestring::ByteString; /// The Value type is used in cases where the schema is not known statically. /// As used in Watchman's protocol, this allows encoding arbitrary metadata /// that can be passed through the system by eg: the `state-enter` command, /// or returned from a saved state storage engine. /// The values are conceptually equivalent to json values, with the notable /// difference that BSER can represent a binary byte string value. #[derive(Debug, Clone, PartialEq)] pub enum Value { Array(Vec), Object(HashMap), ByteString(ByteString), Integer(i64), Real(f64), Bool(bool), Null, Utf8String(String), } impl From> for Value { fn from(v: Vec) -> Self { Self::Array(v) } } impl From> for Value { fn from(v: HashMap) -> Self { Self::Object(v) } } impl From for Value { fn from(v: bool) -> Self { Self::Bool(v) } } impl From<&str> for Value { fn from(s: &str) -> Self { Self::Utf8String(s.to_string()) } } impl From for Value { fn from(s: String) -> Self { Self::Utf8String(s) } } impl TryInto for PathBuf { type Error = &'static str; fn try_into(self) -> Result { let s: ByteString = self.try_into()?; Ok(Value::ByteString(s)) } } impl From for Value { fn from(v: i64) -> Self { Self::Integer(v) } } impl TryInto for usize { type Error = &'static str; fn try_into(self) -> Result { if self > i64::max_value() as usize { Err("value is too large to represent as i64") } else { Ok(Value::Integer(self as i64)) } } } impl<'de> Deserialize<'de> for Value { #[inline] fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { struct ValueVisitor; impl<'de> Visitor<'de> for ValueVisitor { type Value = Value; fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { formatter.write_str("any valid BSER value") } #[inline] fn visit_bool(self, value: bool) -> Result { Ok(Value::Bool(value)) } #[inline] fn visit_i64(self, value: i64) -> Result { Ok(Value::Integer(value)) } /* #[inline] fn visit_u64(self, v: u64) -> Result { // maybe_put_int! doesn't work for u64 because it converts to i64 // internally. if v > (i64::max_value() as u64) { Err(serde::de::Error::custom(format!( "value {} is too large to represent as a BSER integer", v ))) } else { Ok(Value::Integer(v as i64)) } } */ #[inline] fn visit_f64(self, value: f64) -> Result { Ok(Value::Real(value)) } #[inline] fn visit_bytes(self, value: &[u8]) -> Result { Ok(Value::ByteString(value.to_vec().into())) } #[inline] fn visit_byte_buf(self, value: Vec) -> Result { Ok(Value::ByteString(value.into())) } #[inline] fn visit_str(self, value: &str) -> Result where E: serde::de::Error, { self.visit_string(String::from(value)) } #[inline] fn visit_string(self, value: String) -> Result { Ok(Value::Utf8String(value)) } #[inline] fn visit_some(self, deserializer: D) -> Result where D: serde::Deserializer<'de>, { Deserialize::deserialize(deserializer) } #[inline] fn visit_none(self) -> Result { Ok(Value::Null) } #[inline] fn visit_unit(self) -> Result { Ok(Value::Null) } #[inline] fn visit_seq(self, mut visitor: V) -> Result where V: SeqAccess<'de>, { let mut vec = Vec::new(); while let Some(elem) = visitor.next_element()? { vec.push(elem); } Ok(Value::Array(vec)) } fn visit_map(self, mut visitor: V) -> Result where V: MapAccess<'de>, { match visitor.next_key()? { Some(Value::ByteString(key)) => { let mut values = HashMap::new(); values.insert( key.try_into().map_err(serde::de::Error::custom)?, visitor.next_value()?, ); while let Some((key, value)) = visitor.next_entry()? { values.insert(key, value); } Ok(Value::Object(values)) } Some(Value::Utf8String(key)) => { let mut values = HashMap::new(); values.insert(key, visitor.next_value()?); while let Some((key, value)) = visitor.next_entry()? { values.insert(key, value); } Ok(Value::Object(values)) } Some(value) => Err(serde::de::Error::custom(format!( "value {:?} is illegal as a key in a BSER map", value ))), None => Ok(Value::Object(HashMap::new())), } } } deserializer.deserialize_any(ValueVisitor) } } impl Serialize for Value { #[inline] fn serialize(&self, serializer: S) -> Result where S: ::serde::Serializer, { match *self { Value::Null => serializer.serialize_unit(), Value::Bool(b) => serializer.serialize_bool(b), Value::Integer(n) => serializer.serialize_i64(n), Value::Real(n) => serializer.serialize_f64(n), Value::Utf8String(ref s) => serializer.serialize_str(s), Value::ByteString(ref b) => serializer.serialize_bytes(b.as_bytes()), Value::Array(ref v) => v.serialize(serializer), Value::Object(ref m) => { use serde::ser::SerializeMap; let mut map = serializer.serialize_map(Some(m.len()))?; for (k, v) in m { map.serialize_key(k)?; map.serialize_value(v)?; } map.end() } } } }