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

Remove bincode #20

Merged
merged 8 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
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
6 changes: 3 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,22 @@ members = ["derive"]
[features]
default = []


[dependencies]
bincode = "1.3.3"
chrono = { version = "0.4.26", features = ["serde"], optional = true }
derive = { version = "0.8.0", package = "revision-derive", path = "derive" }
geo = { version = "0.26.0", features = ["use-serde"], optional = true }
ordered-float = { version = "3", optional = true }
regex = { version = "1.9.3", optional = true }
roaring = { version = "0.10.2", features = ["serde"], optional = true }
rust_decimal = { version = "1.31.0", optional = true }
serde = "1.0.183"
thiserror = "1.0.44"
uuid = { version = "1.4.1", optional = true }

[dev-dependencies]
rand = "0.8.5"
criterion = "0.5.1"
bincode = "1.3.3"
serde = "1.0.183"

[[bench]]
name = "roaring"
Expand Down
48 changes: 44 additions & 4 deletions src/error.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,62 @@
use thiserror::Error;
use std::{io, str::Utf8Error};

/// An error which occurs when revisioned serialization / deserialization fails.
#[derive(Error, Debug, PartialEq)]
#[derive(Debug)]
pub enum Error {
/// An IO error occured.
Io(i32),
/// Generic serialization error.
Io(io::Error),
/// Tried to deserialize a boolean value with an invalid byte value.
InvalidBoolValue(u8),
/// Deserialization encountered integer encoding which is not suported.
InvalidIntegerEncoding,
/// Deserialization encountered an integer with a value which did not fit the target type..
IntegerOverflow,
/// Path contains invalid utf-8 characters
InvalidPath,
/// Invalid character encoding
InvalidCharEncoding,
/// Error parsing a string
Utf8Error(Utf8Error),
/// Failed to serialize character.
Serialize(String),
/// Generic deserialization error.
Deserialize(String),
/// Semantic translation/validation error.
Conversion(String),
}

impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::Io(ref x) => Some(x),
Error::Utf8Error(ref x) => Some(x),
_ => None,
}
}
}

impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
match self {
Self::Io(e) => write!(f, "An IO error occured: {}", e),
Self::InvalidBoolValue(_) => {
write!(f, "Tried to deserialize a boolean value with an invalid byte value.")
}
Self::InvalidIntegerEncoding => {
write!(f, "Encountered invalid integer encoding.")
}
Self::IntegerOverflow => {
write!(f, "Encountered integer which doesn't fit the target integer type during deserialization.")
}
Self::InvalidPath => {
write!(f, "Path contained invalid UTF-8 characters.")
}
Self::InvalidCharEncoding => {
write!(f, "Invalid character encoding.")
}
Self::Utf8Error(x) => {
write!(f, "Invalid UTF-8 characters in string: {x}")
}
Self::Serialize(e) => write!(f, "A serialization error occured: {}", e),
Self::Deserialize(e) => write!(f, "A deserialization error occured: {}", e),
Self::Conversion(e) => write!(f, "A user generated conversion error occured: {}", e),
Expand Down
25 changes: 4 additions & 21 deletions src/implementations/bound.rs
Original file line number Diff line number Diff line change
@@ -1,43 +1,26 @@
use super::super::Error;
use super::super::Revisioned;
use bincode::Options;
use std::ops::Bound;

impl<T: Revisioned> Revisioned for Bound<T> {
#[inline]
fn serialize_revisioned<W: std::io::Write>(&self, writer: &mut W) -> Result<(), Error> {
let opts = bincode::options()
.with_no_limit()
.with_little_endian()
.with_varint_encoding()
.reject_trailing_bytes();
match *self {
Bound::Unbounded => opts
.serialize_into(writer, &0u32)
.map_err(|ref err| Error::Serialize(format!("{:?}", err))),
Bound::Unbounded => 0u32.serialize_revisioned(writer),
Bound::Included(ref value) => {
opts.serialize_into(&mut *writer, &1u32)
.map_err(|ref err| Error::Serialize(format!("{:?}", err)))?;
1u32.serialize_revisioned(writer)?;
value.serialize_revisioned(writer)
}
Bound::Excluded(ref value) => {
opts.serialize_into(&mut *writer, &2u32)
.map_err(|ref err| Error::Serialize(format!("{:?}", err)))?;
2u32.serialize_revisioned(writer)?;
value.serialize_revisioned(writer)
}
}
}

#[inline]
fn deserialize_revisioned<R: std::io::Read>(reader: &mut R) -> Result<Self, Error> {
let opts = bincode::options()
.with_no_limit()
.with_little_endian()
.with_varint_encoding()
.reject_trailing_bytes();
let variant: u32 = opts
.deserialize_from(&mut *reader)
.map_err(|ref err| Error::Deserialize(format!("{:?}", err)))?;
let variant = u32::deserialize_revisioned(reader)?;
match variant {
0 => Ok(Bound::Unbounded),
1 => Ok(Bound::Included(
Expand Down
29 changes: 4 additions & 25 deletions src/implementations/decimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,14 @@ use rust_decimal::Decimal;
impl Revisioned for Decimal {
#[inline]
fn serialize_revisioned<W: std::io::Write>(&self, writer: &mut W) -> Result<(), Error> {
writer
.write_all(self.serialize().as_slice())
.map_err(|e| Error::Io(e.raw_os_error().unwrap_or(0)))
writer.write_all(self.serialize().as_slice()).map_err(Error::Io)
}

#[inline]
fn deserialize_revisioned<R: std::io::Read>(reader: &mut R) -> Result<Self, Error> {
let mut v = vec![0u8; 16];
reader
.read_exact(v.as_mut_slice())
.map_err(|e| Error::Io(e.raw_os_error().unwrap_or(0)))?;
Ok(Decimal::deserialize([
v.remove(0),
v.remove(0),
v.remove(0),
v.remove(0),
v.remove(0),
v.remove(0),
v.remove(0),
v.remove(0),
v.remove(0),
v.remove(0),
v.remove(0),
v.remove(0),
v.remove(0),
v.remove(0),
v.remove(0),
v.remove(0),
]))
let mut b = [0u8; 16];
reader.read_exact(&mut b).map_err(Error::Io)?;
Ok(Decimal::deserialize(b))
}

fn revision() -> u16 {
Expand Down
29 changes: 14 additions & 15 deletions src/implementations/duration.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,19 @@
use super::super::Error;
use super::super::Revisioned;
use bincode::Options;
use std::time::Duration;

impl Revisioned for Duration {
#[inline]
fn serialize_revisioned<W: std::io::Write>(&self, writer: &mut W) -> Result<(), Error> {
bincode::options()
.with_no_limit()
.with_little_endian()
.with_varint_encoding()
.reject_trailing_bytes()
.serialize_into(writer, self)
.map_err(|ref err| Error::Serialize(format!("{:?}", err)))
self.as_secs().serialize_revisioned(writer)?;
self.subsec_nanos().serialize_revisioned(writer)
}

#[inline]
fn deserialize_revisioned<R: std::io::Read>(reader: &mut R) -> Result<Self, Error> {
bincode::options()
.with_no_limit()
.with_little_endian()
.with_varint_encoding()
.reject_trailing_bytes()
.deserialize_from(reader)
.map_err(|ref err| Error::Deserialize(format!("{:?}", err)))
let secs = u64::deserialize_revisioned(reader)?;
let nanos = u32::deserialize_revisioned(reader)?;
Ok(Duration::new(secs, nanos))
}

fn revision() -> u16 {
Expand All @@ -33,6 +23,7 @@ impl Revisioned for Duration {

#[cfg(test)]
mod tests {
use crate::implementations::assert_bincode_compat;

use super::Duration;
use super::Revisioned;
Expand All @@ -46,4 +37,12 @@ mod tests {
let out = <Duration as Revisioned>::deserialize_revisioned(&mut mem.as_slice()).unwrap();
assert_eq!(val, out);
}

#[test]
fn bincode_compat() {
assert_bincode_compat(&Duration::ZERO);
assert_bincode_compat(&Duration::MAX);
assert_bincode_compat(&Duration::new(u64::MAX, 0));
assert_bincode_compat(&Duration::new(0, 999_999_999));
}
}
Loading