Skip to content

Commit

Permalink
Clean up documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog committed Mar 21, 2024
1 parent 7185b7c commit 0114f3c
Show file tree
Hide file tree
Showing 60 changed files with 487 additions and 379 deletions.
3 changes: 2 additions & 1 deletion crates/musli-allocator/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@
//! [Müsli]: <https://docs.rs/musli>
//! [`std::alloc::System`]: https://doc.rust-lang.org/std/alloc/struct.System.html

#![allow(clippy::type_complexity)]
#![deny(missing_docs)]
#![no_std]
#![cfg_attr(doc_cfg, feature(doc_cfg))]

#[cfg_attr(test, macro_use)]
#[cfg(feature = "std")]
Expand All @@ -62,6 +62,7 @@ mod tests;
#[cfg(feature = "alloc")]
mod system;
#[cfg(feature = "alloc")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
pub use self::system::{System, SystemBuffer};

mod disabled;
Expand Down
2 changes: 0 additions & 2 deletions crates/musli-common/src/buf/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
//! Utilitioes for working with buffers.

mod buf_string;
pub use self::buf_string::BufString;
2 changes: 1 addition & 1 deletion crates/musli-common/src/buffered_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

use musli::{Buf, Context};

use crate::fixed_bytes::FixedBytes;
use crate::fixed::FixedBytes;
use crate::writer::Writer;

/// A writer which buffers `N` bytes inline.
Expand Down
2 changes: 0 additions & 2 deletions crates/musli-common/src/context/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
//! Helper types to set up a basic Müsli [`Context`].

mod access;
mod error_marker;
mod rich_error;
Expand Down
4 changes: 3 additions & 1 deletion crates/musli-common/src/context/stack_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use super::access::{Access, Shared};
use super::rich_error::{RichError, Step};
use super::ErrorMarker;

type BufPair<'a, A> = (Range<usize>, BufString<<A as Allocator>::Buf<'a>>);

