starlark/src/values/freeze.rs (128 lines of code) (raw):

/* * Copyright 2018 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 std::{cell::RefCell, marker, marker::PhantomData}; use gazebo::prelude::*; use crate::{ collections::{ vec_map::{Bucket, VecMap}, SmallMap, }, values::{Freezer, FrozenStringValue, FrozenValue, StringValue, Value}, }; /// Need to be implemented for non-simple `StarlarkValue`. /// /// This is called on freeze of the heap. Must produce a replacement object to place /// in the frozen heap. /// /// For relatively simple cases it can be implemented with `#[derive(Freeze)]`: /// /// ``` /// # struct AdditionalData; /// /// use starlark::values::Freeze; /// /// #[derive(Freeze)] /// struct MyType<V> { /// value: V, /// // This field does not implement `Freeze`, but we can use it as is for freeze. /// #[freeze(identity)] /// data: AdditionalData, /// } /// ``` pub trait Freeze { /// When type is frozen, it is frozen into this type. type Frozen; /// Freeze a value. The frozen value _must_ be equal to the original, /// and produce the same hash. /// /// Note during freeze, `Value` objects in `Self` might be already special forward-objects, /// trying to unpack these objects will crash the process. /// So the function is only allowed to access `Value` objects after it froze them. fn freeze(self, freezer: &Freezer) -> anyhow::Result<Self::Frozen>; } impl Freeze for String { type Frozen = String; fn freeze(self, _freezer: &Freezer) -> anyhow::Result<String> { Ok(self) } } impl Freeze for i32 { type Frozen = i32; fn freeze(self, _freezer: &Freezer) -> anyhow::Result<i32> { Ok(self) } } impl Freeze for usize { type Frozen = usize; fn freeze(self, _freezer: &Freezer) -> anyhow::Result<usize> { Ok(self) } } impl Freeze for bool { type Frozen = bool; fn freeze(self, _freezer: &Freezer) -> anyhow::Result<bool> { Ok(self) } } impl<'v, T: 'static> Freeze for marker::PhantomData<&'v T> { type Frozen = PhantomData<&'static T>; fn freeze(self, _freezer: &Freezer) -> anyhow::Result<PhantomData<&'static T>> { Ok(marker::PhantomData) } } impl<T> Freeze for Vec<T> where T: Freeze, { type Frozen = Vec<T::Frozen>; fn freeze(self, freezer: &Freezer) -> anyhow::Result<Vec<T::Frozen>> { self.into_try_map(|v| v.freeze(freezer)) } } impl<T> Freeze for RefCell<T> where T: Freeze, { type Frozen = T::Frozen; fn freeze(self, freezer: &Freezer) -> anyhow::Result<T::Frozen> { self.into_inner().freeze(freezer) } } impl<T> Freeze for Option<T> where T: Freeze, { type Frozen = Option<T::Frozen>; fn freeze(self, freezer: &Freezer) -> anyhow::Result<Option<T::Frozen>> { self.into_try_map(|v| v.freeze(freezer)) } } impl<K, V> Freeze for VecMap<K, V> where K: Freeze, V: Freeze, { type Frozen = VecMap<K::Frozen, V::Frozen>; fn freeze(self, freezer: &Freezer) -> anyhow::Result<Self::Frozen> { let buckets = self.buckets.into_try_map(|Bucket { hash, key, value }| { let key = key.freeze(freezer)?; let value = value.freeze(freezer)?; // `freeze` must not change hash. anyhow::Ok(Bucket { hash, key, value }) })?; Ok(VecMap { buckets }) } } impl<K, V> Freeze for SmallMap<K, V> where K: Freeze, V: Freeze, { type Frozen = SmallMap<K::Frozen, V::Frozen>; fn freeze(mut self, freezer: &Freezer) -> anyhow::Result<SmallMap<K::Frozen, V::Frozen>> { self.maybe_drop_index(); let (entries, index) = self.into_raw_parts(); let entries = entries.freeze(freezer)?; unsafe { Ok(SmallMap::from_raw_parts(entries, index)) } } } impl<'v> Freeze for Value<'v> { type Frozen = FrozenValue; fn freeze(self, freezer: &Freezer) -> anyhow::Result<FrozenValue> { freezer.freeze(self) } } impl Freeze for FrozenValue { type Frozen = FrozenValue; fn freeze(self, _freezer: &Freezer) -> anyhow::Result<FrozenValue> { Ok(self) } } impl<'v> Freeze for StringValue<'v> { type Frozen = FrozenStringValue; fn freeze(self, freezer: &Freezer) -> anyhow::Result<FrozenStringValue> { self.freeze(freezer) } } impl Freeze for FrozenStringValue { type Frozen = FrozenStringValue; fn freeze(self, _freezer: &Freezer) -> anyhow::Result<FrozenStringValue> { Ok(self) } }