Something went wrong. Try again.
Reggie, the experimental Gleam -> WASM compiler (mirror) reggie.desertthunder.dev
wasm compiler rust gleam
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976use std::collections::HashMap;
use crate::source::{SourceFileId, Span};use crate::types::{ConstructorInfo, FieldInfo, ModuleInterface, Type, TypeDeclaration};
const STDLIB_SPAN: Span = Span { file_id: SourceFileId(u32::MAX), start: 0, end: 0 };
#[derive(Debug, Clone, Copy, PartialEq, Eq)]pub enum ModuleStrategy { Hybrid, PreferCompiledSource,}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]pub enum RetentionCategory { TemporaryInterface, UpstreamSource, PackageAsset, RuntimePrimitive, TargetHostAdapter,}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]pub enum RetentionGap { SourceLanguageFeature, TargetFiltering, PackageMetadata, PackageAsset, RuntimePrimitive, HostAbi,}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]pub struct RegistryRetention { pub category: RetentionCategory, pub gap: RetentionGap, pub deletion_condition: &'static str,}
#[derive(Debug, Clone, PartialEq, Eq)]pub struct StdlibMember { pub name: &'static str, pub retention: RegistryRetention,}
#[derive(Debug, Clone, PartialEq, Eq)]pub struct StdlibModule { pub name: &'static str, pub strategy: ModuleStrategy, pub retention: RegistryRetention, pub interface: ModuleInterface, pub members: Vec<StdlibMember>,}
#[derive(Debug, Clone, PartialEq, Eq)]pub struct StdlibRegistry { modules: HashMap<&'static str, StdlibModule>,}
impl StdlibRegistry { pub fn new() -> Self { Self { modules: stdlib_modules() .into_iter() .map(|module| (module.name, module)) .collect(), } }
pub fn module(&self, name: &str) -> Option<&StdlibModule> { self.modules.get(name) }
pub fn interface(&self, name: &str) -> Option<&ModuleInterface> { self.module(name).map(|module| &module.interface) }
pub fn member_retention(&self, module: &str, member: &str) -> Option<RegistryRetention> { self.module(module)? .members .iter() .find(|entry| entry.name == member) .map(|entry| entry.retention) }
pub fn modules(&self) -> impl Iterator<Item = &StdlibModule> { self.modules.values() }}
impl Default for StdlibRegistry { fn default() -> Self { Self::new() }}
fn stdlib_modules() -> Vec<StdlibModule> { vec![ StdlibModule::gleam_io(), StdlibModule::gleam_int(), StdlibModule::gleam_string(), StdlibModule::gleam_list(), StdlibModule::gleam_result(), StdlibModule::gleam_option(), StdlibModule::gleam_order(), StdlibModule::gleam_bit_array(), StdlibModule::gleam_bool(), StdlibModule::remaining("gleam/bytes_tree", RetentionGap::PackageMetadata), StdlibModule::gleam_dict(), StdlibModule::gleam_dynamic(), StdlibModule::gleam_dynamic_decode(), StdlibModule::gleam_float(), StdlibModule::gleam_function(), StdlibModule::remaining("gleam/set", RetentionGap::TargetFiltering), StdlibModule::remaining("gleam/string_tree", RetentionGap::PackageAsset), StdlibModule::remaining("gleam/uri", RetentionGap::PackageMetadata), ]}
impl StdlibModule { fn gleam_io() -> Self { Self::new( "gleam/io", ModuleStrategy::Hybrid, module_retention(RetentionGap::HostAbi), &[ function("println", vec![Type::String], Type::Nil, host_adapter_retention()), function("print", vec![Type::String], Type::Nil, host_adapter_retention()), function( "debug", vec![Type::generic("a")], Type::generic("a"), upstream_source_retention(), ), ], &[], ) }
fn gleam_int() -> Self { Self::new( "gleam/int", ModuleStrategy::Hybrid, module_retention(RetentionGap::PackageMetadata), &[ function("to_string", vec![Type::Int], Type::String, upstream_source_retention()), function( "parse", vec![Type::String], result(Type::Int, Type::Nil), temporary_interface_retention(), ), ], &[], ) }
fn gleam_string() -> Self { Self::new( "gleam/string", ModuleStrategy::Hybrid, module_retention(RetentionGap::PackageMetadata), &[ function( "append", vec![Type::String, Type::String], Type::String, runtime_primitive_retention(), ), function( "concat", vec![Type::List(Box::new(Type::String))], Type::String, runtime_primitive_retention(), ), function("length", vec![Type::String], Type::Int, runtime_primitive_retention()), function( "is_empty", vec![Type::String], Type::Bool, runtime_primitive_retention(), ), ], &[], ) }
fn gleam_list() -> Self { Self::new( "gleam/list", ModuleStrategy::Hybrid, module_retention(RetentionGap::PackageMetadata), &[ function( "length", vec![Type::List(Box::new(Type::generic("a")))], Type::Int, upstream_source_retention(), ), function( "reverse", vec![Type::List(Box::new(Type::generic("a")))], list(Type::generic("a")), upstream_source_retention(), ), function( "map", vec![ list(Type::generic("a")), fn_type(vec![Type::generic("a")], Type::generic("b")), ], list(Type::generic("b")), upstream_source_retention(), ), function( "fold", vec![ list(Type::generic("a")), Type::generic("b"), fn_type(vec![Type::generic("b"), Type::generic("a")], Type::generic("b")), ], Type::generic("b"), upstream_source_retention(), ), ], &[], ) }
fn gleam_result() -> Self { let result_type = type_decl( "Result", vec!["a", "e"], false, vec![ constructor( "Ok", vec![FieldInfo::new("value".to_string(), Type::generic("a"))], result(Type::generic("a"), Type::generic("e")), ), constructor( "Error", vec![FieldInfo::new("reason".to_string(), Type::generic("e"))], result(Type::generic("a"), Type::generic("e")), ), ], ); Self::new( "gleam/result", ModuleStrategy::Hybrid, module_retention(RetentionGap::PackageMetadata), &[ constructor_member("Ok"), constructor_member("Error"), function( "map", vec![ result(Type::generic("a"), Type::generic("e")), fn_type(vec![Type::generic("a")], Type::generic("b")), ], result(Type::generic("b"), Type::generic("e")), upstream_source_retention(), ), ], &[result_type], ) }
fn gleam_option() -> Self { let option_type = type_decl( "Option", vec!["a"], false, vec![ constructor( "Some", vec![FieldInfo::new("value".to_string(), Type::generic("a"))], option(Type::generic("a")), ), constructor("None", vec![], option(Type::generic("a"))), ], ); Self::new( "gleam/option", ModuleStrategy::Hybrid, module_retention(RetentionGap::PackageAsset), &[ constructor_member("Some"), constructor_member("None"), function( "map", vec![ option(Type::generic("a")), fn_type(vec![Type::generic("a")], Type::generic("b")), ], option(Type::generic("b")), upstream_source_retention(), ), ], &[option_type], ) }
fn gleam_order() -> Self { let order_type = type_decl( "Order", vec![], false, vec![ constructor("Lt", vec![], Type::custom("Order", vec![])), constructor("Eq", vec![], Type::custom("Order", vec![])), constructor("Gt", vec![], Type::custom("Order", vec![])), ], ); Self::new( "gleam/order", ModuleStrategy::Hybrid, module_retention(RetentionGap::SourceLanguageFeature), &[ constructor_member("Lt"), constructor_member("Eq"), constructor_member("Gt"), ], &[order_type], ) }
fn gleam_bit_array() -> Self { Self::new( "gleam/bit_array", ModuleStrategy::Hybrid, module_retention(RetentionGap::TargetFiltering), &[ function( "append", vec![Type::BitArray, Type::BitArray], Type::BitArray, runtime_primitive_retention(), ), function( "concat", vec![Type::List(Box::new(Type::BitArray))], Type::BitArray, runtime_primitive_retention(), ), function( "bit_size", vec![Type::BitArray], Type::Int, runtime_primitive_retention(), ), function( "byte_size", vec![Type::BitArray], Type::Int, runtime_primitive_retention(), ), function( "is_empty", vec![Type::BitArray], Type::Bool, runtime_primitive_retention(), ), function( "starts_with", vec![Type::BitArray, Type::BitArray], Type::Bool, runtime_primitive_retention(), ), ], &[], ) }
fn gleam_bool() -> Self { Self::new( "gleam/bool", ModuleStrategy::Hybrid, module_retention(RetentionGap::SourceLanguageFeature), &[ function("to_string", vec![Type::Bool], Type::String, upstream_source_retention()), function("negate", vec![Type::Bool], Type::Bool, upstream_source_retention()), function( "compare", vec![Type::Bool, Type::Bool], Type::custom("Order", vec![]), upstream_source_retention(), ), ], &[], ) }
fn gleam_dict() -> Self { let dict_type = type_decl("Dict", vec!["k", "v"], true, vec![]); let dict_kv = dict(Type::generic("k"), Type::generic("v")); Self::new( "gleam/dict", ModuleStrategy::Hybrid, module_retention(RetentionGap::PackageMetadata), &[ function("new", vec![], dict_kv.clone(), runtime_primitive_retention()), function("size", vec![dict_kv.clone()], Type::Int, runtime_primitive_retention()), function( "is_empty", vec![dict_kv.clone()], Type::Bool, runtime_primitive_retention(), ), function( "insert", vec![dict_kv.clone(), Type::generic("k"), Type::generic("v")], dict_kv.clone(), runtime_primitive_retention(), ), function( "get", vec![dict_kv.clone(), Type::generic("k")], option(Type::generic("v")), runtime_primitive_retention(), ), function( "has_key", vec![dict_kv.clone(), Type::generic("k")], Type::Bool, runtime_primitive_retention(), ), function( "delete", vec![dict_kv.clone(), Type::generic("k")], dict_kv, runtime_primitive_retention(), ), ], &[dict_type], ) }
fn gleam_dynamic() -> Self { let dynamic_type = type_decl("Dynamic", vec![], true, vec![]); Self::new( "gleam/dynamic", ModuleStrategy::Hybrid, module_retention(RetentionGap::PackageAsset), &[ function("array", vec![list(dynamic())], dynamic(), runtime_primitive_retention()), function( "bit_array", vec![Type::BitArray], dynamic(), runtime_primitive_retention(), ), function("bool", vec![Type::Bool], dynamic(), runtime_primitive_retention()), function("classify", vec![dynamic()], Type::String, runtime_primitive_retention()), function("float", vec![Type::Float], dynamic(), runtime_primitive_retention()), function("int", vec![Type::Int], dynamic(), runtime_primitive_retention()), function("list", vec![list(dynamic())], dynamic(), runtime_primitive_retention()), function("nil", vec![], dynamic(), runtime_primitive_retention()), function( "properties", vec![list(Type::Tuple(vec![dynamic(), dynamic()]))], dynamic(), runtime_primitive_retention(), ), function("string", vec![Type::String], dynamic(), runtime_primitive_retention()), ], &[dynamic_type], ) }
fn gleam_dynamic_decode() -> Self { let decoder_type = type_decl("Decoder", vec!["t"], true, vec![]); let decode_error_type = type_decl( "DecodeError", vec![], false, vec![constructor( "DecodeError", vec![ FieldInfo::new("expected".to_string(), Type::String), FieldInfo::new("found".to_string(), Type::String), FieldInfo::new("path".to_string(), list(Type::String)), ], decode_error(), )], ); Self::new( "gleam/dynamic/decode", ModuleStrategy::Hybrid, module_retention(RetentionGap::PackageMetadata), &[ value("bit_array", decoder(Type::BitArray), runtime_primitive_retention()), value("bool", decoder(Type::Bool), runtime_primitive_retention()), value("dynamic", decoder(dynamic()), runtime_primitive_retention()), value("float", decoder(Type::Float), runtime_primitive_retention()), value("int", decoder(Type::Int), runtime_primitive_retention()), value("string", decoder(Type::String), runtime_primitive_retention()), function( "run", vec![dynamic(), decoder(Type::generic("t"))], result(Type::generic("t"), list(decode_error())), runtime_primitive_retention(), ), function( "list", vec![decoder(Type::generic("a"))], decoder(list(Type::generic("a"))), runtime_primitive_retention(), ), function( "optional", vec![decoder(Type::generic("a"))], decoder(option(Type::generic("a"))), runtime_primitive_retention(), ), function( "dict", vec![decoder(Type::generic("k")), decoder(Type::generic("v"))], decoder(dict(Type::generic("k"), Type::generic("v"))), temporary_interface_retention(), ), function( "at", vec![list(Type::generic("segment")), decoder(Type::generic("a"))], decoder(Type::generic("a")), temporary_interface_retention(), ), function( "optionally_at", vec![ list(Type::generic("segment")), Type::generic("a"), decoder(Type::generic("a")), ], decoder(Type::generic("a")), temporary_interface_retention(), ), function( "field", vec![ Type::generic("name"), decoder(Type::generic("t")), fn_type(vec![Type::generic("t")], decoder(Type::generic("final"))), ], decoder(Type::generic("final")), temporary_interface_retention(), ), function( "optional_field", vec![ Type::generic("name"), Type::generic("t"), decoder(Type::generic("t")), fn_type(vec![Type::generic("t")], decoder(Type::generic("final"))), ], decoder(Type::generic("final")), temporary_interface_retention(), ), function( "subfield", vec![ list(Type::generic("name")), decoder(Type::generic("t")), fn_type(vec![Type::generic("t")], decoder(Type::generic("final"))), ], decoder(Type::generic("final")), temporary_interface_retention(), ), function( "success", vec![Type::generic("t")], decoder(Type::generic("t")), temporary_interface_retention(), ), function( "failure", vec![Type::generic("a"), Type::String], decoder(Type::generic("a")), temporary_interface_retention(), ), function( "map", vec![ decoder(Type::generic("a")), fn_type(vec![Type::generic("a")], Type::generic("b")), ], decoder(Type::generic("b")), temporary_interface_retention(), ), function( "then", vec![ decoder(Type::generic("a")), fn_type(vec![Type::generic("a")], decoder(Type::generic("b"))), ], decoder(Type::generic("b")), temporary_interface_retention(), ), function( "one_of", vec![decoder(Type::generic("a")), list(decoder(Type::generic("a")))], decoder(Type::generic("a")), temporary_interface_retention(), ), function( "collapse_errors", vec![decoder(Type::generic("a")), Type::String], decoder(Type::generic("a")), temporary_interface_retention(), ), function( "map_errors", vec![ decoder(Type::generic("a")), fn_type(vec![list(decode_error())], list(decode_error())), ], decoder(Type::generic("a")), temporary_interface_retention(), ), function( "recursive", vec![fn_type(vec![], decoder(Type::generic("a")))], decoder(Type::generic("a")), temporary_interface_retention(), ), function( "new_primitive_decoder", vec![ Type::String, fn_type(vec![dynamic()], result(Type::generic("t"), Type::generic("t"))), ], decoder(Type::generic("t")), temporary_interface_retention(), ), function( "decode_error", vec![Type::String, dynamic()], list(decode_error()), temporary_interface_retention(), ), ], &[decoder_type, decode_error_type], ) }
fn gleam_float() -> Self { Self::new( "gleam/float", ModuleStrategy::Hybrid, module_retention(RetentionGap::PackageMetadata), &[ function( "compare", vec![Type::Float, Type::Float], Type::custom("Order", vec![]), upstream_source_retention(), ), function( "to_string", vec![Type::Float], Type::String, upstream_source_retention(), ), function( "max", vec![Type::Float, Type::Float], Type::Float, upstream_source_retention(), ), function( "min", vec![Type::Float, Type::Float], Type::Float, upstream_source_retention(), ), function("negate", vec![Type::Float], Type::Float, upstream_source_retention()), ], &[], ) }
fn gleam_function() -> Self { Self::new( "gleam/function", ModuleStrategy::Hybrid, module_retention(RetentionGap::SourceLanguageFeature), &[ function( "identity", vec![Type::generic("a")], Type::generic("a"), upstream_source_retention(), ), function( "constant", vec![Type::generic("a"), Type::generic("b")], Type::generic("a"), upstream_source_retention(), ), function( "compose", vec![ fn_type(vec![Type::generic("b")], Type::generic("c")), fn_type(vec![Type::generic("a")], Type::generic("b")), ], fn_type(vec![Type::generic("a")], Type::generic("c")), upstream_source_retention(), ), function( "flip", vec![fn_type( vec![Type::generic("a"), Type::generic("b")], Type::generic("c"), )], fn_type(vec![Type::generic("b"), Type::generic("a")], Type::generic("c")), upstream_source_retention(), ), ], &[], ) }
fn remaining(name: &'static str, gap: RetentionGap) -> Self { Self::new( name, ModuleStrategy::PreferCompiledSource, RegistryRetention { category: RetentionCategory::UpstreamSource, gap, deletion_condition: "delete this placeholder when the upstream module compiles from package source", }, &[], &[], ) }
fn new( name: &'static str, strategy: ModuleStrategy, retention: RegistryRetention, members: &[StdlibMemberSpec], types: &[TypeDeclaration], ) -> Self { let mut interface = ModuleInterface::default(); let mut member_entries = Vec::new();
for member in members { member_entries.push(StdlibMember { name: member.name, retention: member.retention }); if let Some(type_) = &member.type_ { interface.functions.insert(member.name.into(), type_.clone()); } }
for type_ in types { interface.types.insert(type_.name.clone(), type_.clone()); for constructor in &type_.constructors { interface .constructors .insert(constructor.name.clone(), constructor.clone()); } }
Self { name, strategy, retention, interface, members: member_entries } }}
#[derive(Debug, Clone)]struct StdlibMemberSpec { name: &'static str, retention: RegistryRetention, type_: Option<Type>,}
fn function( name: &'static str, params: Vec<Type>, return_type: Type, retention: RegistryRetention,) -> StdlibMemberSpec { StdlibMemberSpec { name, retention, type_: Some(fn_type(params, return_type)) }}
fn value(name: &'static str, type_: Type, retention: RegistryRetention) -> StdlibMemberSpec { StdlibMemberSpec { name, retention, type_: Some(type_) }}
fn constructor_member(name: &'static str) -> StdlibMemberSpec { StdlibMemberSpec { name, retention: constructor_interface_retention(), type_: None }}
fn module_retention(gap: RetentionGap) -> RegistryRetention { let category = match gap { RetentionGap::PackageAsset => RetentionCategory::PackageAsset, RetentionGap::RuntimePrimitive => RetentionCategory::RuntimePrimitive, RetentionGap::HostAbi => RetentionCategory::TargetHostAdapter, RetentionGap::SourceLanguageFeature | RetentionGap::TargetFiltering | RetentionGap::PackageMetadata => { RetentionCategory::TemporaryInterface } }; RegistryRetention { category, gap, deletion_condition: "delete this module entry when its interface comes from package source, package metadata, validated assets, or runtime primitive tables", }}
fn runtime_primitive_retention() -> RegistryRetention { RegistryRetention { category: RetentionCategory::RuntimePrimitive, gap: RetentionGap::RuntimePrimitive, deletion_condition: "move this primitive out of the stdlib registry or replace the library behavior with compiled upstream source", }}
fn upstream_source_retention() -> RegistryRetention { RegistryRetention { category: RetentionCategory::UpstreamSource, gap: RetentionGap::SourceLanguageFeature, deletion_condition: "delete this retained interface when the upstream function is loaded from package source by default", }}
fn host_adapter_retention() -> RegistryRetention { RegistryRetention { category: RetentionCategory::TargetHostAdapter, gap: RetentionGap::HostAbi, deletion_condition: "move this host adapter out of the stdlib registry and into target ABI tables", }}
fn constructor_interface_retention() -> RegistryRetention { RegistryRetention { category: RetentionCategory::TemporaryInterface, gap: RetentionGap::PackageMetadata, deletion_condition: "delete this constructor entry when custom type constructors come from package source or prelude metadata", }}
fn temporary_interface_retention() -> RegistryRetention { RegistryRetention { category: RetentionCategory::TemporaryInterface, gap: RetentionGap::PackageMetadata, deletion_condition: "delete this interface-only entry when upstream source or package metadata provides the interface", }}
fn type_decl(name: &str, parameters: Vec<&str>, opaque: bool, constructors: Vec<ConstructorInfo>) -> TypeDeclaration { TypeDeclaration { name: name.into(), parameters: parameters.into_iter().map(str::to_string).collect(), opaque, constructors, span: STDLIB_SPAN, }}
fn constructor(name: &str, fields: Vec<FieldInfo>, return_type: Type) -> ConstructorInfo { ConstructorInfo { name: name.into(), fields, return_type, span: STDLIB_SPAN }}
fn fn_type(params: Vec<Type>, return_type: Type) -> Type { Type::Function { params, return_type: Box::new(return_type) }}
fn list(item: Type) -> Type { Type::List(Box::new(item))}
fn result(ok: Type, error: Type) -> Type { Type::custom("Result", vec![ok, error])}
fn option(item: Type) -> Type { Type::custom("Option", vec![item])}
fn dict(key: Type, value: Type) -> Type { Type::custom("Dict", vec![key, value])}
fn dynamic() -> Type { Type::custom("Dynamic", vec![])}
fn decoder(item: Type) -> Type { Type::custom("Decoder", vec![item])}
fn decode_error() -> Type { Type::custom("DecodeError", vec![])}
#[cfg(test)]mod tests { use super::*;
#[test] fn registers_initial_modules_and_member_retention() { let registry = StdlibRegistry::new();
assert_eq!( registry.member_retention("gleam/io", "println"), Some(host_adapter_retention()), ); assert_eq!( registry.member_retention("gleam/int", "to_string"), Some(upstream_source_retention()), ); assert_eq!( registry.member_retention("gleam/result", "Ok"), Some(constructor_interface_retention()), ); }
#[test] fn exposes_initial_interfaces() { let registry = StdlibRegistry::new(); let interface = registry.interface("gleam/string").expect("string interface");
assert_eq!( interface.functions.get("append"), Some(&fn_type(vec![Type::String, Type::String], Type::String)), ); }
#[test] fn records_remaining_stdlib_strategy() { let registry = StdlibRegistry::new(); let module = registry.module("gleam/bytes_tree").expect("bytes_tree module");
assert_eq!(module.strategy, ModuleStrategy::PreferCompiledSource); }
#[test] fn every_registry_entry_records_retention_reason() { let registry = StdlibRegistry::new();
for module in registry.modules() { assert!( !module.retention.deletion_condition.is_empty(), "{} should record why its registry entry may remain", module.name ); for member in &module.members { assert!( !member.retention.deletion_condition.is_empty(), "{}.{} should record why its registry entry may remain", module.name, member.name ); } } }
#[test] fn registry_retention_reasons_track_current_blocker_groups() { let registry = StdlibRegistry::new();
let order = registry.module("gleam/order").expect("order module"); assert_eq!(order.retention.category, RetentionCategory::TemporaryInterface); assert_eq!(order.retention.gap, RetentionGap::SourceLanguageFeature);
let string_tree = registry.module("gleam/string_tree").expect("string_tree module"); assert_eq!(string_tree.retention.category, RetentionCategory::UpstreamSource); assert_eq!(string_tree.retention.gap, RetentionGap::PackageAsset);
let option = registry.module("gleam/option").expect("option module"); assert_eq!(option.retention.category, RetentionCategory::PackageAsset); assert_eq!(option.retention.gap, RetentionGap::PackageAsset);
let io = registry.module("gleam/io").expect("io module"); assert_eq!(io.retention.category, RetentionCategory::TargetHostAdapter); assert_eq!(io.retention.gap, RetentionGap::HostAbi); assert_eq!( registry .member_retention("gleam/io", "println") .expect("println retention"), host_adapter_retention() ); }}