Trait starlark::values::ComplexValue
source · pub trait ComplexValue<'v>: StarlarkValue<'v> + Trace<'v> + Freeze{ }
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 allocative::Allocative;
use derive_more::Display;
use starlark::starlark_complex_value;
use starlark::values::Coerce;
use starlark::values::ComplexValue;
use starlark::values::Freeze;
use starlark::values::Freezer;
use starlark::values::FrozenValue;
use starlark::values::NoSerialize;
use starlark::values::ProvidesStaticType;
use starlark::values::StarlarkValue;
use starlark::values::Trace;
use starlark::values::Tracer;
use starlark::values::Value;
use starlark::values::ValueLike;
use starlark_derive::starlark_value;
#[derive(
Debug,
Trace,
Coerce,
Display,
ProvidesStaticType,
NoSerialize,
Allocative
)]
#[repr(C)]
struct OneGen<V>(V);
starlark_complex_value!(One);
#[starlark_value(type = "one")]
impl<'v, V: ValueLike<'v> + 'v> StarlarkValue<'v> for OneGen<V>
where
Self: ProvidesStaticType<'v>,
{
// To implement methods which work for both `One` and `FrozenOne`,
// use the `ValueLike` trait.
}
impl<'v> Freeze 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 ProvidesStaticType
for both,
AllocValue
for both,
AllocFrozenValue
for the frozen one, and
UnpackValue
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<&'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: