starlark 0.8.0

An implementation of the Starlark language in Rust.
Documentation
/*
 * 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::{Cell, RefCell},
    marker,
};

use hashbrown::raw::RawTable;

use crate::{
    collections::SmallMap,
    values::{FrozenValue, Tracer, Value},
};

/// Called by the garbage collection, and must walk over every contained `Value` in the type.
/// Marked `unsafe` because if you miss a nested `Value`, it will probably segfault.
///
/// For the most cases `#[derive(Trace)]` is enough to implement this trait:
///
/// ```
/// # use starlark::values::Value;
/// # use starlark::values::Trace;
///
/// #[derive(Trace)]
/// struct MySet<'v> {
///    keys: Vec<Value<'v>>
/// }
/// ```
pub unsafe trait Trace<'v> {
    /// Recursively "trace" the value.
    ///
    /// Note during trace, `Value` objects in `Self` might be already special forward-objects,
    /// trying to unpack these values may crash the process.
    ///
    /// Generally this function should not do anything except calling `trace` on the fields.
    fn trace(&mut self, tracer: &Tracer<'v>);
}

unsafe impl<'v, T: Trace<'v>> Trace<'v> for Vec<T> {
    fn trace(&mut self, tracer: &Tracer<'v>) {
        self.iter_mut().for_each(|x| x.trace(tracer));
    }
}

unsafe impl<'v, T: Trace<'v>> Trace<'v> for [T] {
    fn trace(&mut self, tracer: &Tracer<'v>) {
        self.iter_mut().for_each(|x| x.trace(tracer));
    }
}

unsafe impl<'v, T: Trace<'v>> Trace<'v> for RawTable<T> {
    fn trace(&mut self, tracer: &Tracer<'v>) {
        unsafe {
            self.iter().for_each(|e| e.as_mut().trace(tracer));
        }
    }
}

unsafe impl<'v, K: Trace<'v>, V: Trace<'v>> Trace<'v> for SmallMap<K, V> {
    fn trace(&mut self, tracer: &Tracer<'v>) {
        self.iter_mut().for_each(|(k, v)| {
            // We are going to replace it, but promise morally it's the same Value
            // so things like Hash/Ord/Eq will work the same
            #[allow(clippy::cast_ref_to_mut)]
            let k_mut = unsafe { &mut *(k as *const K as *mut K) };
            k_mut.trace(tracer);
            v.trace(tracer);
        })
    }
}

unsafe impl<'v, T: Trace<'v>> Trace<'v> for Option<T> {
    fn trace(&mut self, tracer: &Tracer<'v>) {
        if let Some(x) = self {
            x.trace(tracer)
        }
    }
}

unsafe impl<'v, T: Trace<'v>> Trace<'v> for RefCell<T> {
    fn trace(&mut self, tracer: &Tracer<'v>) {
        self.get_mut().trace(tracer)
    }
}

unsafe impl<'v, T: Trace<'v> + Copy> Trace<'v> for Cell<T> {
    fn trace(&mut self, tracer: &Tracer<'v>) {
        self.get_mut().trace(tracer);
    }
}

unsafe impl<'v, T: Trace<'v> + ?Sized> Trace<'v> for Box<T> {
    fn trace(&mut self, tracer: &Tracer<'v>) {
        Box::as_mut(self).trace(tracer)
    }
}

unsafe impl<'v, T1: Trace<'v>, T2: Trace<'v>> Trace<'v> for (T1, T2) {
    fn trace(&mut self, tracer: &Tracer<'v>) {
        self.0.trace(tracer);
        self.1.trace(tracer);
    }
}

unsafe impl<'v> Trace<'v> for Value<'v> {
    fn trace(&mut self, tracer: &Tracer<'v>) {
        tracer.trace(self)
    }
}

unsafe impl<'v> Trace<'v> for FrozenValue {
    fn trace(&mut self, _tracer: &Tracer<'v>) {}
}

unsafe impl<'v> Trace<'v> for String {
    fn trace(&mut self, _tracer: &Tracer<'v>) {}
}

unsafe impl<'v> Trace<'v> for usize {
    fn trace(&mut self, _tracer: &Tracer<'v>) {}
}

unsafe impl<'v> Trace<'v> for i32 {
    fn trace(&mut self, _tracer: &Tracer<'v>) {}
}

unsafe impl<'v> Trace<'v> for u32 {
    fn trace(&mut self, _tracer: &Tracer<'v>) {}
}

unsafe impl<'v> Trace<'v> for u64 {
    fn trace(&mut self, _tracer: &Tracer<'v>) {}
}

unsafe impl<'v> Trace<'v> for bool {
    fn trace(&mut self, _tracer: &Tracer<'v>) {}
}

unsafe impl<'v> Trace<'v> for std::time::Instant {
    fn trace(&mut self, _tracer: &Tracer<'v>) {}
}

unsafe impl<'v, T> Trace<'v> for marker::PhantomData<T> {
    fn trace(&mut self, _tracer: &Tracer<'v>) {}
}