/// A rich context which uses allocations and tracks the exact location of every
/// error.
///
Expand All @@ -28,7 +30,7 @@ where
access: Access,
mark: Cell<usize>,
alloc: &'a A,
error: UnsafeCell<Option<(Range<usize>, BufString<A::Buf<'a>>)>>,
error: UnsafeCell<Option<BufPair<'a, A>>>,
path: UnsafeCell<FixedVec<Step<BufString<A::Buf<'a>>>, P>>,
path_cap: Cell<usize>,
include_type: bool,
Expand Down
6 changes: 4 additions & 2 deletions crates/musli-common/src/context/system_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,14 @@ use super::access::{self, Access};
use super::rich_error::{RichError, Step};
use super::ErrorMarker;

type BufTriplet<E> = (Vec<Step<String>>, Range<usize>, E);

/// A rich context dynamically allocating space using the system allocator.
pub struct SystemContext<A, M> {
access: Access,
mark: Cell<usize>,
alloc: A,
errors: UnsafeCell<Vec<(Vec<Step<String>>, Range<usize>, String)>>,
errors: UnsafeCell<Vec<BufTriplet<String>>>,
path: UnsafeCell<Vec<Step<String>>>,
include_type: bool,
_marker: PhantomData<M>,
Expand Down Expand Up @@ -238,7 +240,7 @@ where

/// An iterator over collected errors.
pub struct Errors<'a, E> {
errors: &'a [(Vec<Step<String>>, Range<usize>, E)],
errors: &'a [BufTriplet<E>],
index: usize,
// NB: Drop order is significant, drop the shared access last.
_access: access::Shared<'a>,
Expand Down
210 changes: 205 additions & 5 deletions crates/musli-common/src/fixed.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,219 @@
//! Fixed capacity containers.

// Parts borrowed under the MIT license from
// https://github.com/bluss/arrayvec/tree/2c92a59bed0d1669cede3806000d2e61d5994c4e

use core::fmt;
use core::mem::{self, MaybeUninit};
use core::ops::{Deref, DerefMut};
use core::ptr;
use core::slice;

use musli::{Buf, Context};

use crate::writer::Writer;

/// A fixed-size bytes storage which keeps track of how much has been initialized.
pub struct FixedBytes<const N: usize> {
/// Data storage.
data: [MaybeUninit<u8>; N],
/// How many bytes have been initialized.
init: usize,
}

impl<const N: usize> FixedBytes<N> {
/// Construct a new fixed bytes array storage.
#[inline]
pub const fn new() -> Self {
Self {
// SAFETY: MaybeUnint::uninit_array is not stable.
data: unsafe { MaybeUninit::<[MaybeUninit<u8>; N]>::uninit().assume_init() },
init: 0,
}
}

/// Get the length of the collection.
#[inline]
pub const fn len(&self) -> usize {
self.init
}

/// Test if the current container is empty.
#[inline]
pub const fn is_empty(&self) -> bool {
self.init == 0
}

/// Clear the [FixedBytes] container.
#[inline]
pub fn clear(&mut self) {
self.init = 0;
}

/// Get the remaining capacity of the [FixedBytes].
#[inline]
pub const fn remaining(&self) -> usize {
N.saturating_sub(self.init)
}

/// Coerce into the underlying bytes if all of them have been initialized.
#[inline]
pub fn into_bytes(self) -> Option<[u8; N]> {
if self.init == N {
// SAFETY: All of the bytes in the sequence have been initialized
// and can be safety transmuted.
//
// Method of transmuting comes from the implementation of
// `MaybeUninit::array_assume_init` which is not yet stable.
unsafe { Some((&self.data as *const _ as *const [u8; N]).read()) }
} else {
None
}
}

/// Coerce into the slice of initialized memory which is present.
#[inline]
pub fn as_slice(&self) -> &[u8] {
if self.init == 0 {
return &[];
}

// SAFETY: We've asserted that `initialized` accounts for the number of
// bytes that have been initialized.
unsafe { core::slice::from_raw_parts(self.data.as_ptr().cast(), self.init) }
}

/// Coerce into the mutable slice of initialized memory which is present.
#[inline]
pub fn as_mut_slice(&mut self) -> &[u8] {
if self.init == 0 {
return &[];
}

// SAFETY: We've asserted that `initialized` accounts for the number of
// bytes that have been initialized.
unsafe { core::slice::from_raw_parts_mut(self.data.as_mut_ptr().cast(), self.init) }
}

/// Try and push a single byte.
#[inline]
pub fn push(&mut self, value: u8) -> bool {
if N.saturating_sub(self.init) == 0 {
return false;
}

unsafe {
self.data
.as_mut_ptr()
.cast::<u8>()
.add(self.init)
.write(value)
}

self.init += 1;
true
}

/// Try and extend from the given slice.
#[inline]
pub fn extend_from_slice(&mut self, source: &[u8]) -> bool {
if source.len() > N.saturating_sub(self.init) {
return false;
}

unsafe {
let dst = (self.data.as_mut_ptr() as *mut u8).add(self.init);
ptr::copy_nonoverlapping(source.as_ptr(), dst, source.len());
}

self.init = self.init.wrapping_add(source.len());
true
}

/// Try and extend from the given slice.
#[inline]
pub fn write_bytes<C>(&mut self, cx: &C, source: &[u8]) -> Result<(), C::Error>
where
C: ?Sized + Context,
{
if !self.extend_from_slice(source) {
return Err(cx.message(FixedBytesOverflow {
at: self.init,
additional: source.len(),
capacity: N,
}));
}

Ok(())
}
}

impl<const N: usize> Default for FixedBytes<N> {
#[inline]
fn default() -> Self {
Self::new()
}
}

impl<const N: usize> Writer for FixedBytes<N> {
type Mut<'this> = &'this mut Self where Self: 'this;

#[inline]
fn borrow_mut(&mut self) -> Self::Mut<'_> {
self
}

#[inline]
fn write_buffer<C, B>(&mut self, cx: &C, buffer: B) -> Result<(), C::Error>
where
C: ?Sized + Context,
B: Buf,
{
// SAFETY: the buffer never outlives this function call.
self.write_bytes(cx, buffer.as_slice())
}

#[inline]
fn write_bytes<C>(&mut self, cx: &C, bytes: &[u8]) -> Result<(), C::Error>
where
C: ?Sized + Context,
{
FixedBytes::write_bytes(self, cx, bytes)?;
cx.advance(bytes.len());
Ok(())
}
}

/// Capacity error raised by trying to write to a [FixedBytes] with no remaining
/// capacity.
#[derive(Debug)]
#[allow(missing_docs)]
#[non_exhaustive]
pub(crate) struct FixedBytesOverflow {
at: usize,
additional: usize,
capacity: usize,
}

impl fmt::Display for FixedBytesOverflow {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let FixedBytesOverflow {
at,
additional,
capacity,
} = self;

write!(
f,
"Tried to write {additional} bytes at {at} with capacity {capacity}"
)
}
}

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

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

0 comments on commit 0114f3c

Please sign in to comment.