Skip to content

Commit

Permalink
Fix array encoding
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Apr 15, 2024
1 parent 6929cd5 commit 6de87b0
Show file tree
Hide file tree
Showing 8 changed files with 247 additions and 20 deletions.
2 changes: 1 addition & 1 deletion crates/musli-descriptive/src/integer_encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ where

Ok(value)
}
NumberKind::Unsigned => Ok(value),
NumberKind::Unsigned | NumberKind::Float => Ok(value),
kind => Err(cx.message(format_args!(
"Expected signed or unsigned number, got {:?}",
kind
Expand Down
4 changes: 3 additions & 1 deletion crates/musli-wire/src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,9 @@ where
} else {
musli_utils::int::decode_usize::<_, _, OPT>(self.cx, self.reader.borrow_mut())?
}),
_ => Err(self.cx.marked_message(start, "Expected prefix")),
kind => Err(self
.cx
.marked_message(start, format_args!("Expected prefix, but got {kind:?}"))),
}
}
}
Expand Down
21 changes: 21 additions & 0 deletions crates/musli/src/de/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,66 +17,87 @@
//! ```

mod skip;
#[doc(inline)]
pub use self::skip::Skip;

mod as_decoder;
#[doc(inline)]
pub use self::as_decoder::AsDecoder;

mod decode;
#[doc(inline)]
pub use self::decode::{Decode, TraceDecode};

mod decode_unsized;
#[doc(inline)]
pub use self::decode_unsized::DecodeUnsized;

mod decode_unsized_bytes;
#[doc(inline)]
pub use self::decode_unsized_bytes::DecodeUnsizedBytes;

mod decode_bytes;
#[doc(inline)]
pub use self::decode_bytes::DecodeBytes;

mod decoder;
#[doc(inline)]
pub use self::decoder::Decoder;

mod map_decoder;
#[doc(inline)]
pub use self::map_decoder::MapDecoder;

mod map_entries_decoder;
#[doc(inline)]
pub use self::map_entries_decoder::MapEntriesDecoder;

mod map_entry_decoder;
#[doc(inline)]
pub use self::map_entry_decoder::MapEntryDecoder;

mod number_visitor;
#[doc(inline)]
pub use self::number_visitor::NumberVisitor;

mod pack_decoder;
#[doc(inline)]
pub use self::pack_decoder::PackDecoder;

mod tuple_decoder;
#[doc(inline)]
pub use self::tuple_decoder::TupleDecoder;

mod sequence_decoder;
#[doc(inline)]
pub use self::sequence_decoder::SequenceDecoder;

mod struct_decoder;
#[doc(inline)]
pub use self::struct_decoder::StructDecoder;

mod struct_field_decoder;
#[doc(inline)]
pub use self::struct_field_decoder::StructFieldDecoder;

mod struct_fields_decoder;
#[doc(inline)]
pub use self::struct_fields_decoder::StructFieldsDecoder;

mod size_hint;
#[doc(inline)]
pub use self::size_hint::SizeHint;

mod value_visitor;
#[doc(inline)]
pub use self::value_visitor::ValueVisitor;

mod variant_decoder;
#[doc(inline)]
pub use self::variant_decoder::VariantDecoder;

mod visitor;
#[doc(inline)]
pub use self::visitor::Visitor;

use crate::mode::DefaultMode;
Expand Down
12 changes: 12 additions & 0 deletions crates/musli/src/en/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,37 +17,49 @@
//! ```

mod encode;
#[doc(inline)]
pub use self::encode::{Encode, TraceEncode};

mod encode_bytes;
#[doc(inline)]
pub use self::encode_bytes::EncodeBytes;

mod encoder;
#[doc(inline)]
pub use self::encoder::Encoder;

mod sequence_encoder;
#[doc(inline)]
pub use self::sequence_encoder::SequenceEncoder;

mod tuple_encoder;
#[doc(inline)]
pub use self::tuple_encoder::TupleEncoder;

mod pack_encoder;
#[doc(inline)]
pub use self::pack_encoder::PackEncoder;

mod map_encoder;
#[doc(inline)]
pub use self::map_encoder::MapEncoder;

mod map_entry_encoder;
#[doc(inline)]
pub use self::map_entry_encoder::MapEntryEncoder;

mod map_entries_encoder;
#[doc(inline)]
pub use self::map_entries_encoder::MapEntriesEncoder;

mod struct_encoder;
#[doc(inline)]
pub use self::struct_encoder::StructEncoder;

mod struct_field_encoder;
#[doc(inline)]
pub use self::struct_field_encoder::StructFieldEncoder;

