Trait starlark::values::ComplexValue[][src]

pub trait ComplexValue<'v>: StarlarkValue<'v> + Trace<'v> {
    type Frozen: SimpleValue;
    fn freeze(self, freezer: &Freezer) -> Result<Self::Frozen>;
}
Expand description

A trait for values which are more complex - because they are either mutable, or contain references to other values.

For values that contain nested Value types (mutable or not) there are a bunch of helpers and macros.

Types containing Value

A Starlark type containing values will need to exist in two states: one containing Value and one containing FrozenValue. To deal with that, if we are defining the type containing a single value, let’s call it One, we’d define OneGen (for the general version), and then have the starlark_complex_value! macro generate One and FrozenOne aliases.

use starlark::values::{AnyLifetime, ComplexValue, Coerce, Freezer, FrozenValue, SimpleValue, StarlarkValue, Value, ValueLike, Trace, Tracer};
use starlark::{starlark_complex_value, starlark_type};

#[derive(Debug, Trace, Coerce)]
#[repr(C)]
struct OneGen<V>(V);
starlark_complex_value!(One);

impl<'v, V: ValueLike<'v>> StarlarkValue<'v> for OneGen<V>
    where Self: AnyLifetime<'v>
{
    starlark_type!("one");

    // To implement methods which are work for both `One` and `FrozenOne`,
    // use the `ValueLike` trait.
}

impl<'v> ComplexValue<'v> for One<'v> {
    type Frozen = FrozenOne;
    fn freeze(self, freezer: &Freezer) -> anyhow::Result<Self::Frozen> {
        Ok(OneGen(self.0.freeze(freezer)?))
    }
}

The starlark_complex_value! requires that the type have an instance for Coerce, then the macro defines two type aliases.

type One<'v> = OneGen<Value<'v>>;
type FrozenOne = OneGen<FrozenValue>;

To make these aliases public (or public to the crate) pass a visibility to the macro, e.g. starlark_complex_value!(pub One).

The macro also defines instances of AnyLifetime for both, AllocValue for both, AllocFrozenValue for the frozen one, SimpleValue for the frozen one and FromValue for the non-frozen one. It also defines the methods:

impl<'v> One<'v> {
    // Obtain a reference to `One` from a `Value`, regardless
    // of whether the underlying `Value` is a `One` or `FrozenOne`.
    pub fn from_value(x: Value<'v>) -> Option<ARef<'v, Self>> {
        ...
    }
}

Different types

If the types are different between the frozen and non-frozen values you can define your own type specialisations as type One<'v> = OneGen<Value<'v>> and type FrozenOne = OneGen<String> and use starlark_complex_values! which will provide similar facilities to starlark_complex_value!.

Other types

The macro starlark_complex_value! is applicable when there is a single base type, FooGen<V>, with specialisations FooGen<Value<'v>> and FooGen<FrozenValue>. If you have a type where the difference between frozen and non-frozen does not follow this pattern then you will have to write instances of the traits you need manually. Examples of cases where the macro doesn’t work include:

  • If your type doesn’t contain any Value types, but instead implements this trait for mutability.
  • If the difference between frozen and non-frozen is more complex, e.g. a Cell when non-frozen and a direct value when frozen.

Associated Types

Required methods

Freeze a value. The frozen value must be equal to the original, and produce the same hash.

Implementors