Skip to content

Commit

Permalink
Rework decoding to be less error prone
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Mar 25, 2024
1 parent 490051b commit 25a267c
Show file tree
Hide file tree
Showing 67 changed files with 2,305 additions and 2,209 deletions.
48 changes: 28 additions & 20 deletions crates/musli-common/src/int/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::writer::Writer;

/// Governs how unsigned integers are encoded into a [Writer].
#[inline]
pub fn encode_unsigned<C, W, T, const F: Options>(
pub fn encode_unsigned<C, W, T, const OPT: Options>(
cx: &C,
writer: W,
value: T,
Expand All @@ -19,10 +19,10 @@ where
W: Writer,
T: Unsigned + UnsignedOps,
{
match crate::options::integer::<F>() {
match crate::options::integer::<OPT>() {
crate::options::Integer::Variable => c::encode(cx, writer, value),
_ => {
let bo = crate::options::byteorder::<F>();
let bo = crate::options::byteorder::<OPT>();
value.write_bytes(cx, writer, bo)
}
}
Expand All @@ -31,7 +31,7 @@ where
/// Decode an unsigned value from the specified reader using the configuration
/// passed in through `F`.
#[inline]
pub fn decode_unsigned<'de, C, R, T: UnsignedOps, const F: Options>(
pub fn decode_unsigned<'de, C, R, T: UnsignedOps, const OPT: Options>(
cx: &C,
reader: R,
) -> Result<T, C::Error>
Expand All @@ -40,65 +40,73 @@ where
R: Reader<'de>,
T: Unsigned,
{
match crate::options::integer::<F>() {
match crate::options::integer::<OPT>() {
crate::options::Integer::Variable => c::decode(cx, reader),
_ => {
let bo = crate::options::byteorder::<F>();
let bo = crate::options::byteorder::<OPT>();
T::read_bytes(cx, reader, bo)
}
}
}

/// Governs how signed integers are encoded into a [Writer].
#[inline]
pub fn encode_signed<C, W, T, const F: Options>(cx: &C, writer: W, value: T) -> Result<(), C::Error>
pub fn encode_signed<C, W, T, const OPT: Options>(
cx: &C,
writer: W,
value: T,
) -> Result<(), C::Error>
where
C: ?Sized + Context,
W: Writer,
T: Signed,
T::Unsigned: UnsignedOps,
{
match crate::options::integer::<F>() {
match crate::options::integer::<OPT>() {
crate::options::Integer::Variable => c::encode(cx, writer, zig::encode(value)),
_ => {
let bo = crate::options::byteorder::<F>();
let bo = crate::options::byteorder::<OPT>();
value.unsigned().write_bytes(cx, writer, bo)
}
}
}

/// Governs how signed integers are decoded from a [Reader].
#[inline]
pub fn decode_signed<'de, C, R, T, const F: Options>(cx: &C, reader: R) -> Result<T, C::Error>
pub fn decode_signed<'de, C, R, T, const OPT: Options>(cx: &C, reader: R) -> Result<T, C::Error>
where
C: ?Sized + Context,
R: Reader<'de>,
T: Signed,
T::Unsigned: UnsignedOps,
{
match crate::options::integer::<F>() {
match crate::options::integer::<OPT>() {
crate::options::Integer::Variable => {
let value: T::Unsigned = c::decode(cx, reader)?;
Ok(zig::decode(value))
}
_ => {
let bo = crate::options::byteorder::<F>();
let bo = crate::options::byteorder::<OPT>();
Ok(T::Unsigned::read_bytes(cx, reader, bo)?.signed())
}
}
}

/// Governs how usize lengths are encoded into a [Writer].
#[inline]
pub fn encode_usize<C, W, const F: Options>(cx: &C, writer: W, value: usize) -> Result<(), C::Error>
pub fn encode_usize<C, W, const OPT: Options>(
cx: &C,
writer: W,
value: usize,
) -> Result<(), C::Error>
where
C: ?Sized + Context,
W: Writer,
{
match crate::options::length::<F>() {
match crate::options::length::<OPT>() {
crate::options::Integer::Variable => c::encode(cx, writer, value),
_ => {
let bo = crate::options::byteorder::<F>();
let bo = crate::options::byteorder::<OPT>();
macro_rules! fixed {
($ty:ty) => {{
let Ok(value) = <$ty>::try_from(value) else {
Expand All @@ -109,22 +117,22 @@ where
}};
}

crate::width_arm!(crate::options::length_width::<F>(), fixed)
crate::width_arm!(crate::options::length_width::<OPT>(), fixed)
}
}
}

/// Governs how usize lengths are decoded from a [Reader].
#[inline]
pub fn decode_usize<'de, C, R, const F: Options>(cx: &C, reader: R) -> Result<usize, C::Error>
pub fn decode_usize<'de, C, R, const OPT: Options>(cx: &C, reader: R) -> Result<usize, C::Error>
where
C: ?Sized + Context,
R: Reader<'de>,
{
match crate::options::length::<F>() {
match crate::options::length::<OPT>() {
crate::options::Integer::Variable => c::decode(cx, reader),
_ => {
let bo = crate::options::byteorder::<F>();
let bo = crate::options::byteorder::<OPT>();

macro_rules! fixed {
($ty:ty) => {{
Expand All @@ -138,7 +146,7 @@ where
}};
}

crate::width_arm!(crate::options::length_width::<F>(), fixed)
crate::width_arm!(crate::options::length_width::<OPT>(), fixed)
}
}
}
23 changes: 13 additions & 10 deletions crates/musli-common/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ pub const fn new() -> OptionsBuilder {
///
/// Note: despite being made up of a primitive type, this cannot be serialized
/// and correctly re-used.
///
/// Making assumptions about its layout might lead to unspecified behavior
/// during encoding. Only use this type through the provided API.
pub type Options = u128;

const BYTEORDER_BIT: Options = 0;
Expand Down Expand Up @@ -56,33 +59,33 @@ impl OptionsBuilder {
}

#[doc(hidden)]
pub const fn integer<const F: Options>() -> Integer {
match (F >> INTEGER_BIT) & 0b1 {
pub const fn integer<const OPT: Options>() -> Integer {
match (OPT >> INTEGER_BIT) & 0b1 {
0 => Integer::Variable,
_ => Integer::Fixed,
}
}

#[doc(hidden)]
pub const fn float<const F: Options>() -> Float {
match (F >> FLOAT_BIT) & 0b11 {
pub const fn float<const OPT: Options>() -> Float {
match (OPT >> FLOAT_BIT) & 0b11 {
0 => Float::Integer,
1 => Float::Variable,
_ => Float::Fixed,
}
}

#[doc(hidden)]
pub const fn length<const F: Options>() -> Integer {
match (F >> LENGTH_BIT) & 0b1 {
pub const fn length<const OPT: Options>() -> Integer {
match (OPT >> LENGTH_BIT) & 0b1 {
0 => Integer::Variable,
_ => Integer::Fixed,
}
}

#[doc(hidden)]
pub const fn length_width<const F: Options>() -> Width {
match (F >> LENGTH_WIDTH_BIT) & 0b11 {
pub const fn length_width<const OPT: Options>() -> Width {
match (OPT >> LENGTH_WIDTH_BIT) & 0b11 {
0 => Width::U8,
1 => Width::U16,
2 => Width::U32,
Expand All @@ -91,8 +94,8 @@ pub const fn length_width<const F: Options>() -> Width {
}

#[doc(hidden)]
pub const fn byteorder<const F: Options>() -> ByteOrder {
match (F >> BYTEORDER_BIT) & 0b1 {
pub const fn byteorder<const OPT: Options>() -> ByteOrder {
match (OPT >> BYTEORDER_BIT) & 0b1 {
0 => ByteOrder::LittleEndian,
_ => ByteOrder::BigEndian,
}
Expand Down
Loading

0 comments on commit 25a267c

Please sign in to comment.