Struct EvolveBox

Source
pub struct EvolveBox<S: List<P>, P = ()> { /* private fields */ }
Expand description

A pointer type which allows for safe transformations of its content without reallocation.

An EvolveBox has the same size as a Box and has the smallest size and alignment on the heap needed to store its largest possible variant.

Therefore EvolveBox should be a zero cost abstraction, meaning that there should be no runtime difference between a Box pointing at an untagged union and an EvolveBox, while using an EvolveBox is also safe.

The size and alignment of the allocated memory is stored in the type S, which is a list of all used types,
as it is required for deallocation.

§Examples

Using EvolveBox inside of a function.

use evobox::{EvolveBox, L};

let s: EvolveBox<L<&str, L<String, L<u32>>>> = EvolveBox::new("7");
let owned = s.evolve(|v| v.to_string());
assert_eq!(owned.as_str(), "7");

let seven = owned.try_evolve(|s| s.parse()).expect("invalid integer");
assert_eq!(*seven, 7);

Storing it in a generic struct.

use evobox::{EvolveBox, List, L};

enum Ty {
    Integer,
    String,
    Boolean,
}

#[derive(Debug)]
struct TypeError;

struct Variable<'a, N, T>
where
    L<&'a str, L<usize>>: List<N>,
    L<&'a str, L<Ty>>: List<T>,
{
    name: EvolveBox<L<&'a str, L<usize>>, N>,
    ty: EvolveBox<L<&'a str, L<Ty>>, T>,
}

impl<'a> Variable<'a, (), ()> {
    fn new(name: &'a str, ty: &'a str) -> Self {
        Self {
            name: EvolveBox::new(name),
            ty: EvolveBox::new(ty),
        }
    }
}

impl<'a, T> Variable<'a, (), T>
where
    L<&'a str, L<Ty>>: List<T>,
{
    fn resolve_names(self, names: &mut Vec<&'a str>) -> Variable<'a, L<()>, T> {
        let id = names.len();
        let name = self.name.evolve(|name| {
            names.push(name);
            id
        });

        Variable { name, ty: self.ty }
    }
}

impl<'a, N> Variable<'a, N, ()>
where
    L<&'a str, L<usize>>: List<N>,
{
    fn resolve_types(self) -> Result<Variable<'a, N, L<()>>, TypeError> {
        let ty = self.ty.try_evolve(|ty|
            match ty {
                "int" => Ok(Ty::Integer),
                "string" => Ok(Ty::String),
                "bool" => Ok(Ty::Boolean),
                _ => Err(TypeError)
            }
        )?;

        Ok(Variable { name: self.name, ty })
    }
}

let a = Variable::new("a", "int");
let b = Variable::new("b", "string");

let mut names = Vec::new();
let a = a.resolve_names(&mut names);
let _ = a.resolve_types().expect("unknown type");
let b = b.resolve_types().expect("unknown type");
let _ = b.resolve_names(&mut names);

Implementations§

Source§

impl<S: List<()>> EvolveBox<S, ()>

Source

pub fn new(x: S::Value) -> Self

Allocates memory on the heap and then places x into it. This does not actually allocate if all types used in S are zero-sized.

§Examples
let value = EvolveBox::<L<_>>::new(7);

assert_eq!(*value, 7);
Source§

impl<S: List<P>, P> EvolveBox<S, P>

Source

pub fn into_inner(self) -> S::Value

Consumes this pointer, returning the current value.

§Examples
let evolve_box = EvolveBox::<L<_>>::new("hi");
assert_eq!("hi", evolve_box.into_inner());
Source§

impl<S: List<P>, P> EvolveBox<S, P>

Source

pub fn evolve<F>(self, f: F) -> EvolveBox<S, L<P>>
where F: FnOnce(<S as List<P>>::Value) -> <S as List<L<P>>>::Value, S: List<L<P>>,

Converts the current value to the next one without requiring a new allocation.

§Examples

let int_box: EvolveBox<L<u32, L<String>>> = EvolveBox::new(7);
let str_box = int_box.evolve(|i| format!("{}", i));
assert_eq!(str_box.as_str(), "7");
Source

pub fn try_evolve<F, E>(self, f: F) -> Result<EvolveBox<S, L<P>>, E>
where F: FnOnce(<S as List<P>>::Value) -> Result<<S as List<L<P>>>::Value, E>, S: List<L<P>>,

Tries to convert the current value to the next one without requiring a new allocation. The error is propagated outwards in case the conversion fails.

§Examples
use std::convert::TryFrom;

let origin: EvolveBox<L<u32, L<u16, L<u8>>>> = EvolveBox::new(256);

let success = origin.try_evolve(u16::try_from).unwrap();
assert_eq!(*success, 256);

let error = success.try_evolve(u8::try_from);
assert!(error.is_err());

Trait Implementations§

Source§

impl<S: List<P>, P> AsMut<<S as List<P>>::Value> for EvolveBox<S, P>

Source§

fn as_mut(&mut self) -> &mut S::Value

Converts this type into a mutable reference of the (usually inferred) input type.
Source§

impl<S: List<P>, P> AsRef<<S as List<P>>::Value> for EvolveBox<S, P>

Source§

fn as_ref(&self) -> &S::Value

Converts this type into a shared reference of the (usually inferred) input type.
Source§

impl<S: List<P>, P> Debug for EvolveBox<S, P>
where S::Value: Debug,

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<S: List<P>, P> Deref for EvolveBox<S, P>

Source§

type Target = <S as List<P>>::Value

The resulting type after dereferencing.
Source§

fn deref(&self) -> &S::Value

Dereferences the value.
Source§

impl<S: List<P>, P> DerefMut for EvolveBox<S, P>

Source§

fn deref_mut(&mut self) -> &mut S::Value

Mutably dereferences the value.
Source§

impl<S: List<P>, P> Drop for EvolveBox<S, P>

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

impl<S1: List<P1>, P1, S2: List<P2>, P2> PartialEq<EvolveBox<S2, P2>> for EvolveBox<S1, P1>
where S1::Value: PartialEq<S2::Value>,

Source§

fn eq(&self, other: &EvolveBox<S2, P2>) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl<S: List<P>, P> Eq for EvolveBox<S, P>
where S::Value: Eq,

Source§

impl<S: List<P>, P> Send for EvolveBox<S, P>
where S::Value: Send,

Source§

impl<S: List<P>, P> Sync for EvolveBox<S, P>
where S::Value: Sync,

Auto Trait Implementations§

§

impl<S, P> Freeze for EvolveBox<S, P>

§

impl<S, P> RefUnwindSafe for EvolveBox<S, P>
where <S as List<P>>::Value: RefUnwindSafe,

§

impl<S, P> Unpin for EvolveBox<S, P>

§

impl<S, P> UnwindSafe for EvolveBox<S, P>
where <S as List<P>>::Value: RefUnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.