Create starlark types crate.

This crate contains the core bazel types that all other crates depend on.

For now, this crate can only be built with cargo.
Note: Tests require linking in a .a file from GN. Running the tests
thus requires first building gn.

Bug: 528225104
Change-Id: I805094989f01480a3875a38c191ddb5e6a6a6964
Reviewed-on: https://gn-review.googlesource.com/c/gn/+/23382
Reviewed-by: Philipp Wollermann <philwo@google.com>
Reviewed-by: Richard Wang <richardwa@google.com>
Commit-Queue: Matt Stark <msta@google.com>
diff --git a/src/gn/starlark/.cargo/config.toml b/src/gn/starlark/.cargo/config.toml
new file mode 100644
index 0000000..1a0e35a
--- /dev/null
+++ b/src/gn/starlark/.cargo/config.toml
@@ -0,0 +1,2 @@
+[env]
+CXXFLAGS = { value = "-std=c++23", relative = false }
diff --git a/src/gn/starlark/Cargo.lock b/src/gn/starlark/Cargo.lock
index 979b39c..9e55395 100644
--- a/src/gn/starlark/Cargo.lock
+++ b/src/gn/starlark/Cargo.lock
@@ -3,45 +3,1787 @@
 version = 4
 
 [[package]]
-name = "gn_starlark"
-version = "0.1.0"
+name = "Inflector"
+version = "0.11.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
+dependencies = [
+ "lazy_static",
+ "regex",
+]
 
-[[patch.unused]]
+[[package]]
+name = "aho-corasick"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
 name = "allocative"
 version = "0.3.6"
 source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#c599dd000d7f754cfa68af4bca4a4e2a622c2e1b"
+dependencies = [
+ "allocative_derive",
+ "bumpalo",
+ "ctor",
+ "hashbrown 0.16.1",
+ "num-bigint",
+]
 
-[[patch.unused]]
+[[package]]
 name = "allocative_derive"
 version = "0.3.6"
 source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#c599dd000d7f754cfa68af4bca4a4e2a622c2e1b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
 
