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}