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