-[[patch.unused]]
+[[package]]
+name = "allocator-api2"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
+
+[[package]]
+name = "annotate-snippets"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccaf7e9dfbb6ab22c82e473cd1a8a7bd313c19a5b7e40970f3d89ef5a5c9e81e"
+dependencies = [
+ "unicode-width",
+]
+
+[[package]]
+name = "anstyle"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
+
+[[package]]
+name = "anyhow"
+version = "1.0.103"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3"
+
+[[package]]
+name = "arrayref"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb"
+
+[[package]]
+name = "arrayvec"
+version = "0.7.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f02882884d3e1bc524fb12c79f107f6ad0e1cfd498c536ffb494301740995dfe"
+
+[[package]]
+name = "async-trait"
+version = "0.1.89"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "atomic"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba"
+
+[[package]]
+name = "atomic-polyfill"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4"
+dependencies = [
+ "critical-section",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
+
+[[package]]
+name = "beef"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
+
+[[package]]
+name = "bit-set"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
+dependencies = [
+ "bit-vec",
+]
+
+[[package]]
+name = "bit-vec"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
+
+[[package]]
+name = "blake3"
+version = "1.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0"
+dependencies = [
+ "arrayref",
+ "arrayvec",
+ "cc",
+ "cfg-if",
+ "constant_time_eq",
+ "digest",
+ "rayon-core",
+]
+
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.20.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
+
+[[package]]
+name = "bytemuck"
+version = "1.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec"
+dependencies = [
+ "bytemuck_derive",
+]
+
+[[package]]
+name = "bytemuck_derive"
+version = "1.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "cc"
+version = "1.2.65"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96"
+dependencies = [
+ "find-msvc-tools",
+ "shlex",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
+
+[[package]]
+name = "cfg_aliases"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
+
+[[package]]
+name = "clap"
+version = "4.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51"
+dependencies = [
+ "clap_builder",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
+dependencies = [
+ "anstyle",
+ "clap_lex",
+ "strsim",
+]
+
+[[package]]
+name = "clap_lex"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
+
+[[package]]
+name = "clipboard-win"
+version = "5.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4"
+dependencies = [
+ "error-code",
+]
+
+[[package]]
+name = "cmp_any"
+version = "0.8.1"
+source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#1dc81928e2b9766919416ef5fb21857452153ec0"
+
+[[package]]
+name = "cobs"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
+dependencies = [
+ "thiserror",
+]
+
+[[package]]
+name = "codespan-reporting"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af491d569909a7e4dee0ad7db7f5341fef5c614d5b8ec8cf765732aba3cff681"
+dependencies = [
+ "serde",
+ "termcolor",
+ "unicode-width",
+]
+
+[[package]]
+name = "constant_time_eq"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6"
+
+[[package]]
+name = "convert_case"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "crc"
+version = "3.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d"
+dependencies = [
+ "crc-catalog",
+]
+
+[[package]]
+name = "crc-catalog"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853"
+
+[[package]]
+name = "critical-section"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51"
+dependencies = [
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
+
+[[package]]
+name = "crypto-common"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a"
+dependencies = [
+ "generic-array",
+ "typenum",
+]
+
+[[package]]
+name = "ctor"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "01334b89b69ff726750c5ce5073fc8bd860e99aa9a8fc5ca11b04730e3aee97a"
+dependencies = [
+ "link-section",
+ "linktime-proc-macro",
+]
+
+[[package]]
+name = "cxx"
+version = "1.0.194"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "747d8437319e3a2f43d93b341c137927ca70c0f5dabeea7a005a73665e247c7e"
+dependencies = [
+ "cc",
+ "cxx-build",
+ "cxxbridge-cmd",
+ "cxxbridge-flags",
+ "cxxbridge-macro",
+ "foldhash",
+ "link-cplusplus",
+]
+
+[[package]]
+name = "cxx-build"
+version = "1.0.194"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0f4697d190a142477b16aef7da8a99bfdc41e7e8b1687583c0d23a79c7afc1e"
+dependencies = [
+ "cc",
+ "codespan-reporting",
+ "indexmap",
+ "proc-macro2",
+ "quote",
+ "scratch",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "cxxbridge-cmd"
+version = "1.0.194"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0956799fa8678d4c50eed028f2de1c0552ae183c76e976cf7ca8c4e36a7c328"
+dependencies = [
+ "clap",
+ "codespan-reporting",
+ "indexmap",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "cxxbridge-flags"
+version = "1.0.194"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23384a836ab4f0ad98ace7e3955ad2de39de42378ab487dc28d3990392cb283a"
+
+[[package]]
+name = "cxxbridge-macro"
+version = "1.0.194"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6acc6b5822b9526adfb4fc377b67128fdd60aac757cc4a741a6278603f763cf"
+dependencies = [
+ "indexmap",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "dashmap"
+version = "6.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c"
+dependencies = [
+ "cfg-if",
+ "crossbeam-utils",
+ "hashbrown 0.14.5",
+ "lock_api",
+ "once_cell",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "debugserver-types"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2bf6834a70ed14e8e4e41882df27190bea150f1f6ecf461f1033f8739cd8af4a"
+dependencies = [
+ "schemafy",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "derivative"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "derive_more"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05"
+dependencies = [
+ "derive_more-impl",
+]
+
+[[package]]
+name = "derive_more-impl"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
+dependencies = [
+ "convert_case",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+ "unicode-xid",
+]
+
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer",
+ "crypto-common",
+ "subtle",
+]
+
+[[package]]
+name = "display_container"
+version = "0.9.0"
+source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#1dc81928e2b9766919416ef5fb21857452153ec0"
+dependencies = [
+ "either",
+ "indenter",
+]
+
+[[package]]
+name = "dupe"
+version = "0.9.1"
+source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#1dc81928e2b9766919416ef5fb21857452153ec0"
+dependencies = [
+ "dupe_derive",
+]
+
+[[package]]
+name = "dupe_derive"
+version = "0.9.1"
+source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#1dc81928e2b9766919416ef5fb21857452153ec0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "either"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
+
+[[package]]
+name = "embedded-io"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
+
+[[package]]
+name = "embedded-io"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
+
+[[package]]
+name = "endian-type"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d"
+
+[[package]]
+name = "env_filter"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "900d271a03799a1ee8d1ca9b19893b48ca674a9284fefcfb85f05e74ed314217"
+dependencies = [
+ "log",
+ "regex",
+]
+
+[[package]]
+name = "env_logger"
+version = "0.11.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de671bd27a75a797dc9ae289ba1e77276e75e2026408aab65185384e2d5cd3f6"
+dependencies = [
+ "env_filter",
+ "log",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
+
+[[package]]
+name = "erased-serde"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c138974f9d5e7fe373eb04df7cae98833802ae4b11c24ac7039a21d5af4b26c"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "erased-serde"
+version = "0.4.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2add8a07dd6a8d93ff627029c51de145e12686fbc36ecb298ac22e74cf02dec"
+dependencies = [
+ "serde",
+ "serde_core",
+ "typeid",
+]
+
+[[package]]
+name = "errno"
+version = "0.3.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
+dependencies = [
+ "libc",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "error-code"
+version = "3.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59"
+
+[[package]]
+name = "fancy-regex"
+version = "0.16.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "998b056554fbe42e03ae0e152895cd1a7e1002aec800fdc6635d20270260c46f"
+dependencies = [
+ "bit-set",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "fd-lock"
+version = "4.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78"
+dependencies = [
+ "cfg-if",
+ "rustix",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
+name = "find-msvc-tools"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
+
+[[package]]
+name = "fluent-uri"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17c704e9dbe1ddd863da1e6ff3567795087b1eb201ce80d8fa81162e1516500d"
+dependencies = [
+ "bitflags 1.3.2",
+]
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "foldhash"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
+
+[[package]]
+name = "fxhash"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c"
+dependencies = [
+ "byteorder",
+]
+
+[[package]]
+name = "generic-array"
+version = "0.14.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+dependencies = [
+ "typenum",
+ "version_check",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "rand_core",
+]
+
+[[package]]
+name = "gn_starlark"
+version = "0.1.0"
+
+[[package]]
+name = "hash32"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67"
+dependencies = [
+ "byteorder",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+
+[[package]]
+name = "hashbrown"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
+dependencies = [
+ "allocator-api2",
+ "equivalent",
+ "foldhash",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.17.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
+
+[[package]]
+name = "heapless"
+version = "0.7.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f"
+dependencies = [
+ "atomic-polyfill",
+ "hash32",
+ "rustc_version",
+ "serde",
+ "spin",
+ "stable_deref_trait",
+]
+
+[[package]]
+name = "home"
+version = "0.5.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "indenter"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5"
+
+[[package]]
+name = "indexmap"
+version = "2.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.17.1",
+ "serde",
+ "serde_core",
+]
+
+[[package]]
+name = "inventory"
+version = "0.3.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4f0c30c76f2f4ccee3fe55a2435f691ca00c0e4bd87abe4f4a851b1d4dac39b"
+dependencies = [
+ "rustversion",
+]
+
+[[package]]
+name = "itertools"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
+
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
+[[package]]
+name = "libc"
+version = "0.2.186"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
+
+[[package]]
+name = "link-cplusplus"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f78c730aaa7d0b9336a299029ea49f9ee53b0ed06e9202e8cb7db9bae7b8c82"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "link-section"
+version = "0.18.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24670b639492630905459a6c7d47f063d33c2d4fcd5362f6e5827c5613976c9f"
+
+[[package]]
+name = "linktime-proc-macro"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c7b0a3383c2a1002d11349c92c85a666a5fb679e96c79d782cf0dbe557fd6ee"
+
+[[package]]
+name = "linux-raw-sys"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
+
+[[package]]
+name = "lock_api"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
+dependencies = [
+ "scopeguard",
+]
+
+[[package]]
+name = "lock_free_hashtable"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebf3631712f5b790675292ff827af269f5d9f920c920b77dc41d0485e3719612"
+dependencies = [
+ "atomic",
+ "parking_lot",
+]
+
+[[package]]
+name = "log"
+version = "0.4.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
+
+[[package]]
+name = "logos"
+version = "0.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ff472f899b4ec2d99161c51f60ff7075eeb3097069a36050d8037a6325eb8154"
+dependencies = [
+ "logos-derive",
+]
+
+[[package]]
+name = "logos-codegen"
+version = "0.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "192a3a2b90b0c05b27a0b2c43eecdb7c415e29243acc3f89cc8247a5b693045c"
+dependencies = [
+ "beef",
+ "fnv",
+ "lazy_static",
+ "proc-macro2",
+ "quote",
+ "regex-syntax",
+ "rustc_version",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "logos-derive"
+version = "0.15.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "605d9697bcd5ef3a42d38efc51541aa3d6a4a25f7ab6d1ed0da5ac632a26b470"
+dependencies = [
+ "logos-codegen",
+]
+
+[[package]]
+name = "lsp-types"
+version = "0.97.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53353550a17c04ac46c585feb189c2db82154fc84b79c7a66c96c2c644f66071"
+dependencies = [
+ "bitflags 1.3.2",
+ "fluent-uri",
+ "serde",
+ "serde_json",
+ "serde_repr",
+]
+
+[[package]]
+name = "maplit"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d"
+
+[[package]]
+name = "memchr"
+version = "2.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
+
+[[package]]
+name = "memoffset"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "nibble_vec"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43"
+dependencies = [
+ "smallvec",
+]
+
+[[package]]
+name = "nix"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
+dependencies = [
+ "bitflags 2.13.0",
+ "cfg-if",
+ "cfg_aliases",
+ "libc",
+]
+
+[[package]]
+name = "num-bigint"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9"
+dependencies = [
+ "num-integer",
+ "num-traits",
+ "serde",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.21.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
+
+[[package]]
 name = "pagable"
 version = "0.4.1"
 source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#c599dd000d7f754cfa68af4bca4a4e2a622c2e1b"
+dependencies = [
+ "allocative",
+ "anyhow",
+ "async-trait",
+ "blake3",
+ "bytemuck",
+ "dashmap",
+ "dupe",
+ "either",
+ "erased-serde 0.4.10",
+ "fancy-regex",
+ "indexmap",
+ "inventory",
+ "num-bigint",
+ "once_cell",
+ "pagable_derive",
+ "parking_lot",
+ "postcard",
+ "regex",
+ "sequence_trie",
+ "serde",
+ "serde_json",
+ "smallvec",
+ "sorted_vector_map",
+ "static_assertions",
+ "static_interner",
+ "strong_hash",
+ "take_mut",
+ "triomphe",
+]
 
-[[patch.unused]]
+[[package]]
 name = "pagable_derive"
 version = "0.4.1"
 source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#c599dd000d7f754cfa68af4bca4a4e2a622c2e1b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
 
-[[patch.unused]]
+[[package]]
+name = "parking_lot"
+version = "0.12.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-link",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+
+[[package]]
+name = "postcard"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24"
+dependencies = [
+ "cobs",
+ "crc",
+ "embedded-io 0.4.0",
+ "embedded-io 0.6.1",
+ "heapless",
+ "serde",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.106"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quickcheck"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95c589f335db0f6aaa168a7cd27b1fc6920f5e1470c804f814d9cd6e62a0f70b"
+dependencies = [
+ "env_logger",
+ "log",
+ "rand",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "r-efi"
+version = "6.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
+
+[[package]]
+name = "radix_trie"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd"
+dependencies = [
+ "endian-type",
+ "nibble_vec",
+]
+
+[[package]]
+name = "rand"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207"
+dependencies = [
+ "getrandom",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
+
+[[package]]
+name = "rayon-core"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91"
+dependencies = [
+ "crossbeam-deque",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.5.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
+dependencies = [
+ "bitflags 2.13.0",
+]
+
+[[package]]
+name = "ref-cast"
+version = "1.0.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d"
+dependencies = [
+ "ref-cast-impl",
+]
+
+[[package]]
+name = "ref-cast-impl"
+version = "1.0.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "regex"
+version = "1.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
+
+[[package]]
+name = "rustc_version"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "rustix"
+version = "1.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
+dependencies = [
+ "bitflags 2.13.0",
+ "errno",
+ "libc",
+ "linux-raw-sys",
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
+
+[[package]]
+name = "rustyline"
+version = "14.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7803e8936da37efd9b6d4478277f4b2b9bb5cdb37a113e8d63222e58da647e63"
+dependencies = [
+ "bitflags 2.13.0",
+ "cfg-if",
+ "clipboard-win",
+ "fd-lock",
+ "home",
+ "libc",
+ "log",
+ "memchr",
+ "nix",
+ "radix_trie",
+ "unicode-segmentation",
+ "unicode-width",
+ "utf8parse",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "schemafy"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8aea5ba40287dae331f2c48b64dbc8138541f5e97ee8793caa7948c1f31d86d5"
+dependencies = [
+ "Inflector",
+ "schemafy_core",
+ "schemafy_lib",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "serde_repr",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "schemafy_core"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41781ae092f4fd52c9287efb74456aea0d3b90032d2ecad272bd14dbbcb0511b"
+dependencies = [
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "schemafy_lib"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e953db32579999ca98c451d80801b6f6a7ecba6127196c5387ec0774c528befa"
+dependencies = [
+ "Inflector",
+ "proc-macro2",
+ "quote",
+ "schemafy_core",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "scratch"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d68f2ec51b097e4c1a75b681a8bec621909b5e91f15bb7b840c4f2f7b01148b2"
+
+[[package]]
+name = "semver"
+version = "1.0.28"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
+
+[[package]]
+name = "sequence_trie"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ee22067b7ccd072eeb64454b9c6e1b33b61cd0d49e895fd48676a184580e0c3"
+
+[[package]]
+name = "serde"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
+dependencies = [
+ "serde_core",
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_core"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.228"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.150"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
+dependencies = [
+ "itoa",
+ "memchr",
+ "serde",
+ "serde_core",
+ "zmij",
+]
+
+[[package]]
+name = "serde_repr"
+version = "0.1.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "shlex"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
+
+[[package]]
+name = "smallvec"
+version = "1.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90"
+
+[[package]]
+name = "sorted_vector_map"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94bf565ee1681b4473aa5a9d71d807347c28021bd1d8947cb626b02f42a0141f"
+dependencies = [
+ "itertools",
+ "quickcheck",
+]
+
+[[package]]
+name = "spin"
+version = "0.9.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
+dependencies = [
+ "lock_api",
+]
+
+[[package]]
+name = "stable_deref_trait"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
+
+[[package]]
 name = "starlark"
 version = "0.14.2"
 source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#c599dd000d7f754cfa68af4bca4a4e2a622c2e1b"
+dependencies = [
+ "allocative",
+ "anyhow",
+ "blake3",
+ "bumpalo",
+ "cmp_any",
+ "dashmap",
+ "debugserver-types",
+ "derivative",
+ "derive_more",
+ "display_container",
+ "dupe",
+ "either",
+ "erased-serde 0.3.31",
+ "hashbrown 0.16.1",
+ "indexmap",
+ "inventory",
+ "itertools",
+ "maplit",
+ "memoffset",
+ "num-bigint",
+ "num-traits",
+ "once_cell",
+ "pagable",
+ "paste",
+ "ref-cast",
+ "regex",
+ "rustyline",
+ "serde",
+ "serde_json",
+ "starlark_derive",
+ "starlark_map",
+ "starlark_syntax",
+ "static_assertions",
+ "strong_hash",
+ "strsim",
+ "textwrap",
+ "thiserror",
+]
 
-[[patch.unused]]
+[[package]]
 name = "starlark_derive"
 version = "0.14.2"
 source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#c599dd000d7f754cfa68af4bca4a4e2a622c2e1b"
+dependencies = [
+ "dupe",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
 
-[[patch.unused]]
+[[package]]
 name = "starlark_map"
 version = "0.14.2"
 source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#c599dd000d7f754cfa68af4bca4a4e2a622c2e1b"
+dependencies = [
+ "allocative",
+ "dupe",
+ "equivalent",
+ "fxhash",
+ "hashbrown 0.16.1",
+ "pagable",
+ "serde",
+ "strong_hash",
+]
 
-[[patch.unused]]
+[[package]]
 name = "starlark_syntax"
 version = "0.14.2"
 source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#c599dd000d7f754cfa68af4bca4a4e2a622c2e1b"
+dependencies = [
+ "allocative",
+ "annotate-snippets",
+ "anyhow",
+ "derivative",
+ "derive_more",
+ "dupe",
+ "logos",
+ "lsp-types",
+ "memchr",
+ "num-bigint",
+ "num-traits",
+ "once_cell",
+ "pagable",
+ "starlark_map",
+ "thiserror",
+]
+
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
+name = "static_interner"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0a72d2480db611b8ee9287b4a2e0adc63c4d7fdd647d2a1a65d529fc234fd16"
+dependencies = [
+ "equivalent",
+ "lock_free_hashtable",
+]
+
+[[package]]
+name = "strong_hash"
+version = "0.1.0"
+source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#1dc81928e2b9766919416ef5fb21857452153ec0"
+dependencies = [
+ "ref-cast",
+ "strong_hash_derive",
+]
+
+[[package]]
+name = "strong_hash_derive"
+version = "0.1.0"
+source = "git+https://github.com/matts1/starlark-rust.git?branch=gn_starlark#1dc81928e2b9766919416ef5fb21857452153ec0"
+dependencies = [
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "subtle"
+version = "2.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.118"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "take_mut"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
+
+[[package]]
+name = "termcolor"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
+dependencies = [
+ "unicode-width",
+]
+
+[[package]]
+name = "thiserror"
+version = "2.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "2.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.118",
+]
+
+[[package]]
+name = "triomphe"
+version = "0.1.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd69c5aa8f924c7519d6372789a74eac5b94fb0f8fcf0d4a97eb0bfc3e785f39"
+dependencies = [
+ "serde",
+ "stable_deref_trait",
+]
+
+[[package]]
+name = "typeid"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c"
+
+[[package]]
+name = "typenum"
+version = "1.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
+
+[[package]]
+name = "types"
+version = "0.1.0"
+dependencies = [
+ "allocative",
+ "cxx",
+ "starlark",
+ "starlark_derive",
+ "thiserror",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.13.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
+
+[[package]]
+name = "unicode-width"
+version = "0.1.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
+
+[[package]]
+name = "utf8parse"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+
+[[package]]
+name = "version_check"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
+dependencies = [
+ "windows-sys 0.61.2",
+]
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.59.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
+
+[[package]]
+name = "zmij"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
diff --git a/src/gn/starlark/Cargo.toml b/src/gn/starlark/Cargo.toml
index bcbee9d..d216093 100644
--- a/src/gn/starlark/Cargo.toml
+++ b/src/gn/starlark/Cargo.toml
@@ -13,6 +13,7 @@
 [workspace]
 members = [
     ".",
+    "crates/types",
 ]
 
 [workspace.dependencies]
diff --git a/src/gn/starlark/crates/types/Cargo.toml b/src/gn/starlark/crates/types/Cargo.toml
new file mode 100644
index 0000000..ee19c49
--- /dev/null
+++ b/src/gn/starlark/crates/types/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "types"
+version = "0.1.0"
+edition = "2021"
+
+[lints]
+workspace = true
+
+[lib]
+doctest = false
+
+[dependencies]
+starlark = { workspace = true }
+starlark_derive = { workspace = true }
+thiserror = { workspace = true }
+cxx = { workspace = true }
+allocative = { workspace = true }
diff --git a/src/gn/starlark/crates/types/build.rs b/src/gn/starlark/crates/types/build.rs
new file mode 100644
index 0000000..73e52be
--- /dev/null
+++ b/src/gn/starlark/crates/types/build.rs
@@ -0,0 +1,17 @@
+// Copyright 2026 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+fn main() {
+    // When running with ninja, it should set NINJA_OUT_DIR.
+    // If running directly with cargo, we know nothing about the output directory,
+    // so we fall back to assuming the default one.
+    let out_dir = if let Ok(out_dir) = std::env::var("NINJA_OUT_DIR") {
+        std::path::PathBuf::from(out_dir)
+    } else {
+        let manifest_dir = std::path::PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap());
+        manifest_dir.join("../../../../../out")
+    };
+    println!("cargo:rustc-link-search=native={}", out_dir.display());
+    println!("cargo:rustc-link-lib=static=string_atom");
+}
diff --git a/src/gn/starlark/crates/types/src/ctx_state.rs b/src/gn/starlark/crates/types/src/ctx_state.rs
new file mode 100644
index 0000000..0787ff8
--- /dev/null
+++ b/src/gn/starlark/crates/types/src/ctx_state.rs
@@ -0,0 +1,49 @@
+// Copyright 2026 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::{File, TargetRef};
+use starlark::collections::SmallSet;
+
+/// The state associated with the `ctx` object during the rule implementation function.
+#[derive(Clone, Debug, allocative::Allocative)]
+pub struct CtxState<T: TargetRef> {
+    /// Reference to the underlying target.
+    pub target: T,
+    /// All files declared by ctx.actions.declare_file that were never generated.
+    pub unused_declared_outputs: SmallSet<File>,
+    /// A list of phonies declared during this execution step.
+    pub phonies: Vec<(File, Vec<File>)>,
+}
+
+impl<T: TargetRef> CtxState<T> {
+    /// Creates a new `CtxState` for the given target.
+    pub fn new(target: T) -> Self {
+        Self {
+            target,
+            unused_declared_outputs: SmallSet::new(),
+            phonies: Vec::new(),
+        }
+    }
+
+    /// Declares a new phony build step in the target's build state.
+    pub fn new_phony(&mut self, deps: Vec<File>) -> File {
+        let count = self.phonies.len();
+        let mut path = self.target.target_out_dir("phony/", "", "/:");
+        path.push('_');
+        path.push_str(&count.to_string());
+        let phony = File::intern(&path);
+
+        self.phonies.push((phony.clone(), deps));
+        phony
+    }
+
+    /// Declares a new output file relative to the target's output directory.
+    pub fn declare_file(&mut self, name: &str) -> File {
+        let mut path = self.target.target_out_dir("", "obj/", "/");
+        path.push_str(name);
+        let file = File::intern(&path);
+        self.unused_declared_outputs.insert(file.clone());
+        file
+    }
+}
diff --git a/src/gn/starlark/crates/types/src/errors.rs b/src/gn/starlark/crates/types/src/errors.rs
new file mode 100644
index 0000000..4db276b
--- /dev/null
+++ b/src/gn/starlark/crates/types/src/errors.rs
@@ -0,0 +1,36 @@
+// Copyright 2026 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use starlark::values::UnpackValueError;
+
+use crate::Package;
+
+/// Errors returned by this crate.
+#[derive(thiserror::Error, Debug)]
+pub(crate) enum Error {
+    /// The string is not a valid label (e.g. doesn't start with "//" or ":").
+    #[error("Not a label: {0}")]
+    NotALabel(String),
+    /// An absolute label is invalid (e.g. missing a colon, or has too many colons).
+    #[error("Invalid absolute label, must contain exactly one colon: {0}")]
+    InvalidAbsoluteLabel(String),
+    /// A relative label contains a colon (which is invalid).
+    #[error("Relative label cannot contain a colon: {0}")]
+    ColonInRelativeLabel(String),
+    /// The referenced file does not exist on disk.
+    #[error("File {1} does not exist in {0}")]
+    FileNotFound(Package, String),
+}
+
+impl From<Error> for starlark::Error {
+    fn from(err: Error) -> Self {
+        starlark::Error::new_other(err)
+    }
+}
+
+impl UnpackValueError for Error {
+    fn into_error(this: Self) -> starlark::Error {
+        starlark::Error::new_other(this)
+    }
+}
diff --git a/src/gn/starlark/crates/types/src/eval_context.rs b/src/gn/starlark/crates/types/src/eval_context.rs
new file mode 100644
index 0000000..6f32985
--- /dev/null
+++ b/src/gn/starlark/crates/types/src/eval_context.rs
@@ -0,0 +1,80 @@
+// Copyright 2026 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::{LabelRef, PackageRef, PathResolver, Session};
+
+/// The starlark Evaluator has an "extra" object that you can use to store
+/// whatever metadata you want, accessible to any custom functions you write
+/// in starlark.
+///
+/// This interface contains the specific features we need to access for our
+/// bazel-like API.
+pub trait EvalContext:
+    for<'v> starlark::values::ProvidesStaticType<'v, StaticType = Self>
+    + allocative::Allocative
+    + Send
+    + Sync
+    + 'static
+{
+    /// The session type associated with this context.
+    type Session: Session;
+
+    /// Returns the package currently being evaluated.
+    fn current_package(&self) -> &PackageRef;
+
+    /// Returns the path resolver to map source files to output files.
+    fn path_resolver(&self) -> &PathResolver;
+
+    /// Returns the Starlark session.
+    fn session(&self) -> &Self::Session;
+
+    /// Returns the label of the current toolchain.
+    fn current_toolchain(&self) -> LabelRef<'_>;
+
+    /// Asserts that the current evaluation context is a macro context.
+    /// Use when a function cannot be called from other contexts (eg. `static_library` cannot be called inside rule evaluation)
+    fn require_macro(&self) -> starlark::Result<()>;
+
+    /// Asserts that the current evaluation context is a bzl file context.
+    fn require_bzl(&self) -> starlark::Result<()>;
+
+    /// Asserts that the evaluator is executing a rule implementation, and returns the state of the rule implementation.
+    fn require_rule_impl(
+        &self,
+    ) -> starlark::Result<&crate::CtxState<<Self::Session as Session>::TargetRef>>;
+
+    /// Asserts that the evaluator is executing a rule implementation, and returns the mutable state of the rule implementation.
+    fn require_rule_impl_mut(
+        &mut self,
+    ) -> starlark::Result<&mut crate::CtxState<<Self::Session as Session>::TargetRef>>;
+}
+
+/// Extension trait to add the methods `.context` and `.context_mut` to the starlark Evaluator.
+pub trait EvaluatorContextExt<'v, 'a, 'e> {
+    /// Returns a reference to the evaluation context.
+    fn context<C: EvalContext>(&self) -> &C;
+
+    /// Returns a mutable reference to the evaluation context.
+    fn context_mut<C: EvalContext>(&mut self) -> &mut C;
+}
+
+impl<'v, 'a, 'e> EvaluatorContextExt<'v, 'a, 'e> for starlark::eval::Evaluator<'v, 'a, 'e> {
+    #[inline]
+    fn context<C: EvalContext>(&self) -> &C {
+        let extra = self.extra_mut.as_ref();
+        debug_assert!(extra.is_some(), "evaluator context not set");
+        let dyn_any = unsafe { extra.unwrap_unchecked() };
+        debug_assert!(dyn_any.is::<C>(), "failed to downcast evaluator context");
+        unsafe { dyn_any.downcast_ref::<C>().unwrap_unchecked() }
+    }
+
+    #[inline]
+    fn context_mut<C: EvalContext>(&mut self) -> &mut C {
+        let extra = self.extra_mut.as_mut();
+        debug_assert!(extra.is_some(), "evaluator context not set");
+        let dyn_any = unsafe { extra.unwrap_unchecked() };
+        debug_assert!(dyn_any.is::<C>(), "failed to downcast evaluator context");
+        unsafe { dyn_any.downcast_mut::<C>().unwrap_unchecked() }
+    }
+}
diff --git a/src/gn/starlark/crates/types/src/file.rs b/src/gn/starlark/crates/types/src/file.rs
new file mode 100644
index 0000000..4cade31
--- /dev/null
+++ b/src/gn/starlark/crates/types/src/file.rs
@@ -0,0 +1,250 @@
+// Copyright 2026 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::borrow::Cow;
+use std::path::Path;
+
+use starlark::collections::StarlarkHasher;
+use starlark::environment::Methods;
+use starlark::environment::MethodsBuilder;
+use starlark::environment::MethodsStatic;
+use starlark::starlark_simple_value;
+use starlark::values::Freeze;
+use starlark::values::FreezeResult;
+use starlark::values::Freezer;
+use starlark::values::ProvidesStaticType;
+use starlark::values::StarlarkValue;
+use starlark::values::Trace;
+use starlark::values::Tracer;
+use starlark::values::ValueLike;
+use starlark_derive::starlark_module;
+use starlark_derive::starlark_value;
+use starlark_derive::NoSerialize;
+
+/// File is equivalent to GN's OutputFile. Like OutputFile, its path is relative
+/// to the root_build_dir (which is also the execution directory).
+///
+/// Unlike GN, we don't distinguish between SourceFile and OutputFile.
+/// All Files are OutputFiles, and thus we simply call it "File".
+///
+/// For example, if the root_build_dir is out/Default, then the path
+/// foo/bar.cc relative to the source root would be represented as
+/// ../../foo/bar.cc
+///
+/// It is an interned string (via StringAtom) and thus is safely 'static.
+///
+/// We use a &str instead of an &Path, as would be standard in rust, because:
+/// * Path::new(&str) is a zero cost transmute and always succeeds
+/// * Path::new(&str).to_string_lossy() always returns the input str but has to perform an error check.
+#[derive(Clone, Debug, ProvidesStaticType, NoSerialize, allocative::Allocative)]
+pub struct File(#[allocative(skip)] &'static str);
+
+starlark_simple_value!(File);
+
+impl File {
+    /// Creates a `File` from a string representing a path.
+    /// The path is relative to the root_build_dir.
+    pub fn new(path: &'static str) -> Self {
+        Self(path)
+    }
+
+    /// Creates a `File` by interning a string representing a path.
+    /// The path is relative to the root_build_dir.
+    pub fn intern(s: &str) -> Self {
+        extern "C" {
+            fn intern_string(s: &str) -> &'static str;
+        }
+        // Safety: Just an ffi function
+        Self(unsafe { intern_string(s) })
+    }
+
+    /// Returns the file path relative to the root_build_dir.
+    pub fn as_path(&self) -> &'static Path {
+        // Note: This is a zero-cost operation.
+        // It's basically just a reinterpret cast.
+        Path::new(self.0)
+    }
+
+    /// Returns the file path relative to the root_build_dir as a &str.
+    pub fn as_str(&self) -> &'static str {
+        self.0
+    }
+
+    /// Returns the file path with proper escaping applied for use in the inputs section of a ninja file.
+    pub fn ninja_escaped_path(&self) -> Cow<'static, str> {
+        let s = self.0;
+        if s.contains(|c| c == ' ' || c == '$' || c == ':') {
+            let mut result = String::with_capacity(s.len());
+            for c in s.chars() {
+                if c == '$' || c == ' ' || c == ':' {
+                    result.push('$');
+                }
+                result.push(c);
+            }
+            Cow::Owned(result)
+        } else {
+            Cow::Borrowed(s)
+        }
+    }
+}
+
+// Because we do string interning, we can make PartialEq and Hashing based on
+// pointers, making storing files in depsets extremely fast.
+impl PartialEq for File {
+    fn eq(&self, other: &Self) -> bool {
+        std::ptr::eq(self.0, other.0)
+    }
+}
+impl Eq for File {}
+
+impl std::hash::Hash for File {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        std::ptr::hash(self.0, state);
+    }
+}
+
+impl std::fmt::Display for File {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{}", self.0)
+    }
+}
+
+unsafe impl<'v> Trace<'v> for File {
+    fn trace(&mut self, _tracer: &Tracer<'v>) {}
+}
+
+impl Freeze for File {
+    type Frozen = File;
+    fn freeze(self, _freezer: &Freezer) -> FreezeResult<Self::Frozen> {
+        Ok(self)
+    }
+}
+
+#[starlark_value(type = "File")]
+impl<'v> StarlarkValue<'v> for File {
+    fn get_methods() -> Option<&'static Methods>
+    where
+        Self: Sized,
+    {
+        static RES: MethodsStatic = MethodsStatic::new("File", file_methods);
+        Some(RES.methods())
+    }
+
+    fn write_hash(&self, hasher: &mut StarlarkHasher) -> starlark::Result<()> {
+        use std::hash::Hash;
+        self.hash(hasher);
+        Ok(())
+    }
+
+    fn equals(&self, other: starlark::values::Value<'v>) -> starlark::Result<bool> {
+        Ok(other.downcast_ref::<File>().is_some_and(|o| self == o))
+    }
+
+    fn collect_repr(&self, collector: &mut String) {
+        use std::fmt::Write;
+        write!(collector, "{:?}", self).unwrap();
+    }
+
+    fn collect_str(&self, collector: &mut String) {
+        use std::fmt::Write;
+        write!(collector, "{}", self).unwrap();
+    }
+}
+
+#[starlark_module]
+fn file_methods(methods: &mut MethodsBuilder) {
+    #[starlark(attribute)]
+    fn basename<'v>(this: &'v File) -> starlark::Result<&'static str> {
+        Ok(this
+            .as_path()
+            .file_name()
+            .and_then(|s| s.to_str())
+            .unwrap_or(""))
+    }
+
+    #[starlark(attribute)]
+    fn dirname<'v>(this: &'v File) -> starlark::Result<&'static str> {
+        Ok(this
+            .as_path()
+            .parent()
+            .and_then(|s| s.to_str())
+            .unwrap_or(""))
+    }
+
+    #[starlark(attribute)]
+    fn extension<'v>(this: &'v File) -> starlark::Result<&'static str> {
+        Ok(this
+            .as_path()
+            .extension()
+            .and_then(|s| s.to_str())
+            .unwrap_or(""))
+    }
+
+    #[starlark(attribute)]
+    fn is_source(this: &File) -> starlark::Result<bool> {
+        Ok(this.as_path().starts_with(".."))
+    }
+
+    #[starlark(attribute)]
+    fn path<'v>(this: &'v File) -> starlark::Result<&'static str> {
+        Ok(this.0)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_file_interning() {
+        let f1 = File::intern("foo/bar.txt");
+        let f2 = File::intern("foo/bar.txt");
+
+        assert_eq!(f1.as_str(), "foo/bar.txt");
+        // Verify pointer equality (they point to the exact same static string backing memory)
+        assert!(std::ptr::eq(f1.as_str(), f2.as_str()));
+    }
+
+    #[test]
+    fn test_file_equality() {
+        let f1 = File::intern("foo/bar.txt");
+        let f2 = File::intern("foo/bar.txt");
+        let f3 = File::intern("other.txt");
+
+        assert_eq!(f1, f2);
+        assert_ne!(f1, f3);
+    }
+
+    #[test]
+    fn test_file_starlark_api() {
+        let mut a = starlark::assert::Assert::new();
+        a.globals_add(move |builder| {
+            builder.set("source_file", File::intern("../foo/bar/baz.txt"));
+            builder.set("generated_file", File::intern("foo/bar/baz.txt"));
+        });
+        a.eq("source_file.basename", "\"baz.txt\"");
+        a.eq("source_file.dirname", "\"../foo/bar\"");
+        a.eq("source_file.extension", "\"txt\"");
+        a.eq("source_file.is_source", "True");
+        a.eq("source_file.path", "\"../foo/bar/baz.txt\"");
+        a.eq("str(source_file)", "\"../foo/bar/baz.txt\"");
+        a.eq("repr(source_file)", "'File(\"../foo/bar/baz.txt\")'");
+
+        a.eq("generated_file.basename", "\"baz.txt\"");
+        a.eq("generated_file.dirname", "\"foo/bar\"");
+        a.eq("generated_file.extension", "\"txt\"");
+        a.eq("generated_file.is_source", "False");
+        a.eq("generated_file.path", "\"foo/bar/baz.txt\"");
+        a.eq("str(generated_file)", "\"foo/bar/baz.txt\"");
+        a.eq("repr(generated_file)", "'File(\"foo/bar/baz.txt\")'");
+    }
+}
+
+#[allow(dead_code)]
+fn dummy_to_force_cxx_linking() {
+    // The C++ code depends on the cxx crate being linked for the rust::Str type.
+    // Because the rust code doesn't depend on the cxx crate, we need a dummy
+    // function that uses some part of cxx to ensure it links.
+    drop(cxx::UniquePtr::<cxx::CxxString>::null());
+}
diff --git a/src/gn/starlark/crates/types/src/label.rs b/src/gn/starlark/crates/types/src/label.rs
new file mode 100644
index 0000000..73c27ce
--- /dev/null
+++ b/src/gn/starlark/crates/types/src/label.rs
@@ -0,0 +1,248 @@
+// Copyright 2026 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use starlark::collections::StarlarkHasher;
+use starlark::environment::Methods;
+use starlark::environment::MethodsBuilder;
+use starlark::environment::MethodsStatic;
+use starlark::starlark_simple_value;
+use starlark::values::Freeze;
+use starlark::values::FreezeResult;
+use starlark::values::Freezer;
+use starlark::values::ProvidesStaticType;
+use starlark::values::StarlarkValue;
+use starlark::values::Trace;
+use starlark::values::Tracer;
+use starlark::values::ValueLike;
+use starlark_derive::starlark_module;
+use starlark_derive::starlark_value;
+use starlark_derive::NoSerialize;
+
+use crate::LabelRef;
+use crate::Package;
+use crate::PackageRef;
+
+/// A Label represents a target label, e.g., "//foo/bar:baz".
+/// Note that unlike a regular GN label, this label does *not* include a toolchain.
+///
+/// In Starlark, a fully qualified GN label is represented as a tuple
+/// (label, toolchain). "//foo:bar(//toolchain:name)" would thus convert to
+/// (Label("//foo:bar"), Label("//toolchain:name")).
+#[derive(Clone, Eq, PartialEq, Hash, ProvidesStaticType, NoSerialize, allocative::Allocative)]
+pub struct Label {
+    /// The package part of the label.
+    package: Package,
+    /// The name part of the label.
+    name: String,
+}
+
+starlark_simple_value!(Label);
+
+impl Label {
+    /// Creates a new `Label`.
+    pub fn new(package: Package, name: String) -> Self {
+        Self { package, name }
+    }
+
+    /// Returns a `LabelRef` referencing the data inside this label.
+    pub fn as_ref(&self) -> LabelRef<'_> {
+        LabelRef {
+            package: &self.package,
+            name: &self.name,
+        }
+    }
+
+    /// Returns the package of this label.
+    pub fn package(&self) -> &PackageRef {
+        &self.package
+    }
+
+    /// Returns the name of this label.
+    pub fn name(&self) -> &str {
+        &self.name
+    }
+
+    /// Parses a label guaranteed to start with a "//"
+    pub(crate) fn parse_absolute(s: &str) -> starlark::Result<Self> {
+        let mut iter = s.split(':');
+        // Verify that there is exactly one colon.
+        match (iter.next(), iter.next(), iter.next()) {
+            (Some(package), Some(name), None) if !name.is_empty() => Ok(Label {
+                // Safety: already checked.
+                package: unsafe { PackageRef::new_unchecked(package) }.to_owned(),
+                name: name.to_owned(),
+            }),
+            // In GN, this refers to the file foo in the // directory in file
+            // contexts, and //foo:foo in label contexts.
+            // In Bazel, files and labels can be mixed, and thus it always
+            // resolves to the label //foo:foo.
+            // We explicitly ban this syntax to reduce confusion.
+            // We may choose to change this later, but it's easier to allow
+            // previously banned things than to ban previously allowed things.
+            _ => Err(crate::Error::InvalidAbsoluteLabel(s.to_owned()).into()),
+        }
+    }
+
+    /// Parses a label guaranteed to start with a ":"
+    pub(crate) fn parse_relative(s: &str, relative_to: &PackageRef) -> starlark::Result<Self> {
+        let name = &s[1..];
+        if name.is_empty() {
+            return Err(crate::Error::NotALabel(s.to_owned()).into());
+        }
+        if name.contains(':') {
+            return Err(crate::Error::ColonInRelativeLabel(s.to_owned()).into());
+        }
+        Ok(Label {
+            package: relative_to.to_owned(),
+            name: name.to_owned(),
+        })
+    }
+
+    /// Parses a label. If it is relative, it is parsed as relative to the given package.
+    pub fn parse(s: &str, relative_to: &PackageRef) -> starlark::Result<Self> {
+        if s.starts_with("//") {
+            Self::parse_absolute(s)
+        } else if s.starts_with(':') {
+            Self::parse_relative(s, relative_to)
+        } else {
+            Err(crate::Error::NotALabel(s.to_owned()).into())
+        }
+    }
+
+    /// Same as parse, but if it doesn't start with "//" or ":", returns None
+    /// instead of erroring out.
+    pub fn parse_maybe_label(s: &str, relative_to: &PackageRef) -> starlark::Result<Option<Self>> {
+        Ok(if s.starts_with("//") {
+            Some(Self::parse_absolute(s)?)
+        } else if s.starts_with(':') {
+            Some(Self::parse_relative(s, relative_to)?)
+        } else {
+            None
+        })
+    }
+}
+
+impl std::fmt::Display for Label {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{}", self.as_ref())
+    }
+}
+
+impl std::fmt::Debug for Label {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        std::fmt::Debug::fmt(&self.as_ref(), f)
+    }
+}
+
+unsafe impl<'v> Trace<'v> for Label {
+    fn trace(&mut self, _tracer: &Tracer<'v>) {}
+}
+
+impl Freeze for Label {
+    type Frozen = Label;
+    fn freeze(self, _freezer: &Freezer) -> FreezeResult<Self::Frozen> {
+        Ok(self)
+    }
+}
+
+#[starlark_value(type = "Label")]
+impl<'v> StarlarkValue<'v> for Label {
+    fn get_methods() -> Option<&'static Methods>
+    where
+        Self: Sized,
+    {
+        static RES: MethodsStatic = MethodsStatic::new("Label", label_methods);
+        Some(RES.methods())
+    }
+
+    fn write_hash(&self, hasher: &mut StarlarkHasher) -> starlark::Result<()> {
+        use std::hash::Hash;
+        self.hash(hasher);
+        Ok(())
+    }
+
+    fn equals(&self, other: starlark::values::Value<'v>) -> starlark::Result<bool> {
+        Ok(other.downcast_ref::<Label>().is_some_and(|o| self == o))
+    }
+
+    fn collect_repr(&self, collector: &mut String) {
+        use std::fmt::Write;
+        write!(collector, "{:?}", self.as_ref()).unwrap();
+    }
+
+    fn collect_str(&self, collector: &mut String) {
+        use std::fmt::Write;
+        write!(collector, "{}", self.as_ref()).unwrap();
+    }
+}
+
+#[starlark_module]
+fn label_methods(methods: &mut MethodsBuilder) {
+    #[starlark(attribute)]
+    fn package<'v>(this: &'v Label) -> starlark::Result<&'v str> {
+        Ok(this.package.as_str())
+    }
+
+    #[starlark(attribute)]
+    fn name<'v>(this: &'v Label) -> starlark::Result<&'v str> {
+        Ok(&this.name)
+    }
+}
+
+// Note: We intentionally *do not* expose a Label() constructor to starlark.
+// Where the label is relative to is confusing for the average user.
+// Instead, if we need this in the future, we may expose:
+// * native.package_relative_label() for macros
+// * ctx.package_relative_label() for rules
+// * Label() for build files only.
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_label_parsing() {
+        let current_pkg = PackageRef::new_for_testing("//foo/bar");
+
+        let lbl = Label::parse("//foo/bar:baz", PackageRef::root()).unwrap();
+        assert_eq!(lbl.to_string(), "//foo/bar:baz");
+
+        let lbl2 = Label::parse(":baz", current_pkg).unwrap();
+        assert_eq!(lbl2.to_string(), "//foo/bar:baz");
+
+        // Test non-absolute and non-colon starting fails
+        assert!(Label::parse("foo", current_pkg).is_err());
+        assert!(Label::parse(":", current_pkg).is_err());
+        assert!(Label::parse("//foo/bar:", current_pkg).is_err());
+    }
+
+    #[test]
+    fn test_label_attributes() {
+        let lbl = Label::parse("//foo/bar:baz", PackageRef::root()).unwrap();
+        assert_eq!(
+            lbl.package.as_ref(),
+            PackageRef::new_for_testing("//foo/bar")
+        );
+        assert_eq!(lbl.name, "baz");
+        assert_eq!(format!("{:?}", lbl), "Label(\"//foo/bar:baz\")");
+    }
+
+    #[test]
+    fn test_label_starlark_api() {
+        let mut a = starlark::assert::Assert::new();
+        a.globals_add(move |builder| {
+            builder.set(
+                "my_label",
+                Label::new(
+                    PackageRef::new_for_testing("//foo/bar").to_owned(),
+                    "baz".to_owned(),
+                ),
+            );
+        });
+        a.eq("my_label.package", "\"//foo/bar\"");
+        a.eq("my_label.name", "\"baz\"");
+        a.eq("str(my_label)", "\"//foo/bar:baz\"");
+        a.eq("repr(my_label)", "'Label(\"//foo/bar:baz\")'");
+    }
+}
diff --git a/src/gn/starlark/crates/types/src/label_ref.rs b/src/gn/starlark/crates/types/src/label_ref.rs
new file mode 100644
index 0000000..892d215
--- /dev/null
+++ b/src/gn/starlark/crates/types/src/label_ref.rs
@@ -0,0 +1,54 @@
+// Copyright 2026 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::Label;
+use crate::PackageRef;
+
+/// A borrowed reference to a `Label`.
+///
+/// We implement this instead of using &Label, because this allows us to
+/// convert C++ labels to rust labels without any copying.
+#[derive(Copy, Clone, Eq, PartialEq, Hash)]
+pub struct LabelRef<'a> {
+    /// The package part of the label reference.
+    pub(crate) package: &'a PackageRef,
+    /// The name part of the label reference.
+    pub(crate) name: &'a str,
+}
+
+impl<'a> LabelRef<'a> {
+    /// Returns the package of this label reference.
+    pub fn package(&self) -> &PackageRef {
+        self.package
+    }
+
+    /// Returns the name of this label reference.
+    pub fn name(&self) -> &str {
+        self.name
+    }
+}
+
+impl<'a> std::fmt::Display for LabelRef<'a> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{}:{}", self.package, self.name)
+    }
+}
+
+impl<'a> std::fmt::Debug for LabelRef<'a> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "Label(\"{}:{}\")", self.package, self.name)
+    }
+}
+
+impl<'a> LabelRef<'a> {
+    /// Creates a new `LabelRef`.
+    pub fn new(package: &'a PackageRef, name: &'a str) -> Self {
+        Self { package, name }
+    }
+
+    /// Converts this reference into an owned `Label`.
+    pub fn to_owned(&self) -> Label {
+        Label::new(self.package.to_owned(), self.name.to_owned())
+    }
+}
diff --git a/src/gn/starlark/crates/types/src/lib.rs b/src/gn/starlark/crates/types/src/lib.rs
new file mode 100644
index 0000000..c43dd5f
--- /dev/null
+++ b/src/gn/starlark/crates/types/src/lib.rs
@@ -0,0 +1,28 @@
+// Copyright 2026 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+pub mod ctx_state;
+pub mod errors;
+pub mod eval_context;
+pub mod file;
+pub mod label;
+pub mod label_ref;
+pub mod package;
+pub mod package_ref;
+pub mod path_resolver;
+pub mod session;
+pub mod target_ref;
+pub mod util;
+
+pub use ctx_state::CtxState;
+pub(crate) use errors::Error;
+pub use eval_context::{EvalContext, EvaluatorContextExt};
+pub use file::File;
+pub use label::Label;
+pub use label_ref::LabelRef;
+pub use package::Package;
+pub use package_ref::PackageRef;
+pub use path_resolver::PathResolver;
+pub use session::Session;
+pub use target_ref::TargetRef;
diff --git a/src/gn/starlark/crates/types/src/package.rs b/src/gn/starlark/crates/types/src/package.rs
new file mode 100644
index 0000000..76876c7
--- /dev/null
+++ b/src/gn/starlark/crates/types/src/package.rs
@@ -0,0 +1,42 @@
+// Copyright 2026 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::PackageRef;
+
+/// A package, conceptually, is a directory in the source tree.
+/// Always prefer &PackageRef over Package to avoid copies.
+///
+/// It represents the same concept as a SourceDir, but differs in its internal
+/// representation: unlike SourceDir, it *never* ends with a '/'.
+///
+/// A package *always* starts with //, and may be either the root package "//",
+/// or a subdirectory "//foo/bar".
+#[derive(Debug, Clone, Eq, PartialEq, Hash, allocative::Allocative)]
+pub struct Package(pub(crate) String);
+
+impl std::ops::Deref for Package {
+    type Target = PackageRef;
+    fn deref(&self) -> &Self::Target {
+        // Safety: already validated
+        unsafe { PackageRef::new_unchecked(&self.0) }
+    }
+}
+
+impl AsRef<PackageRef> for Package {
+    fn as_ref(&self) -> &PackageRef {
+        self
+    }
+}
+
+impl std::borrow::Borrow<PackageRef> for Package {
+    fn borrow(&self) -> &PackageRef {
+        self
+    }
+}
+
+impl std::fmt::Display for Package {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{}", self.as_str())
+    }
+}
diff --git a/src/gn/starlark/crates/types/src/package_ref.rs b/src/gn/starlark/crates/types/src/package_ref.rs
new file mode 100644
index 0000000..9f80e42
--- /dev/null
+++ b/src/gn/starlark/crates/types/src/package_ref.rs
@@ -0,0 +1,65 @@
+// Copyright 2026 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::Package;
+
+/// &PackageRef is to Package as &str is to String.
+#[repr(transparent)]
+#[derive(Debug, Eq, PartialEq, Hash)]
+pub struct PackageRef(str);
+
+impl PackageRef {
+    // Creates a PackageRef for the root package "//"
+    pub fn root() -> &'static Self {
+        // Safety: "//" is a valid package.
+        unsafe { Self::new_unchecked("//") }
+    }
+
+    /// Creates a new `PackageRef` for testing purposes.
+    /// Not #[cfg(test)] because we use it in tests for downstream crates.
+    pub fn new_for_testing(s: &str) -> &Self {
+        assert!(s.starts_with("//"), "Package name must start with //");
+        // Safety: checked above
+        unsafe { Self::new_unchecked(s) }
+    }
+
+    /// Creates a new `PackageRef` from a string slice.
+    ///
+    /// Requires that the string starts with "//"
+    pub unsafe fn new_unchecked(s: &str) -> &Self {
+        debug_assert!(s.starts_with("//"), "Package name must start with //");
+        // Safety: PackageRef is #[repr(transparent)] wrapping str, so their memory layouts are identical.
+        unsafe { &*(s as *const str as *const PackageRef) }
+    }
+
+    /// Returns the full package name, eg. "//foo/bar"
+    pub fn as_str(&self) -> &str {
+        &self.0
+    }
+
+    /// Returns the path to the package relative to the root source dir
+    /// (e.g., "//foo/bar" => "foo/bar")
+    pub fn as_source_relative(&self) -> &str {
+        &self.0[2..]
+    }
+
+    /// Returns true if this is the root package ("//").
+    pub fn is_root(&self) -> bool {
+        // We have an invariant that all packages must start with "//"
+        self.0.len() == 2
+    }
+}
+
+impl std::fmt::Display for PackageRef {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{}", &self.0)
+    }
+}
+
+impl ToOwned for PackageRef {
+    type Owned = Package;
+    fn to_owned(&self) -> Self::Owned {
+        Package(self.0.to_owned())
+    }
+}
diff --git a/src/gn/starlark/crates/types/src/path_resolver.rs b/src/gn/starlark/crates/types/src/path_resolver.rs
new file mode 100644
index 0000000..ae1aad0
--- /dev/null
+++ b/src/gn/starlark/crates/types/src/path_resolver.rs
@@ -0,0 +1,62 @@
+// Copyright 2026 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use std::path::PathBuf;
+
+use crate::{File, PackageRef};
+
+/// Resolves paths to Files relative to the root_build_dir.
+#[derive(Clone, Debug)]
+pub struct PathResolver {
+    /// Absolute path to the root source dir on disk.
+    source_root: PathBuf,
+    /// Path to the root source dir relative to the root_build_dir.
+    /// *Must* end with a trailing slash.
+    source_root_rel: String,
+}
+
+impl PathResolver {
+    /// Creates a new `PathResolver` with the given absolute and relative root paths.
+    pub fn new(source_root: PathBuf, source_root_rel: String) -> Self {
+        assert!(source_root_rel.ends_with('/'));
+        Self {
+            source_root,
+            source_root_rel,
+        }
+    }
+
+    /// Creates a new PathResolver preconfigured for the starlark testdata directory.
+    pub fn new_for_testing() -> Self {
+        Self::new(
+            PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../src/testdata"),
+            "../../".to_string(),
+        )
+    }
+
+    /// Calculates where the file should exist on disk.
+    pub fn absolute_path(&self, pkg: &PackageRef, s: &str) -> PathBuf {
+        self.source_root.join(pkg.as_source_relative()).join(s)
+    }
+
+    /// Creates a `File` object for a file path relative to a package.
+    /// Validates that the file exists on disk.
+    pub fn source_file(&self, pkg: &PackageRef, s: &str) -> starlark::Result<File> {
+        // Gn *does not* check that the files you refer to exist on disk.
+        // This is because native GN allows referencing generated files that do
+        // not yet exist at `gn gen` time.
+        // We explicitly disallow referencing generated files in starlark, so
+        // we should validate that the files exist on disk for correctness.
+        let abs_path = self.absolute_path(pkg, s);
+        if !abs_path.exists() {
+            return Err(crate::Error::FileNotFound(pkg.to_owned(), s.to_owned()).into());
+        }
+        let pkg_dir = pkg.as_source_relative();
+        let rel_path = if pkg.is_root() {
+            format!("{}{s}", self.source_root_rel)
+        } else {
+            format!("{}{pkg_dir}/{s}", self.source_root_rel)
+        };
+        Ok(File::intern(&rel_path))
+    }
+}
diff --git a/src/gn/starlark/crates/types/src/session.rs b/src/gn/starlark/crates/types/src/session.rs
new file mode 100644
index 0000000..863dcb6
--- /dev/null
+++ b/src/gn/starlark/crates/types/src/session.rs
@@ -0,0 +1,22 @@
+// Copyright 2026 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::{LabelRef, TargetRef};
+
+/// An interface for the starlark session.
+pub trait Session {
+    /// The target type managed by this session.
+    type TargetRef: TargetRef;
+
+    /// Look up a target in the session by its label and current toolchain.
+    fn get_target(&self, label: LabelRef<'_>, toolchain: LabelRef<'_>) -> Self::TargetRef;
+
+    /// Registers a dependency from `source` to (label, toolchain).
+    fn register_dependency<'a>(
+        &self,
+        source: Self::TargetRef,
+        label: LabelRef<'a>,
+        toolchain: LabelRef<'a>,
+    );
+}
diff --git a/src/gn/starlark/crates/types/src/target_ref.rs b/src/gn/starlark/crates/types/src/target_ref.rs
new file mode 100644
index 0000000..f418bce
--- /dev/null
+++ b/src/gn/starlark/crates/types/src/target_ref.rs
@@ -0,0 +1,26 @@
+// Copyright 2026 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+use crate::File;
+use starlark::values::{AllocValue, StarlarkValue};
+
+/// An interface for a target in the build graph.
+///
+/// Since the real Target involves a lot of C++ interop, this allows us to
+/// decouple the target from C++
+pub trait TargetRef: for<'v> StarlarkValue<'v> + for<'v> AllocValue<'v> + Clone {
+    /// Returns the output files produced by this target.
+    fn outputs(&self) -> Vec<File>;
+
+    /// Returns the target's output directory path string.
+    /// Toolchain_prefix goes right at the very front, before the toolchain
+    /// Label_prefix goes in between the toolchain and the label
+    /// Package_name_separator is what separates packages and labels (usually ":" or "/").
+    fn target_out_dir(
+        &self,
+        toolchain_prefix: &str,
+        label_prefix: &str,
+        package_name_separator: &str,
+    ) -> String;
+}
diff --git a/src/gn/starlark/crates/types/src/util.rs b/src/gn/starlark/crates/types/src/util.rs
new file mode 100644
index 0000000..b5729b4
--- /dev/null
+++ b/src/gn/starlark/crates/types/src/util.rs
@@ -0,0 +1,9 @@
+// Copyright 2026 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/// Like std::mem::transmute, but can only affect lifetime.
+pub unsafe fn extend_lifetime<'to, 'from, T: ?Sized>(val: &'from T) -> &'to T {
+    // Safety: None - this function is marked unsafe.
+    unsafe { std::mem::transmute(val) }
+}