starlark/macros.rs
1/*
2 * Copyright 2019 The Starlark in Rust Authors.
3 * Copyright (c) Facebook, Inc. and its affiliates.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18/// Reduce boilerplate when making types instances of [`ComplexValue`](crate::values::ComplexValue)
19/// - see the [`ComplexValue`](crate::values::ComplexValue) docs for an example.
20#[macro_export]
21macro_rules! starlark_complex_value {
22 // Common part of macro variants.
23 (impl $x:ident) => {
24 $crate::__macro_refs::item! {
25 impl<'v> $crate::values::AllocValue<'v> for $x<'v> {
26 #[inline]
27 fn alloc_value(self, heap: &'v $crate::values::Heap) -> $crate::values::Value<'v> {
28 heap.alloc_complex(self)
29 }
30 }
31
32 impl $crate::values::AllocFrozenValue for [< Frozen $x >] {
33 #[inline]
34 fn alloc_frozen_value(self, heap: &$crate::values::FrozenHeap) -> $crate::values::FrozenValue {
35 heap.alloc_simple(self)
36 }
37 }
38
39 impl<'v> $x<'v> {
40 /// Downcast the value.
41 #[inline]
42 pub fn from_value(x: $crate::values::Value<'v>) -> Option<&'v Self> {
43 if let Some(x) = x.unpack_frozen() {
44 $crate::values::ValueLike::downcast_ref::< [< Frozen $x >] >(x).map($crate::__macro_refs::coerce)
45 } else {
46 $crate::values::ValueLike::downcast_ref::< $x<'v> >(x)
47 }
48 }
49 }
50
51 impl<'v> $crate::values::type_repr::StarlarkTypeRepr for &'v $x<'v> {
52 type Canonical = $x<'v>;
53
54 #[inline]
55 fn starlark_type_repr() -> $crate::typing::Ty {
56 <$x as $crate::values::StarlarkValue>::get_type_starlark_repr()
57 }
58 }
59
60 impl<'v> $crate::values::UnpackValue<'v> for &'v $x<'v> {
61 type Error = std::convert::Infallible;
62
63 #[inline]
64 fn unpack_value_impl(x: $crate::values::Value<'v>) -> Result<Option<&'v $x<'v>>, Self::Error> {
65 Ok($x::from_value(x))
66 }
67 }
68 }
69 };
70 ($v:vis $x:ident) => {
71 $crate::__macro_refs::item! {
72 /// Type of value.
73 $v type $x<'v> = [< $x Gen >]<$crate::values::Value<'v>>;
74 /// Type of frozen value.
75 $v type [< Frozen $x >] = [< $x Gen >]<$crate::values::FrozenValue>;
76
77 starlark_complex_value!(impl $x);
78 }
79 };
80 ($v:vis $x:ident <'v>) => {
81 $crate::__macro_refs::item! {
82 /// Type of unfrozen value.
83 $v type $x<'v> = [< $x Gen >]<'v, $crate::values::Value<'v>>;
84 /// Type of frozen value.
85 $v type [< Frozen $x >] = [< $x Gen >]<'static, $crate::values::FrozenValue>;
86
87 starlark_complex_value!(impl $x);
88 }
89 };
90}
91
92/// Reduce boilerplate when making types instances of [`ComplexValue`](crate::values::ComplexValue)
93/// - see the [`ComplexValue`](crate::values::ComplexValue) docs for an example.
94#[macro_export]
95macro_rules! starlark_complex_values {
96 ($x:ident) => {
97 $crate::__macro_refs::item! {
98 impl<'v> $crate::values::AllocValue<'v> for $x<'v> {
99 #[inline]
100 fn alloc_value(self, heap: &'v $crate::values::Heap) -> $crate::values::Value<'v> {
101 heap.alloc_complex(self)
102 }
103 }
104
105 impl $crate::values::AllocFrozenValue for [< Frozen $x >] {
106 #[inline]
107 fn alloc_frozen_value(self, heap: &$crate::values::FrozenHeap) -> $crate::values::FrozenValue {
108 heap.alloc_simple(self)
109 }
110 }
111
112 impl<'v> $x<'v> {
113 #[allow(dead_code)]
114 #[inline]
115 pub(crate) fn from_value(
116 x: $crate::values::Value<'v>,
117 ) -> Option<$crate::__macro_refs::Either<&'v Self, &'v [< Frozen $x >]>> {
118 if let Some(x) = x.unpack_frozen() {
119 $crate::values::ValueLike::downcast_ref(x).map($crate::__macro_refs::Either::Right)
120 } else {
121 $crate::values::ValueLike::downcast_ref(x).map($crate::__macro_refs::Either::Left)
122 }
123 }
124 }
125 }
126 };
127}
128
129/// A macro reducing boilerplace defining Starlark values which are simple - they
130/// aren't mutable and can't contain references to other Starlark values.
131///
132/// Let's define a simple object, where `+x` makes the string uppercase:
133///
134/// ```
135/// use allocative::Allocative;
136/// use derive_more::Display;
137/// use starlark::starlark_simple_value;
138/// use starlark::values::Heap;
139/// use starlark::values::NoSerialize;
140/// use starlark::values::ProvidesStaticType;
141/// use starlark::values::StarlarkValue;
142/// use starlark::values::Value;
143/// use starlark_derive::starlark_value;
144///
145/// #[derive(Debug, Display, ProvidesStaticType, NoSerialize, Allocative)]
146/// struct MyObject(String);
147/// starlark_simple_value!(MyObject);
148///
149/// #[starlark_value(type = "my_object")]
150/// impl<'v> StarlarkValue<'v> for MyObject {
151/// // We can choose to implement whichever methods we want.
152/// // All other operations will result in runtime errors.
153/// fn plus(&self, heap: &'v Heap) -> starlark::Result<Value<'v>> {
154/// Ok(heap.alloc(MyObject(self.0.to_uppercase())))
155/// }
156/// }
157/// ```
158///
159/// The `starlark_simple_value!` macro defines instances of
160/// [`ProvidesStaticType`](crate::values::ProvidesStaticType),
161/// [`AllocValue`](crate::values::AllocValue),
162/// [`AllocFrozenValue`](crate::values::AllocFrozenValue) and
163/// [`UnpackValue`](crate::values::UnpackValue). It also defines a method:
164///
165/// ```
166/// # use crate::starlark::values::*;
167/// # struct MyObject;
168/// impl MyObject {
169/// pub fn from_value<'v>(x: Value<'v>) -> Option<&'v MyObject> {
170/// # unimplemented!(
171/// # r#"
172/// ...
173/// # "#);
174/// }
175/// }
176/// ```
177#[macro_export]
178macro_rules! starlark_simple_value {
179 ($x:ident) => {
180 $crate::__macro_refs::item! {
181 impl<'v> $crate::values::AllocValue<'v> for $x {
182 #[inline]
183 fn alloc_value(self, heap: &'v $crate::values::Heap) -> $crate::values::Value<'v> {
184 heap.alloc_simple(self)
185 }
186 }
187
188 impl $crate::values::AllocFrozenValue for $x {
189 #[inline]
190 fn alloc_frozen_value(self, heap: &$crate::values::FrozenHeap) -> $crate::values::FrozenValue {
191 heap.alloc_simple(self)
192 }
193 }
194
195 impl $x {
196 /// Downcast a value to self type.
197 #[inline]
198 pub fn from_value<'v>(x: $crate::values::Value<'v>) -> Option<&'v Self> {
199 $crate::values::ValueLike::downcast_ref::< $x >(x)
200 }
201 }
202
203 impl<'v> $crate::values::type_repr::StarlarkTypeRepr for &'v $x {
204 type Canonical = $x;
205
206 fn starlark_type_repr() -> $crate::typing::Ty {
207 <$x as $crate::values::StarlarkValue>::get_type_starlark_repr()
208 }
209 }
210
211 impl<'v> $crate::values::UnpackValue<'v> for &'v $x {
212 type Error = std::convert::Infallible;
213
214 #[inline]
215 fn unpack_value_impl(x: $crate::values::Value<'v>) -> std::result::Result<Option<&'v $x>, Self::Error> {
216 std::result::Result::Ok($x::from_value(x))
217 }
218 }
219 }
220 };
221}