From c10161bdbea39c653205c06446506759b0acaae4 Mon Sep 17 00:00:00 2001 From: MDLC01 <57839069+MDLC01@users.noreply.github.com> Date: Sat, 14 Dec 2024 23:24:38 +0100 Subject: [PATCH 1/2] Make it possible to deprecate symbols and modules --- build.rs | 46 +++++++++++++++++++++++++++++++++++----------- src/lib.rs | 44 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 69 insertions(+), 21 deletions(-) diff --git a/build.rs b/build.rs index 2e2fd45..b8dc5e4 100644 --- a/build.rs +++ b/build.rs @@ -5,15 +5,21 @@ use std::path::Path; type StrResult = Result; /// A module of definitions. -struct Module<'a>(Vec<(&'a str, Def<'a>)>); +struct Module<'a>(Vec<(&'a str, Entry<'a>)>); impl<'a> Module<'a> { - fn new(mut list: Vec<(&'a str, Def<'a>)>) -> Self { + fn new(mut list: Vec<(&'a str, Entry<'a>)>) -> Self { list.sort_by_key(|&(name, _)| name); Self(list) } } +/// An entry in a module. +struct Entry<'a> { + definition: Def<'a>, + deprecated: Option<&'a str>, +} + /// A definition in a module. enum Def<'a> { Symbol(Symbol<'a>), @@ -30,6 +36,7 @@ enum Symbol<'a> { #[derive(Debug, Copy, Clone)] enum Line<'a> { Blank, + Deprecated(&'a str), ModuleStart(&'a str), ModuleEnd, Symbol(&'a str, Option), @@ -91,7 +98,9 @@ fn tokenize(line: &str) -> StrResult { None => (line, None), }; - Ok(if tail == Some("{") { + Ok(if head == "@deprecated:" { + Line::Deprecated(tail.ok_or("missing deprecation message")?.trim()) + } else if tail == Some("{") { validate_ident(head)?; Line::ModuleStart(head) } else if head == "}" && tail.is_none() { @@ -137,11 +146,18 @@ fn decode_char(text: &str) -> StrResult { /// Turns a stream of lines into a list of definitions. fn parse<'a>( p: &mut Peekable>>>, -) -> StrResult)>> { +) -> StrResult)>> { let mut defs = vec![]; + let mut deprecated = None; loop { match p.next().transpose()? { - None | Some(Line::ModuleEnd) => break, + None | Some(Line::ModuleEnd) => { + if let Some(message) = deprecated { + return Err(format!("dangling `@deprecated: {}`", message)); + } + break; + } + Some(Line::Deprecated(message)) => deprecated = Some(message), Some(Line::Symbol(name, c)) => { let mut variants = vec![]; while let Some(Line::Variant(name, c)) = p.peek().cloned().transpose()? { @@ -160,11 +176,19 @@ fn parse<'a>( Symbol::Single(c) }; - defs.push((name, Def::Symbol(symbol))); + defs.push((name, Entry { definition: Def::Symbol(symbol), deprecated })); + deprecated = None; } Some(Line::ModuleStart(name)) => { let module_defs = parse(p)?; - defs.push((name, Def::Module(Module::new(module_defs)))); + defs.push(( + name, + Entry { + definition: Def::Module(Module::new(module_defs)), + deprecated, + }, + )); + deprecated = None; } other => return Err(format!("expected definition, found {other:?}")), } @@ -175,9 +199,9 @@ fn parse<'a>( /// Encodes a `Module` into Rust code. fn encode(buf: &mut String, module: &Module) { buf.push_str("Module(&["); - for (name, def) in &module.0 { - write!(buf, "({name:?},").unwrap(); - match def { + for (name, entry) in &module.0 { + write!(buf, "({name:?}, Entry {{ definition: ").unwrap(); + match &entry.definition { Def::Module(module) => { buf.push_str("Def::Module("); encode(buf, module); @@ -192,7 +216,7 @@ fn encode(buf: &mut String, module: &Module) { buf.push_str(")"); } } - buf.push_str("),"); + write!(buf, ", deprecated: {:?} }}),", entry.deprecated).unwrap(); } buf.push_str("])"); } diff --git a/src/lib.rs b/src/lib.rs index d541534..235c807 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,12 +3,12 @@ Human-friendly notation for Unicode symbols. */ /// A module of definitions. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub struct Module(&'static [(&'static str, Def)]); +#[derive(Debug, Copy, Clone)] +pub struct Module(&'static [(&'static str, Entry)]); impl Module { /// Try to get a definition from the module. - pub fn get(&self, name: &str) -> Option { + pub fn get(&self, name: &str) -> Option { self.0 .binary_search_by_key(&name, |(k, _)| k) .ok() @@ -16,13 +16,35 @@ impl Module { } /// Iterate over the module's definition. - pub fn iter(&self) -> impl Iterator { + pub fn iter(&self) -> impl Iterator { self.0.iter().copied() } } +/// An entry in a module. +#[derive(Debug, Copy, Clone)] +pub struct Entry { + /// The definition associated with this entry. + pub definition: Def, + /// Indicates whether the entry is deprecated. + /// + /// If `Some(s)`, the entry is deprecated, with the deprecation message `s`. + /// Otherwise, the entry is not deprecated. + pub deprecated: Option<&'static str>, +} + +impl Entry { + pub const fn new(definition: Def) -> Self { + Self { definition, deprecated: None } + } + + pub const fn new_deprecated(definition: Def, message: &'static str) -> Self { + Self { definition, deprecated: Some(message) } + } +} + /// A definition in a module. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Copy, Clone)] pub enum Def { /// A symbol, potentially with modifiers. Symbol(Symbol), @@ -31,7 +53,7 @@ pub enum Def { } /// A symbol, either a leaf or with modifiers. -#[derive(Debug, Copy, Clone, Eq, PartialEq)] +#[derive(Debug, Copy, Clone)] pub enum Symbol { /// A symbol without modifiers. Single(char), @@ -40,8 +62,10 @@ pub enum Symbol { } /// A module that contains the other top-level modules. -pub const ROOT: Module = - Module(&[("emoji", Def::Module(EMOJI)), ("sym", Def::Module(SYM))]); +pub const ROOT: Module = Module(&[ + ("emoji", Entry::new(Def::Module(EMOJI))), + ("sym", Entry::new(Def::Module(SYM))), +]); include!(concat!(env!("OUT_DIR"), "/out.rs")); @@ -54,8 +78,8 @@ mod test { fn assert_sorted_recursively(root: Module) { assert!(root.0.is_sorted_by_key(|(k, _)| k)); - for (_, def) in root.iter() { - if let Def::Module(module) = def { + for (_, entry) in root.iter() { + if let Def::Module(module) = entry.definition { assert_sorted_recursively(module) } } From cd004aad21a4516b89e0331c02d5375e478c243d Mon Sep 17 00:00:00 2001 From: Laurenz Date: Mon, 3 Feb 2025 17:41:09 +0100 Subject: [PATCH 2/2] Rename `Entry` to `Binding` --- build.rs | 38 +++++++++++++++++++------------------- src/lib.rs | 38 ++++++++++++++++---------------------- 2 files changed, 35 insertions(+), 41 deletions(-) diff --git a/build.rs b/build.rs index b8dc5e4..a49152c 100644 --- a/build.rs +++ b/build.rs @@ -5,19 +5,19 @@ use std::path::Path; type StrResult = Result; /// A module of definitions. -struct Module<'a>(Vec<(&'a str, Entry<'a>)>); +struct Module<'a>(Vec<(&'a str, Binding<'a>)>); impl<'a> Module<'a> { - fn new(mut list: Vec<(&'a str, Entry<'a>)>) -> Self { + fn new(mut list: Vec<(&'a str, Binding<'a>)>) -> Self { list.sort_by_key(|&(name, _)| name); Self(list) } } -/// An entry in a module. -struct Entry<'a> { - definition: Def<'a>, - deprecated: Option<&'a str>, +/// A definition bound in a module, with metadata. +struct Binding<'a> { + def: Def<'a>, + deprecation: Option<&'a str>, } /// A definition in a module. @@ -146,18 +146,18 @@ fn decode_char(text: &str) -> StrResult { /// Turns a stream of lines into a list of definitions. fn parse<'a>( p: &mut Peekable>>>, -) -> StrResult)>> { +) -> StrResult)>> { let mut defs = vec![]; - let mut deprecated = None; + let mut deprecation = None; loop { match p.next().transpose()? { None | Some(Line::ModuleEnd) => { - if let Some(message) = deprecated { + if let Some(message) = deprecation { return Err(format!("dangling `@deprecated: {}`", message)); } break; } - Some(Line::Deprecated(message)) => deprecated = Some(message), + Some(Line::Deprecated(message)) => deprecation = Some(message), Some(Line::Symbol(name, c)) => { let mut variants = vec![]; while let Some(Line::Variant(name, c)) = p.peek().cloned().transpose()? { @@ -176,19 +176,19 @@ fn parse<'a>( Symbol::Single(c) }; - defs.push((name, Entry { definition: Def::Symbol(symbol), deprecated })); - deprecated = None; + defs.push((name, Binding { def: Def::Symbol(symbol), deprecation })); + deprecation = None; } Some(Line::ModuleStart(name)) => { let module_defs = parse(p)?; defs.push(( name, - Entry { - definition: Def::Module(Module::new(module_defs)), - deprecated, + Binding { + def: Def::Module(Module::new(module_defs)), + deprecation, }, )); - deprecated = None; + deprecation = None; } other => return Err(format!("expected definition, found {other:?}")), } @@ -200,8 +200,8 @@ fn parse<'a>( fn encode(buf: &mut String, module: &Module) { buf.push_str("Module(&["); for (name, entry) in &module.0 { - write!(buf, "({name:?}, Entry {{ definition: ").unwrap(); - match &entry.definition { + write!(buf, "({name:?}, Binding {{ def: ").unwrap(); + match &entry.def { Def::Module(module) => { buf.push_str("Def::Module("); encode(buf, module); @@ -216,7 +216,7 @@ fn encode(buf: &mut String, module: &Module) { buf.push_str(")"); } } - write!(buf, ", deprecated: {:?} }}),", entry.deprecated).unwrap(); + write!(buf, ", deprecation: {:?} }}),", entry.deprecation).unwrap(); } buf.push_str("])"); } diff --git a/src/lib.rs b/src/lib.rs index 235c807..ae64ee1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,11 +4,11 @@ Human-friendly notation for Unicode symbols. /// A module of definitions. #[derive(Debug, Copy, Clone)] -pub struct Module(&'static [(&'static str, Entry)]); +pub struct Module(&'static [(&'static str, Binding)]); impl Module { - /// Try to get a definition from the module. - pub fn get(&self, name: &str) -> Option { + /// Try to get a bound definition in the module. + pub fn get(&self, name: &str) -> Option { self.0 .binary_search_by_key(&name, |(k, _)| k) .ok() @@ -16,30 +16,24 @@ impl Module { } /// Iterate over the module's definition. - pub fn iter(&self) -> impl Iterator { + pub fn iter(&self) -> impl Iterator { self.0.iter().copied() } } -/// An entry in a module. +/// A definition bound in a module, with metadata. #[derive(Debug, Copy, Clone)] -pub struct Entry { - /// The definition associated with this entry. - pub definition: Def, - /// Indicates whether the entry is deprecated. - /// - /// If `Some(s)`, the entry is deprecated, with the deprecation message `s`. - /// Otherwise, the entry is not deprecated. - pub deprecated: Option<&'static str>, +pub struct Binding { + /// The bound definition. + pub def: Def, + /// A deprecation message for the definition, if it is deprecated. + pub deprecation: Option<&'static str>, } -impl Entry { +impl Binding { + /// Create a new bound definition. pub const fn new(definition: Def) -> Self { - Self { definition, deprecated: None } - } - - pub const fn new_deprecated(definition: Def, message: &'static str) -> Self { - Self { definition, deprecated: Some(message) } + Self { def: definition, deprecation: None } } } @@ -63,8 +57,8 @@ pub enum Symbol { /// A module that contains the other top-level modules. pub const ROOT: Module = Module(&[ - ("emoji", Entry::new(Def::Module(EMOJI))), - ("sym", Entry::new(Def::Module(SYM))), + ("emoji", Binding::new(Def::Module(EMOJI))), + ("sym", Binding::new(Def::Module(SYM))), ]); include!(concat!(env!("OUT_DIR"), "/out.rs")); @@ -79,7 +73,7 @@ mod test { assert!(root.0.is_sorted_by_key(|(k, _)| k)); for (_, entry) in root.iter() { - if let Def::Module(module) = entry.definition { + if let Def::Module(module) = entry.def { assert_sorted_recursively(module) } }