Skip to main content

nichlink/registry_core/declaration/
registration.rs

1//! Registration declarations and the compile-time construction contracts.
2//! 注册声明与编译期构造合同。
3//!
4//! The vocabulary is split by concept: the compile-time declaration types stay
5//! here, the construction-contract traits and records live in [`contract`], and
6//! the owned snapshot forms live in [`owned`]. The module tree mirrors that
7//! split, and every public path is preserved by re-export.
8//! 词表按概念拆分:编译期声明类型留在本页,构造合同 trait 与记录位于 [`contract`],
9//! 拥有型快照形式位于 [`owned`]。文件树与之一致,所有公开路径都通过再导出保留。
10
11use super::*;
12use crate::registry_core::lexicon::path_is_under;
13
14/// One capability requirement and the object expected to provide it.
15/// 一条能力需求,以及本应提供它的对象。
16#[derive(Clone, Copy, Debug, PartialEq, Eq)]
17pub struct RequirementSpec {
18    /// Capability name that must be resolvable in the registry tree.
19    /// 必须在注册树中可解析的能力名称。
20    pub capability: &'static str,
21    /// Object expected to provide that capability; any other provider fails the check.
22    /// 本应提供该能力的对象;由其他对象提供即判定失败。
23    pub provider: &'static str,
24}
25
26/// Dependency admission for objects produced outside the current registry tree.
27/// 当前注册树对外部注册机产物的依赖门禁。
28#[derive(Clone, Copy, Debug, PartialEq, Eq)]
29pub struct Admission {
30    /// External path prefixes admitted; empty admits every path not denied.
31    /// 允许进入的外部路径前缀;为空时允许所有未被拒绝的路径。
32    pub allowed_paths: &'static [&'static str],
33    /// External path prefixes refused; a denial overrides any allowance.
34    /// 拒绝进入的外部路径前缀;拒绝优先于允许。
35    pub denied_paths: &'static [&'static str],
36}
37
38impl Admission {
39    /// Admission that accepts every external path.
40    /// 接受任何外部路径的门禁。
41    pub const ANY: Self = Self::new(&[], &[]);
42
43    /// Build an admission from explicit allow and deny path prefixes.
44    /// 用显式的允许与拒绝路径前缀构造门禁。
45    pub const fn new(
46        allowed_paths: &'static [&'static str],
47        denied_paths: &'static [&'static str],
48    ) -> Self {
49        Self {
50            allowed_paths,
51            denied_paths,
52        }
53    }
54
55    /// Admission allowing only paths under the listed prefixes.
56    /// 只允许列出的前缀之下的路径进入的门禁。
57    pub const fn allow_paths(paths: &'static [&'static str]) -> Self {
58        Self::new(paths, &[])
59    }
60
61    /// Whether an external path may enter: denied prefixes win, and an empty
62    /// allow list admits every path not denied.
63    /// 外部路径是否可以进入:拒绝前缀优先,允许列表为空时接受所有未被拒绝的路径。
64    pub fn accepts(self, path: &str) -> bool {
65        if self
66            .denied_paths
67            .iter()
68            .any(|prefix| path_is_under(path, prefix))
69        {
70            return false;
71        }
72        self.allowed_paths.is_empty()
73            || self
74                .allowed_paths
75                .iter()
76                .any(|prefix| path_is_under(path, prefix))
77    }
78
79    /// Copy this admission into the owned form a snapshot can retain.
80    /// 将该门禁复制为快照可长期持有的拥有所有权形式。
81    pub fn into_owned(self) -> OwnedAdmission {
82        OwnedAdmission {
83            allowed_paths: self
84                .allowed_paths
85                .iter()
86                .map(|value| (*value).to_owned())
87                .collect(),
88            denied_paths: self
89                .denied_paths
90                .iter()
91                .map(|value| (*value).to_owned())
92                .collect(),
93        }
94    }
95}
96
97/// Structural rule for faces entering a Registry.
98/// 注册面进入 Registry 时必须满足的结构规范。
99#[derive(Clone, Copy, Debug, PartialEq, Eq)]
100pub struct RegistrationRule {
101    /// Preset name every admitted face must declare; `None` leaves it unconstrained.
102    /// 每个被接纳的注册面都必须声明的 preset 名;`None` 表示不作要求。
103    pub required_preset: Option<&'static str>,
104    /// Part names every admitted face must provide.
105    /// 每个被接纳的注册面都必须提供的 part 名称。
106    pub required_parts: &'static [&'static str],
107    /// Export names every admitted face must declare.
108    /// 每个被接纳的注册面都必须声明的导出名称。
109    pub required_exports: &'static [&'static str],
110    /// Interfaces the handle type must implement, for example `ControlHandle`.
111    /// handle 类型必须实现的接口,例如 `ControlHandle`。
112    pub required_handle_traits: &'static [&'static str],
113    /// Interfaces the parts type must implement, for example `ActionParts`.
114    /// parts 类型必须实现的接口,例如 `ActionParts`。
115    pub required_part_traits: &'static [&'static str],
116}
117
118impl RegistrationRule {
119    /// Rule with no structural requirements; it admits any face.
120    /// 不含任何结构要求的规则,接纳任意注册面。
121    pub const ANY: Self = Self::new();
122
123    /// Start an unconstrained structural rule.
124    /// 创建一个尚未添加结构要求的规则。
125    pub const fn new() -> Self {
126        Self {
127            required_preset: None,
128            required_parts: &[],
129            required_exports: &[],
130            required_handle_traits: &[],
131            required_part_traits: &[],
132        }
133    }
134
135    /// Set the required preset name and return the updated rule.
136    /// 设置所需 preset 名并返回更新后的规则。
137    pub const fn require_preset(mut self, preset: &'static str) -> Self {
138        self.required_preset = Some(preset);
139        self
140    }
141
142    /// Set the required part names and return the updated rule.
143    /// 设置所需 part 名称并返回更新后的规则。
144    pub const fn require_parts(mut self, parts: &'static [&'static str]) -> Self {
145        self.required_parts = parts;
146        self
147    }
148
149    /// Set the required export names and return the updated rule.
150    /// 设置所需导出名称并返回更新后的规则。
151    pub const fn require_exports(mut self, exports: &'static [&'static str]) -> Self {
152        self.required_exports = exports;
153        self
154    }
155
156    /// Set the required handle trait names and return the updated rule.
157    /// 设置所需 handle trait 名称并返回更新后的规则。
158    pub const fn require_handle_traits(mut self, traits: &'static [&'static str]) -> Self {
159        self.required_handle_traits = traits;
160        self
161    }
162
163    /// Set the required parts trait names and return the updated rule.
164    /// 设置所需 parts trait 名称并返回更新后的规则。
165    pub const fn require_part_traits(mut self, traits: &'static [&'static str]) -> Self {
166        self.required_part_traits = traits;
167        self
168    }
169
170    /// Return one message per unmet structural requirement for `info`; an empty
171    /// result means the declaration may enter the registry.
172    /// 针对 `info` 的每项未满足结构要求各返回一条消息;结果为空表示该声明可进入注册机。
173    pub fn validate(&self, info: &RegistrationInfo) -> Vec<String> {
174        validate_registration_requirements(RegistrationRequirementCheck {
175            required_preset: self.required_preset,
176            required_parts: self.required_parts,
177            required_exports: self.required_exports,
178            required_handle_traits: self.required_handle_traits,
179            required_part_traits: self.required_part_traits,
180            preset: info.preset,
181            provided_parts: info.contract.provided_parts,
182            exports: info.exports,
183            handle: info.handle,
184            handle_traits: info.handle_traits,
185            parts: info.parts,
186            part_traits: info.part_traits,
187        })
188    }
189
190    /// Copy this rule into the owned form a snapshot can retain.
191    /// 将该规则复制为快照可长期持有的拥有所有权形式。
192    pub fn into_owned(self) -> OwnedRegistrationRule {
193        OwnedRegistrationRule {
194            required_preset: self.required_preset.map(str::to_owned),
195            required_parts: self
196                .required_parts
197                .iter()
198                .map(|value| (*value).to_owned())
199                .collect(),
200            required_exports: self
201                .required_exports
202                .iter()
203                .map(|value| (*value).to_owned())
204                .collect(),
205            required_handle_traits: self
206                .required_handle_traits
207                .iter()
208                .map(|value| (*value).to_owned())
209                .collect(),
210            required_part_traits: self
211                .required_part_traits
212                .iter()
213                .map(|value| (*value).to_owned())
214                .collect(),
215        }
216    }
217}
218
219impl Default for RegistrationRule {
220    fn default() -> Self {
221        Self::new()
222    }
223}
224
225/// Declarative information for an ordinary object or a registry owner.
226/// 普通 object 或注册机拥有者的声明式注册信息。
227#[derive(Clone, Copy, Debug)]
228pub struct RegistrationInfo {
229    /// Package namespace that owns this declaration.
230    /// 拥有本声明的包命名空间。
231    pub namespace: &'static str,
232    /// Stable node identity assigned to this face.
233    /// 分配给本注册面的稳定节点身份。
234    pub id: NodeId,
235    /// Node identity of the face this one is registered under.
236    /// 本注册面所挂载到的父节点身份。
237    pub parent: NodeId,
238    /// Face kind name, for example `Button`.
239    /// 注册面种类名,例如 `Button`。
240    pub kind: &'static str,
241    /// Preset type path that constructs this face.
242    /// 构造本注册面的 preset 类型路径。
243    pub preset: &'static str,
244    /// Parts type path that supplies this face's construction parts.
245    /// 提供本注册面构造 parts 的 parts 类型路径。
246    pub parts: &'static str,
247    /// Parameter type path this face declares for its construction input.
248    /// 本注册面为其构造输入声明的参数类型路径。
249    pub params: &'static str,
250    /// Handle type path that exposes this face to its owner.
251    /// 向其拥有者暴露本注册面的 handle 类型路径。
252    pub handle: &'static str,
253    /// Optional author-owned identity that survives source moves.
254    /// 可选的作者逻辑身份,可跨源码文件移动保持不变。
255    pub stable_name: Option<&'static str>,
256    /// Localized display name shown to authors.
257    /// 向作者显示的本地化名称。
258    pub name: LocalizedText,
259    /// Localized one-line description shown alongside the name.
260    /// 与名称一同显示的本地化单行描述。
261    pub summary: LocalizedText,
262    /// Export names this face declares.
263    /// 本注册面声明的导出名称。
264    pub exports: &'static [&'static str],
265    /// Whether this face owns a child Registry.
266    /// 本注册面是否拥有一个子注册机。
267    pub needs_registry: bool,
268    /// Name of that child Registry, used to build its path; ignored otherwise.
269    /// 子注册机的名称,用于生成其路径;不需要子注册机时忽略。
270    pub registry_name: &'static str,
271    /// Name of an external registry this face is provisioned from, if any.
272    /// 本注册面从其获取内容的外部注册机名(如果有)。
273    pub getting_from_other_registry: Option<&'static str>,
274    /// Source path that produced the registry rule, kept for diagnostics.
275    /// 产出注册规范的源码路径,用于诊断。
276    pub registry_rule_path: &'static str,
277    /// Rule for faces entering the Registry owned by this face.
278    /// 该注册面拥有的 Registry 所使用的注册规范。
279    pub registry_rule: RegistrationRule,
280    /// External dependency gate for this face's registry.
281    /// 该注册面所属注册机对外部依赖的门禁。
282    pub admission: Admission,
283    /// Capability requirements this face declares.
284    /// 本注册面声明的能力需求。
285    pub requires: &'static [RequirementSpec],
286    /// Capability names this face makes available to other faces.
287    /// 本注册面向其他注册面提供的能力名称。
288    pub provides: &'static [&'static str],
289    /// Construction contract comparing required and supplied parts.
290    /// 比较所需 parts 与实际提供 parts 的构造合同。
291    pub contract: ObjectContract,
292    /// Automatically comparable input/output contract for grafting.
293    /// 供嫁接自动比较的输入/输出合同。
294    pub flow: crate::FlowContract,
295    /// Type that supplied the compile-time flow contract, when explicit.
296    /// 显式提供编译期数据流合同的类型路径(如果有)。
297    pub flow_provider: Option<&'static str>,
298    /// Interface names declared by the handle type on this registration face.
299    /// 此注册面的 handle 类型声明实现的接口名称。
300    pub handle_traits: &'static [&'static str],
301    /// Interface names declared by the parts type on this registration face.
302    /// 此注册面的 parts 类型声明实现的接口名称。
303    pub part_traits: &'static [&'static str],
304    /// Runtime value checks the host applies to this face; empty accepts any value.
305    /// 宿主对本注册面取值执行的运行期校验;为空时接受任何取值。
306    pub runtime_checks: &'static [RuntimeCheckSpec],
307    /// Optional provenance for a face supplied by an external plugin crate.
308    /// 外部插件 crate 提供注册面时,可附带插件来源元数据。
309    pub plugin: Option<crate::PluginManifest>,
310    /// Declaration site this metadata was captured from.
311    /// 捕获这份元数据时所在的声明位置。
312    pub source: SourceLocation,
313}
314
315impl RegistrationInfo {
316    /// Return the opt-in logical identity for this face.
317    /// 返回该注册面的可选逻辑稳定身份。
318    pub const fn stable_face_id(self) -> StableFaceId {
319        let name = match self.stable_name {
320            Some(name) => name,
321            None => self.kind,
322        };
323        StableFaceId::from_name(name)
324    }
325
326    /// Return the stable identity only when the declaration opted into one.
327    /// 只有声明显式选择稳定名称时才返回稳定身份。
328    ///
329    /// The fallback used by `stable_face_id` is useful for diagnostics, but it
330    /// is not a uniqueness promise: several independent faces may all be
331    /// named `Button`. Only an explicit name can be checked globally.
332    /// `stable_face_id` 的回退值适合诊断,但不代表全局唯一;多个独立注册面
333    /// 可以同名为 `Button`。只有显式名称才需要做全局冲突检查。
334    pub const fn explicit_stable_face_id(self) -> Option<StableFaceId> {
335        match self.stable_name {
336            Some(name) => Some(StableFaceId::from_name(name)),
337            None => None,
338        }
339    }
340
341    /// Copy a compiled declaration into an independently owned snapshot.
342    /// 将编译期声明复制为独立拥有所有权的快照。
343    pub fn into_snapshot(self) -> RegistrationSnapshot {
344        RegistrationSnapshot {
345            namespace: self.namespace.to_owned(),
346            id: self.id,
347            parent: self.parent,
348            kind: self.kind.to_owned(),
349            preset: self.preset.to_owned(),
350            parts: self.parts.to_owned(),
351            params: self.params.to_owned(),
352            handle: self.handle.to_owned(),
353            stable_name: self.stable_name.map(str::to_owned),
354            name: OwnedLocalizedText {
355                zh: self.name.zh.to_owned(),
356                en: self.name.en.to_owned(),
357            },
358            summary: OwnedLocalizedText {
359                zh: self.summary.zh.to_owned(),
360                en: self.summary.en.to_owned(),
361            },
362            exports: self
363                .exports
364                .iter()
365                .map(|value| (*value).to_owned())
366                .collect(),
367            needs_registry: self.needs_registry,
368            registry_name: self.registry_name.to_owned(),
369            getting_from_other_registry: self.getting_from_other_registry.map(str::to_owned),
370            registry_rule_path: self.registry_rule_path.to_owned(),
371            registry_rule: self.registry_rule.into_owned(),
372            admission: self.admission.into_owned(),
373            requires: self
374                .requires
375                .iter()
376                .map(|requirement| OwnedRequirementSpec {
377                    capability: requirement.capability.to_owned(),
378                    provider: requirement.provider.to_owned(),
379                })
380                .collect(),
381            provides: self
382                .provides
383                .iter()
384                .map(|value| (*value).to_owned())
385                .collect(),
386            contract: self.contract.into_owned(),
387            flow: self.flow.into(),
388            flow_provider: self.flow_provider.map(str::to_owned),
389            handle_traits: self
390                .handle_traits
391                .iter()
392                .map(|value| (*value).to_owned())
393                .collect(),
394            part_traits: self
395                .part_traits
396                .iter()
397                .map(|value| (*value).to_owned())
398                .collect(),
399            runtime_checks: self.runtime_checks.to_vec(),
400            plugin: self.plugin,
401            source: OwnedSourceLocation {
402                file: self.source.file.to_owned(),
403                line: self.source.line,
404                column: self.source.column,
405                function: self.source.function.to_owned(),
406            },
407        }
408    }
409}
410
411// ---------------------------------------------------------------------------
412// Runtime check values and specifications.
413// These types are declared here (rather than in the runtime crate) because
414// `RegistrationInfo`/`RegistrationSnapshot` carry them; the runtime crate
415// re-exports them at its historical paths.
416// 以下类型因被 RegistrationInfo/RegistrationSnapshot 持有而定义在 kernel;
417// runtime crate 会在原路径上重导出它们。
418
419/// The face fields in the order the authoring macros accept them.
420/// 作者侧宏接受的注册面字段顺序。
421///
422/// This is the one place the vocabulary is ordered. The face macros declare it
423/// for an editor, and the macro front end sorts an author's fields into it, so
424/// a face may be written in any order and still reach the same declaration.
425/// 这是词表顺序的唯一来源。注册面宏据此为编辑器声明字段,宏前端据此把作者写的
426/// 字段排成这个顺序——因此注册面可以用任意顺序书写,最终仍落到同一份声明。
427pub const FACE_FIELD_ORDER: &[&str] = &[
428    // `source` belongs to the external form only (`external_object!`), which
429    // names the file explicitly because an external crate is not part of the
430    // host's generated tree. It comes first because that matcher expects it
431    // right after `collector`.
432    // `source` 只属于外部形式(`external_object!`):外部 crate 不在宿主的生成树里,
433    // 因此要显式指出文件。它排在首位,因为那个 matcher 期望它紧跟 `collector`。
434    "source",
435    "kind",
436    "preset",
437    "parts",
438    "name",
439    "summary",
440    "exports",
441    "stable_name",
442    "needs_registry",
443    "parent",
444    "getting_from_other_registry",
445    "registry_rule_path",
446    "registry_rule",
447    "admission",
448    "handle_traits",
449    "handle_contracts",
450    "part_traits",
451    "part_contracts",
452    "requires",
453    "provides",
454    "flow",
455    "flow_provider",
456    // The spelling lives in `lexicon` because the build step and the macro
457    // front end look the field up by name; one text, one definition.
458    // 该拼写住在 `lexicon`:构建步骤与宏前端都按名字查找这个字段,一份文本一个定义点。
459    crate::registry_core::lexicon::FACE_FIELD_PLUGIN,
460    "runtime_checks",
461];