[][src]Struct evobox::EvolveBox

pub struct EvolveBox<S: List<P>, P = ()> { /* fields omitted */ }

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);

Methods

impl<S: List<()>> EvolveBox<S, ()>[src]

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

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);

impl<S: List<P>, P> EvolveBox<S, P>[src]

pub fn into_inner(self) -> S::Value[src]

Consumes this pointer, returning the current value.

Examples

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

impl<S: List<P>, P> EvolveBox<S, P>[src]

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>>, 
[src]

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");

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>>, 
[src]

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

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

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

impl<S: List<P>, P> Drop for EvolveBox<S, P>[src]

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

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

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

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

impl<S: List<P>, P> Deref for EvolveBox<S, P>[src]

type Target = S::Value

The resulting type after dereferencing.

impl<S: List<P>, P> DerefMut for EvolveBox<S, P>[src]

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

Auto Trait Implementations

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

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

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

Blanket Implementations

impl<T, U> Into<U> for T where
    U: From<T>, 
[src]

impl<T> From<T> for T[src]

impl<T, U> TryFrom<U> for T where
    U: Into<T>, 
[src]

type Error = !

The type returned in the event of a conversion error.

impl<T, U> TryInto<U> for T where
    U: TryFrom<T>, 
[src]

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

The type returned in the event of a conversion error.

impl<T> Borrow<T> for T where
    T: ?Sized
[src]

impl<T> BorrowMut<T> for T where
    T: ?Sized
[src]

impl<T> Any for T where
    T: 'static + ?Sized
[src]