1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
/*
* Copyright 2019 The Starlark in Rust Authors.
* Copyright (c) Facebook, Inc. and its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use dupe::Dupe;
use either::Either;
use crate::typing::Ty;
use crate::values::none::NoneType;
use crate::values::type_repr::StarlarkTypeRepr;
use crate::values::AllocFrozenValue;
use crate::values::AllocValue;
use crate::values::FrozenHeap;
use crate::values::FrozenValue;
use crate::values::Heap;
use crate::values::UnpackValue;
use crate::values::Value;
/// Equivalent of a Rust [`Option`], where `None`
/// is encoded as [`NoneType`](crate::values::none::NoneType).
/// Useful for its [`UnpackValue`] instance.
#[derive(Debug, Eq, PartialEq, Copy, Clone, Dupe)]
pub enum NoneOr<T> {
/// Starlark `None`.
None,
/// Not `None`.
Other(T),
}
impl<T> NoneOr<T> {
/// Convert the [`NoneOr`] to a real Rust [`Option`].
#[inline]
pub fn into_option(self) -> Option<T> {
match self {
Self::None => None,
Self::Other(x) => Some(x),
}
}
/// Is the value a [`NoneOr::None`].
pub fn is_none(&self) -> bool {
matches!(self, NoneOr::None)
}
}
impl<T: StarlarkTypeRepr> StarlarkTypeRepr for NoneOr<T> {
fn starlark_type_repr() -> Ty {
Either::<NoneType, T>::starlark_type_repr()
}
}
impl<'v, T: UnpackValue<'v>> UnpackValue<'v> for NoneOr<T> {
fn expected() -> String {
format!("None or {}", T::expected())
}
fn unpack_value(value: Value<'v>) -> Option<Self> {
if value.is_none() {
Some(NoneOr::None)
} else {
T::unpack_value(value).map(NoneOr::Other)
}
}
}
impl<'v, T: AllocValue<'v>> AllocValue<'v> for NoneOr<T> {
fn alloc_value(self, heap: &'v Heap) -> Value<'v> {
match self {
NoneOr::None => Value::new_none(),
NoneOr::Other(x) => x.alloc_value(heap),
}
}
}
impl<T: AllocFrozenValue> AllocFrozenValue for NoneOr<T> {
fn alloc_frozen_value(self, heap: &FrozenHeap) -> FrozenValue {
match self {
NoneOr::None => FrozenValue::new_none(),
NoneOr::Other(x) => x.alloc_frozen_value(heap),
}
}
}