mod variant_encoder;
#[doc(inline)]
pub use self::variant_encoder::VariantEncoder;
123 changes: 123 additions & 0 deletions crates/musli/src/fixed.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
use core::fmt;
use core::mem::{self, ManuallyDrop, MaybeUninit};
use core::ops::{Deref, DerefMut};
use core::ptr;
use core::slice;

/// An error raised when we are at capacity.
#[derive(Debug)]
#[non_exhaustive]
pub(crate) struct CapacityError;

impl fmt::Display for CapacityError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Out of capacity when constructing array")
}
}

#[cfg(feature = "std")]
impl std::error::Error for CapacityError {}

/// A fixed capacity vector allocated on the stack.
pub(crate) struct FixedVec<T, const N: usize> {
data: [MaybeUninit<T>; N],
len: usize,
}

impl<T, const N: usize> FixedVec<T, N> {
/// Construct a new empty fixed vector.
pub(crate) const fn new() -> FixedVec<T, N> {
unsafe {
FixedVec {
data: MaybeUninit::uninit().assume_init(),
len: 0,
}
}
}

#[inline]
pub(crate) fn as_ptr(&self) -> *const T {
self.data.as_ptr() as *const T
}

#[inline]
pub(crate) fn as_mut_ptr(&mut self) -> *mut T {
self.data.as_mut_ptr() as *mut T
}

#[inline]
pub(crate) fn as_slice(&self) -> &[T] {
unsafe { slice::from_raw_parts(self.as_ptr(), self.len) }
}

#[inline]
pub(crate) fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
}

/// Try to push an element onto the fixed vector.
pub(crate) fn try_push(&mut self, element: T) -> Result<(), CapacityError> {
if self.len >= N {
return Err(CapacityError);
}

unsafe {
ptr::write(self.as_mut_ptr().wrapping_add(self.len), element);
self.len += 1;
}

Ok(())
}

pub(crate) fn clear(&mut self) {
if self.len == 0 {
return;
}

let len = mem::take(&mut self.len);

if mem::needs_drop::<T>() {
unsafe {
let tail = slice::from_raw_parts_mut(self.as_mut_ptr(), len);
ptr::drop_in_place(tail);
}
}
}

pub(crate) fn into_inner(self) -> [T; N] {
assert!(
self.len == N,
"into_inner: length mismatch, expected {N} but got {}",
self.len
);

// SAFETY: We've asserted that the length is initialized just above.
unsafe {
let this = ManuallyDrop::new(self);
ptr::read(this.data.as_ptr() as *const [T; N])
}
}
}

impl<T, const N: usize> Deref for FixedVec<T, N> {
type Target = [T];

#[inline]
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}

impl<T, const N: usize> DerefMut for FixedVec<T, N> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_mut_slice()
}
}

impl<T, const N: usize> Drop for FixedVec<T, N> {
#[inline]
fn drop(&mut self) {
self.clear()
}
}
34 changes: 29 additions & 5 deletions crates/musli/src/impls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ use core::num::{
use core::{fmt, marker};

use crate::de::{
Decode, DecodeBytes, DecodeUnsized, DecodeUnsizedBytes, Decoder, ValueVisitor, VariantDecoder,
Decode, DecodeBytes, DecodeUnsized, DecodeUnsizedBytes, Decoder, SequenceDecoder, ValueVisitor,
VariantDecoder,
};
use crate::en::{Encode, EncodeBytes, Encoder, SequenceEncoder, VariantEncoder};
use crate::hint::SequenceHint;
Expand Down Expand Up @@ -176,13 +177,36 @@ where
}
}

impl<'de, M, const N: usize> Decode<'de, M> for [u8; N] {
impl<'de, M, T, const N: usize> Decode<'de, M> for [T; N]
where
T: Decode<'de, M>,
{
#[inline]
fn decode<D>(_: &D::Cx, decoder: D) -> Result<Self, D::Error>
fn decode<D>(cx: &D::Cx, decoder: D) -> Result<Self, D::Error>
where
D: Decoder<'de>,
D: Decoder<'de, Mode = M>,
{
decoder.decode_array()
let mark = cx.mark();

decoder.decode_sequence(|seq| {
let mut array = crate::fixed::FixedVec::new();

while let Some(item) = seq.decode_next()? {
array.try_push(item.decode()?).map_err(cx.map())?;
}

if array.len() != N {
return Err(cx.marked_message(
mark,
format_args!(
"Array with length {} does not have the expected {N} number of elements",
array.len()
),
));
}

Ok(array.into_inner())
})
}
}

Expand Down
1 change: 1 addition & 0 deletions crates/musli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ pub mod de;
pub mod derives;
pub mod en;
mod expecting;
mod fixed;
pub mod hint;
mod impls;
mod internal;
Expand Down
Loading

0 comments on commit 6de87b0

Please sign in to comment.