1#![allow(clippy::module_name_repetitions)]
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
18pub enum DocKind {
19 Type,
23 Syntax,
27 Handler,
33}
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub enum Stability {
38 Stable,
39 Experimental,
40}
41
42impl Stability {
43 #[must_use]
44 pub const fn label(self) -> &'static str {
45 match self {
46 Self::Stable => "stable",
47 Self::Experimental => "experimental",
48 }
49 }
50}
51
52#[derive(Debug, Clone, Copy)]
54pub struct DocEntry {
55 pub name: &'static str,
56 pub kind: DocKind,
57 pub since: &'static str,
58 pub stability: Stability,
59 pub body: &'static str,
61}
62
63include!(concat!(env!("OUT_DIR"), "/generated.rs"));
64
65#[must_use]
67pub fn find_doc(name: &str, kind: DocKind) -> Option<&'static DocEntry> {
68 ENTRIES.iter().find(|e| e.name == name && e.kind == kind)
69}
70
71#[must_use]
75pub fn find_any_doc(name: &str) -> Option<&'static DocEntry> {
76 ENTRIES.iter().find(|e| e.name == name)
77}
78
79#[must_use]
82pub const fn entry_count() -> usize {
83 ENTRIES.len()
84}
85
86pub fn iter_entries() -> impl Iterator<Item = &'static DocEntry> {
88 ENTRIES.iter()
89}
90
91#[must_use]
94pub fn render_doc(entry: &DocEntry) -> String {
95 let kind_label = match entry.kind {
96 DocKind::Type => "type",
97 DocKind::Syntax => "syntax",
98 DocKind::Handler => "handler",
99 };
100 format!(
101 "**{kind}** `{name}` · {stability} · since {since}\n\n---\n\n{body}",
102 kind = kind_label,
103 name = entry.name,
104 stability = entry.stability.label(),
105 since = entry.since,
106 body = entry.body,
107 )
108}
109
110#[cfg(test)]
111mod tests {
112 use super::{
113 DocKind, Stability, entry_count, find_any_doc, find_doc, iter_entries, render_doc,
114 };
115
116 #[test]
117 fn corpus_is_non_empty() {
118 assert!(
119 entry_count() >= 10,
120 "expected at least 10 doc entries (sub-fase 0.g verification floor); got {}",
121 entry_count(),
122 );
123 }
124
125 #[test]
126 fn find_doc_pins_name_and_kind() {
127 let s = find_doc("String", DocKind::Type).expect("String type doc");
128 assert_eq!(s.name, "String");
129 assert_eq!(s.kind, DocKind::Type);
130 assert_eq!(s.stability, Stability::Stable);
131 assert!(!s.body.is_empty());
132 assert!(find_doc("String", DocKind::Syntax).is_none());
134 }
135
136 #[test]
137 fn find_any_doc_falls_through_kinds() {
138 let entry = find_any_doc("flow").expect("flow syntax doc");
141 assert_eq!(entry.kind, DocKind::Syntax);
142 }
143
144 #[test]
145 fn render_doc_includes_metadata_header() {
146 let s = find_doc("String", DocKind::Type).unwrap();
147 let md = render_doc(s);
148 assert!(md.starts_with("**type** `String`"));
149 assert!(md.contains("· stable"));
150 assert!(md.contains("· since"));
151 assert!(md.contains(s.body));
152 }
153
154 #[test]
155 fn iter_entries_yields_stable_order() {
156 let kinds: Vec<DocKind> = iter_entries().map(|e| e.kind).collect();
157 let mut sorted = kinds.clone();
161 sorted.sort();
162 assert_eq!(kinds, sorted, "iter_entries must yield stable order");
163 }
164}