starlark 0.14.0

An implementation of the Starlark language in Rust.
Documentation
/*
 * Copyright 2026 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.
 */

//! Macro and trait for registering static Starlark values for pagable serialization.

/// Marker trait for types which are statically allocated and registered
/// for pagable serialization.
///
/// # Safety
///
/// This trait should only be implemented by the `static_starlark_value!` macro
/// (or related macros like `static_type_compiled!`), which ensures the type is
/// properly registered for pagable serialization. Manual implementations may
/// lead to missing registrations or inconsistent behavior.
pub unsafe trait StaticValueRegistered {}

/// Define a singleton static Starlark value with automatic pagable registration.
///
/// This macro creates a static variable using `AllocStaticSimple` and registers it
/// for pagable serialization via the inventory crate using `file!()` and `line!()`
/// to generate a deterministic hash-based ID. It also implements
/// `StaticValueRegistered` for the type.
///
/// # Syntax
///
/// ```ignore
/// static_starlark_value!(pub(crate) VALUE_NONE: NoneType = NoneType);
/// static_starlark_value!(pub(crate) VALUE_EMPTY_TUPLE: FrozenTuple = unsafe { FrozenTuple::new(0) });
///
/// // Multiple static values of the same type
/// static_starlark_value!(StarlarkBool {
///     pub(crate) VALUE_FALSE = StarlarkBool(false);
///     pub(crate) VALUE_TRUE = StarlarkBool(true);
/// });
/// ```
#[macro_export]
macro_rules! static_starlark_value {
    // Multiple values of the same type.
    // Note: we inline the body instead of delegating to `@core` because
    // `line!()` in a recursive macro call resolves to the outer invocation line,
    // so all entries would get the same `(file, line)` and thus the same
    // `StaticValueId`. We use `concat!(file!(), "::", stringify!($name))` to
    // disambiguate entries registered from the same macro invocation.
    ($ty:ty { $( $vis:vis $name:ident = $value:expr );+ $(;)? }) => {
        // SAFETY: This impl is generated by static_starlark_value! alongside the static
        // registration, ensuring the type is properly registered for pagable serialization.
        unsafe impl $crate::values::StaticValueRegistered for $ty {}

        $(
            $vis static $name: $crate::values::AllocStaticSimple<$ty> =
                $crate::values::AllocStaticSimple::alloc($value);

            $crate::__derive_refs::inventory::submit! {
                $crate::__derive_refs::StaticValueEntry::new(
                    concat!(file!(), "::", stringify!($name)),
                    line!(),
                    || $name.to_frozen_value()
                )
            }
        )+
    };

    // Single value
    ($vis:vis $name:ident : $ty:ty = $value:expr) => {
        // SAFETY: This impl is generated by static_starlark_value! alongside the static
        // registration, ensuring the type is properly registered for pagable serialization.
        unsafe impl $crate::values::StaticValueRegistered for $ty {}

        static_starlark_value!(@core $vis $name : $ty = { $value });
    };

    // Internal: core static declaration + inventory registration
    // Value is wrapped in braces to avoid ambiguity
    (@core $vis:vis $name:ident : $ty:ty = { $($value:tt)+ }) => {
        $vis static $name: $crate::values::AllocStaticSimple<$ty> =
            $crate::values::AllocStaticSimple::alloc($($value)+);

        $crate::__derive_refs::inventory::submit! {
            $crate::__derive_refs::StaticValueEntry::new(
                file!(),
                line!(),
                || $name.to_frozen_value()
            )
        }
    };
}