[−][src]Struct evobox::EvolveBox
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]
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");
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]
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
impl<S: List<P>, P> Send for EvolveBox<S, P> where
S::Value: Send,
[src]
S::Value: Send,
impl<S: List<P>, P> Sync for EvolveBox<S, P> where
S::Value: Sync,
[src]
S::Value: Sync,
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]
S::Value: Eq,
impl<S1: List<P1>, P1, S2: List<P2>, P2> PartialEq<EvolveBox<S2, P2>> for EvolveBox<S1, P1> where
S1::Value: PartialEq<S2::Value>,
[src]
S1::Value: PartialEq<S2::Value>,
fn eq(&self, other: &EvolveBox<S2, P2>) -> bool
[src]
#[must_use]
fn ne(&self, other: &Rhs) -> bool
1.0.0[src]
impl<S: List<P>, P> Deref for EvolveBox<S, P>
[src]
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]
S::Value: Debug,
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,
<S as List<P>>::Value: RefUnwindSafe,
impl<S, P> RefUnwindSafe for EvolveBox<S, P> where
<S as List<P>>::Value: RefUnwindSafe,
<S as List<P>>::Value: RefUnwindSafe,
Blanket Implementations
impl<T, U> Into<U> for T where
U: From<T>,
[src]
U: From<T>,
impl<T> From<T> for T
[src]
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]
U: Into<T>,
type Error = !
The type returned in the event of a conversion error.
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]
impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]
U: TryFrom<T>,
type Error = <U as TryFrom<T>>::Error
The type returned in the event of a conversion error.
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>
[src]
impl<T> Borrow<T> for T where
T: ?Sized,
[src]
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]
T: ?Sized,
fn borrow_mut(&mut self) -> &mut T
[src]
impl<T> Any for T where
T: 'static + ?Sized,
[src]
T: 'static + ?Sized,