1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
//! The concept records shared with the JavaScript runtime.
//!
//! `src/data/concept-records.json` is generated from
//! `parity/naming/canonical-concepts.json` by
//! `js/scripts/build-concept-records.mjs`; the npm package ships the same
//! file, so both runtimes agree on every canonical identity, its readable
//! English phrase, definition, constraints, source aliases and former names.
use std::sync::OnceLock;
use serde::Deserialize;
const CONCEPT_RECORDS_JSON: &str = include_str!("data/concept-records.json");
/// Whether a canonical name is a concept (a noun phrase) or an operation (a verb phrase).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ConceptRole {
/// A concept, named by a noun phrase.
Concept,
/// An operation or relation, named by a verb phrase.
Operation,
}
/// The name a source (a grammar format, a programming language, a surface) gives a concept.
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub struct SourceAlias {
/// The source, such as `ebnf`, `Rust` or `Russian grammar surface`.
pub source: String,
/// The name or notation the source uses for the concept.
pub name: String,
}
/// A concept whose phrase is a synonym of another's, with what distinguishes them.
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
pub struct ConceptDistinction {
/// The identity of the synonymous concept.
pub id: String,
/// What distinguishes the two concepts.
pub reason: String,
}
/// The record of one canonical concept or operation.
#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct ConceptRecord {
/// Stable identity, such as `grammar.character-class`.
pub id: String,
/// The readable English phrase the identity spells, such as `character class`.
pub phrase: String,
/// Whether the phrase is a noun phrase or a verb phrase.
pub role: ConceptRole,
/// What the concept means.
pub definition: String,
/// The constraints the concept satisfies.
pub constraints: Vec<String>,
/// The names other sources give the concept.
pub source_aliases: Vec<SourceAlias>,
/// Former names that still decode to the concept.
pub former_names: Vec<String>,
/// The concept this one is a use of, such as the operation a stage performs.
#[serde(default)]
pub represents: Option<String>,
/// The concepts with a synonymous phrase this one is distinct from.
#[serde(default)]
pub distinct_from: Vec<ConceptDistinction>,
}
#[derive(Deserialize)]
struct ConceptRecordFile {
concepts: Vec<ConceptRecord>,
}
/// Returns every concept record in register order.
#[must_use]
pub fn concept_records() -> &'static [ConceptRecord] {
static RECORDS: OnceLock<Vec<ConceptRecord>> = OnceLock::new();
RECORDS.get_or_init(|| {
serde_json::from_str::<ConceptRecordFile>(CONCEPT_RECORDS_JSON)
.expect("the embedded concept records are valid")
.concepts
})
}
/// Returns the record whose identity or former name is `name`.
#[must_use]
pub fn concept_record(name: &str) -> Option<&'static ConceptRecord> {
concept_records()
.iter()
.find(|record| record.id == name || record.former_names.iter().any(|former| former == name))
}
/// Returns the records a source (such as `ebnf` or `Rust`) names `name`, in register order.
#[must_use]
pub fn concept_records_for_source_name(source: &str, name: &str) -> Vec<&'static ConceptRecord> {
concept_records()
.iter()
.filter(|record| {
record
.source_aliases
.iter()
.any(|alias| alias.source == source && alias.name == name)
})
.collect()
}