1use crate::db::{InputFile, RidlDatabase};
10use crate::manifest::TimingDefaults;
11use crate::package::{Package, PackageOrigin};
12
13pub const RIDL_STD_SOURCE: &str = include_str!("../assets/ridl_std.typl");
15
16pub const RIDL_STD_NAME: &str = "ridl.std";
18
19pub const RESERVED_PACKAGE_NAMES: &[&str] = &[RIDL_STD_NAME];
27
28pub fn is_reserved_package_name(name: &str) -> bool {
30 RESERVED_PACKAGE_NAMES.contains(&name)
31}
32
33pub const RIDL_STD_PATH: &str = "<builtin>/ridl_std.typl";
36
37pub fn std_package(db: &mut RidlDatabase) -> Package {
43 if let Some(&package) = db.std_package_cache.get() {
44 return package;
45 }
46 let file = InputFile::new(&*db, RIDL_STD_PATH.to_string(), RIDL_STD_SOURCE.to_string());
47 let package = Package::new(
48 &*db,
49 RIDL_STD_NAME.to_string(),
50 "ridl.std".to_string(),
51 vec![file],
52 PackageOrigin::Std,
53 std::collections::BTreeMap::new(),
54 TimingDefaults::default(),
55 None,
56 );
57 let _ = db.std_package_cache.set(package);
58 package
59}
60
61#[cfg(test)]
62mod tests {
63 use super::*;
64 use crate::db::parse_file;
65
66 #[test]
70 fn std_package_parses_clean_and_exposes_ridl_std() {
71 let mut db = RidlDatabase::default();
72 let package = std_package(&mut db);
73
74 assert_eq!(package.name(&db).as_str(), "ridl.std");
75 assert_eq!(*package.origin(&db), PackageOrigin::Std);
76 assert!(
77 package.imports(&db).is_empty(),
78 "the built-in package has no manifest and no imports",
79 );
80
81 let files = package.files(&db);
82 assert_eq!(files.len(), 1, "ridl.std is a single embedded file");
83 assert_eq!(files[0].path(&db).as_str(), RIDL_STD_PATH);
84
85 let parse = parse_file(&db, files[0]);
86 assert_eq!(
87 parse.errors(),
88 &[],
89 "the embedded Appendix A source must parse without errors",
90 );
91
92 let declared = parse.syntax().text().to_string();
93 assert_eq!(declared, RIDL_STD_SOURCE, "the parse is lossless");
94 assert!(
95 RIDL_STD_SOURCE.starts_with("package ridl.std\n"),
96 "the asset starts with the `package ridl.std` declaration",
97 );
98 }
99
100 #[test]
101 fn std_package_is_memoized_per_database() {
102 let mut db = RidlDatabase::default();
103 let first = std_package(&mut db);
104 let second = std_package(&mut db);
105 assert_eq!(first, second, "the same database returns the same package");
106 }
107
108 #[test]
116 fn the_asset_is_appendix_a_verbatim() {
117 let reference = std::fs::read_to_string(concat!(
118 env!("CARGO_MANIFEST_DIR"),
119 "/../../docs/specification/typl-language-reference.md"
120 ))
121 .expect("the typl reference is readable");
122
123 let block = reference
124 .split("```ridl\n")
125 .find(|block| block.starts_with("package ridl.std\n"))
126 .and_then(|block| block.split("\n```").next())
127 .expect("Appendix A carries a `ridl.std` fenced block");
128
129 assert_eq!(
130 format!("{block}\n"),
131 RIDL_STD_SOURCE,
132 "`crates/ridl-core/assets/ridl_std.typl` and Appendix A of \
133 `docs/specification/typl-language-reference.md` have drifted apart. \
134 They are the same normative text and are edited together.",
135 );
136 }
137}