Skip to content

Commit

Permalink
Rework how an allocator is associated with a context (#160)
Browse files Browse the repository at this point in the history
  • Loading branch information
udoprog authored Jun 9, 2024
1 parent e58035a commit e3a63b4
Show file tree
Hide file tree
Showing 61 changed files with 509 additions and 543 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::buf::Buf;
use super::Buf;

/// An allocator that can be used in combination with a context.
pub trait Allocator {
/// The type of an allocated buffer.
type Buf<'this, T>: Buf<Item = T>
type Buf<'this, T>: Buf<T>
where
Self: 'this,
T: 'this;
Expand Down
53 changes: 53 additions & 0 deletions crates/musli-core/src/alloc/buf.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/// A raw buffer allocated through an [`Allocator`].
///
/// [`Allocator`]: super::Allocator
///
/// ## Examples
///
/// ```
/// use musli::alloc::{Allocator, Buf, Vec};
///
/// let values: [u32; 4] = [1, 2, 3, 4];
///
/// musli::alloc::default!(|alloc| {
/// let mut buf = alloc.alloc::<u32>();
/// let mut len = 0;
///
/// for value in values {
/// if !buf.resize(len, 1) {
/// panic!("Allocation failed");
/// }
///
/// // SAFETY: We've just resized the above buffer.
/// unsafe {
/// buf.as_mut_ptr().add(len).write(value);
/// }
///
/// len += 1;
/// }
///
/// // SAFETY: Slice does not outlive the buffer it references.
/// let bytes = unsafe { core::slice::from_raw_parts(buf.as_ptr(), len) };
/// assert_eq!(bytes, values);
/// });
/// ```
pub trait Buf<T> {
/// Resize the buffer.
fn resize(&mut self, len: usize, additional: usize) -> bool;

/// Get a pointer into the buffer.
fn as_ptr(&self) -> *const T;

/// Get a mutable pointer into the buffer.
fn as_mut_ptr(&mut self) -> *mut T;

/// Try to merge one buffer with another.
///
/// The two length parameters refers to the initialized length of the two
/// buffers.
///
/// If this returns `Err(B)` if merging was not possible.
fn try_merge<B>(&mut self, this_len: usize, other: B, other_len: usize) -> Result<(), B>
where
B: Buf<T>;
}
9 changes: 9 additions & 0 deletions crates/musli-core/src/alloc/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//! Traits related to memory allocation.

mod allocator;
#[doc(inline)]
pub use self::allocator::Allocator;

mod buf;
#[doc(inline)]
pub use self::buf::Buf;
43 changes: 0 additions & 43 deletions crates/musli-core/src/buf.rs

This file was deleted.

25 changes: 9 additions & 16 deletions crates/musli-core/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
use core::fmt;
use core::str;

use crate::alloc::Allocator;
use crate::de::{DecodeBytes, DecodeUnsized, DecodeUnsizedBytes};
use crate::no_std;
use crate::{Buf, Decode, Decoder};
use crate::{Decode, Decoder};

/// Provides ergonomic access to the serialization context.
///
Expand All @@ -17,13 +18,10 @@ pub trait Context {
type Error: 'static;
/// A mark during processing.
type Mark: Copy + Default;
/// A growable buffer.
type Buf<'this, T>: Buf<Item = T>
where
Self: 'this,
T: 'this;
/// The allocator associated with the context.
type Allocator: ?Sized + Allocator;
/// An allocated buffer containing a valid string.
type BufString<'this>: AsRef<str>
type String<'this>: AsRef<str>
where
Self: 'this;

Expand Down Expand Up @@ -71,18 +69,13 @@ pub trait Context {
T::decode_unsized_bytes(self, decoder, f)
}

/// Allocate a bytes buffer.
///
/// Returns `None` if the underlying allocator cannot allocate memory for
/// some reason, typically this indicates that we've run out of memory.
///
/// The buffer will be deallocated once the returned handle is dropped.
fn alloc<T>(&self) -> Self::Buf<'_, T>;
/// Access the underlying allocator.
fn alloc(&self) -> &Self::Allocator;

/// Collect and allocate a string from a [`Display`] implementation.
///
/// [`Display`]: fmt::Display
fn collect_string<T>(&self, value: &T) -> Result<Self::BufString<'_>, Self::Error>
fn collect_string<T>(&self, value: &T) -> Result<Self::String<'_>, Self::Error>
where
T: ?Sized + fmt::Display;

Expand Down Expand Up @@ -219,7 +212,7 @@ pub trait Context {

/// Encountered an unsupported field tag.
#[inline(always)]
fn invalid_field_string_tag(&self, _: &'static str, field: Self::BufString<'_>) -> Self::Error {
fn invalid_field_string_tag(&self, _: &'static str, field: Self::String<'_>) -> Self::Error {
let field = field.as_ref();
self.message(format_args!("Invalid field tag `{field}`"))
}
Expand Down
20 changes: 10 additions & 10 deletions crates/musli-core/src/impls/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ use core::fmt;
#[cfg(feature = "std")]
use core::hash::{BuildHasher, Hash};

use alloc::borrow::{Cow, ToOwned};
use alloc::boxed::Box;
use alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, VecDeque};
use alloc::ffi::CString;
use alloc::rc::Rc;
use alloc::string::String;
use alloc::sync::Arc;
use alloc::vec::Vec;
use rust_alloc::borrow::{Cow, ToOwned};
use rust_alloc::boxed::Box;
use rust_alloc::collections::{BTreeMap, BTreeSet, BinaryHeap, VecDeque};
use rust_alloc::ffi::CString;
use rust_alloc::rc::Rc;
use rust_alloc::string::String;
use rust_alloc::sync::Arc;
use rust_alloc::vec::Vec;

#[cfg(feature = "std")]
use std::collections::{HashMap, HashSet};
Expand Down Expand Up @@ -618,11 +618,11 @@ where
{
use std::os::windows::ffi::OsStrExt;

use crate::alloc::{Allocator, Buf};
use crate::en::VariantEncoder;
use crate::Buf;

encoder.encode_variant_fn(|variant| {
let mut buf = cx.alloc::<u8>();
let mut buf = cx.alloc().alloc::<u8>();
let mut len = 0;

for w in self.encode_wide() {
Expand Down
8 changes: 3 additions & 5 deletions crates/musli-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,17 @@
#![cfg_attr(doc_cfg, feature(doc_cfg))]

#[cfg(feature = "alloc")]
extern crate alloc;
extern crate alloc as rust_alloc;

#[cfg(feature = "std")]
extern crate std;

pub mod alloc;

mod context;
#[doc(inline)]
pub use self::context::Context;

pub mod buf;
#[doc(inline)]
pub use self::buf::Buf;

pub mod de;
#[doc(inline)]
pub use self::de::{Decode, Decoder};
Expand Down
16 changes: 6 additions & 10 deletions crates/musli-core/src/never.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ use core::marker;

use crate::no_std::ToOwned;

use crate::alloc::Buf;
use crate::de::{
AsDecoder, Decode, DecodeUnsized, DecodeUnsizedBytes, Decoder, EntriesDecoder, EntryDecoder,
MapDecoder, SequenceDecoder, SizeHint, UnsizedVisitor, VariantDecoder,
};
use crate::en::{
Encode, Encoder, EntriesEncoder, EntryEncoder, MapEncoder, SequenceEncoder, VariantEncoder,
};
use crate::{Buf, Context};
use crate::Context;

/// Marker type used for the [`Never`] type.
#[doc(hidden)]
Expand Down Expand Up @@ -67,31 +68,26 @@ pub struct Never<A = NeverMarker, B: ?Sized = NeverMarker> {
_marker: marker::PhantomData<(A, B)>,
}

impl<T> Buf for Never<T>
where
T: 'static,
{
type Item = T;

impl<T> Buf<T> for Never<T> {
#[inline]
fn resize(&mut self, _: usize, _: usize) -> bool {
match self._never {}
}

#[inline]
fn as_ptr(&self) -> *const Self::Item {
fn as_ptr(&self) -> *const T {
match self._never {}
}

#[inline]
fn as_mut_ptr(&mut self) -> *mut Self::Item {
fn as_mut_ptr(&mut self) -> *mut T {
match self._never {}
}

#[inline]
fn try_merge<B>(&mut self, _: usize, _: B, _: usize) -> Result<(), B>
where
B: Buf<Item = Self::Item>,
B: Buf<T>,
{
match self._never {}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/musli-core/src/no_std.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
use core::fmt;

#[cfg(feature = "alloc")]
pub use alloc::borrow::ToOwned;
pub use rust_alloc::borrow::ToOwned;

#[cfg(not(feature = "alloc"))]
pub use self::to_owned::ToOwned;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,33 @@
use core::marker::PhantomData;
use core::ptr;

use crate::{Allocator, Buf};
use super::{Allocator, Buf};

/// An empty buffer.
pub struct EmptyBuf<T> {
_marker: PhantomData<T>,
}

impl<T> Buf for EmptyBuf<T> {
type Item = T;

impl<T> Buf<T> for EmptyBuf<T> {
#[inline]
fn resize(&mut self, _: usize, _: usize) -> bool {
false
}

#[inline]
fn as_ptr(&self) -> *const Self::Item {
fn as_ptr(&self) -> *const T {
ptr::NonNull::dangling().as_ptr()
}

#[inline]
fn as_mut_ptr(&mut self) -> *mut Self::Item {
fn as_mut_ptr(&mut self) -> *mut T {
ptr::NonNull::dangling().as_ptr()
}

#[inline]
fn try_merge<B>(&mut self, _: usize, other: B, _: usize) -> Result<(), B>
where
B: Buf<Item = Self::Item>,
B: Buf<T>,
{
Err(other)
}
Expand Down
Loading

0 comments on commit e3a63b4

Please sign in to comment.