nichlink-core 0.1.0

Registry, transaction, contracts, grafts, and diagnostics for NichLink
Documentation
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
//! Registration declarations and the compile-time construction contracts.
//! 注册声明与编译期构造合同。
//!
//! The vocabulary is split by concept: the compile-time declaration types stay
//! here, the construction-contract traits and records live in [`contract`], and
//! the owned snapshot forms live in [`owned`]. The module tree mirrors that
//! split, and every public path is preserved by re-export.
//! 词表按概念拆分:编译期声明类型留在本页,构造合同 trait 与记录位于 [`contract`],
//! 拥有型快照形式位于 [`owned`]。文件树与之一致,所有公开路径都通过再导出保留。

use super::*;
use crate::registry_core::lexicon::path_is_under;

/// One capability requirement and the object expected to provide it.
/// 一条能力需求,以及本应提供它的对象。
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct RequirementSpec {
    /// Capability name that must be resolvable in the registry tree.
    /// 必须在注册树中可解析的能力名称。
    pub capability: &'static str,
    /// Object expected to provide that capability; any other provider fails the check.
    /// 本应提供该能力的对象;由其他对象提供即判定失败。
    pub provider: &'static str,
}

/// Dependency admission for objects produced outside the current registry tree.
/// 当前注册树对外部注册机产物的依赖门禁。
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Admission {
    /// External path prefixes admitted; empty admits every path not denied.
    /// 允许进入的外部路径前缀;为空时允许所有未被拒绝的路径。
    pub allowed_paths: &'static [&'static str],
    /// External path prefixes refused; a denial overrides any allowance.
    /// 拒绝进入的外部路径前缀;拒绝优先于允许。
    pub denied_paths: &'static [&'static str],
}

impl Admission {
    /// Admission that accepts every external path.
    /// 接受任何外部路径的门禁。
    pub const ANY: Self = Self::new(&[], &[]);

    /// Build an admission from explicit allow and deny path prefixes.
    /// 用显式的允许与拒绝路径前缀构造门禁。
    pub const fn new(
        allowed_paths: &'static [&'static str],
        denied_paths: &'static [&'static str],
    ) -> Self {
        Self {
            allowed_paths,
            denied_paths,
        }
    }

    /// Admission allowing only paths under the listed prefixes.
    /// 只允许列出的前缀之下的路径进入的门禁。
    pub const fn allow_paths(paths: &'static [&'static str]) -> Self {
        Self::new(paths, &[])
    }

    /// Whether an external path may enter: denied prefixes win, and an empty
    /// allow list admits every path not denied.
    /// 外部路径是否可以进入:拒绝前缀优先,允许列表为空时接受所有未被拒绝的路径。
    pub fn accepts(self, path: &str) -> bool {
        if self
            .denied_paths
            .iter()
            .any(|prefix| path_is_under(path, prefix))
        {
            return false;
        }
        self.allowed_paths.is_empty()
            || self
                .allowed_paths
                .iter()
                .any(|prefix| path_is_under(path, prefix))
    }

    /// Copy this admission into the owned form a snapshot can retain.
    /// 将该门禁复制为快照可长期持有的拥有所有权形式。
    pub fn into_owned(self) -> OwnedAdmission {
        OwnedAdmission {
            allowed_paths: self
                .allowed_paths
                .iter()
                .map(|value| (*value).to_owned())
                .collect(),
            denied_paths: self
                .denied_paths
                .iter()
                .map(|value| (*value).to_owned())
                .collect(),
        }
    }
}

/// Structural rule for faces entering a Registry.
/// 注册面进入 Registry 时必须满足的结构规范。
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct RegistrationRule {
    /// Preset name every admitted face must declare; `None` leaves it unconstrained.
    /// 每个被接纳的注册面都必须声明的 preset 名;`None` 表示不作要求。
    pub required_preset: Option<&'static str>,
    /// Part names every admitted face must provide.
    /// 每个被接纳的注册面都必须提供的 part 名称。
    pub required_parts: &'static [&'static str],
    /// Export names every admitted face must declare.
    /// 每个被接纳的注册面都必须声明的导出名称。
    pub required_exports: &'static [&'static str],
    /// Interfaces the handle type must implement, for example `ControlHandle`.
    /// handle 类型必须实现的接口,例如 `ControlHandle`。
    pub required_handle_traits: &'static [&'static str],
    /// Interfaces the parts type must implement, for example `ActionParts`.
    /// parts 类型必须实现的接口,例如 `ActionParts`。
    pub required_part_traits: &'static [&'static str],
}

impl RegistrationRule {
    /// Rule with no structural requirements; it admits any face.
    /// 不含任何结构要求的规则,接纳任意注册面。
    pub const ANY: Self = Self::new();

    /// Start an unconstrained structural rule.
    /// 创建一个尚未添加结构要求的规则。
    pub const fn new() -> Self {
        Self {
            required_preset: None,
            required_parts: &[],
            required_exports: &[],
            required_handle_traits: &[],
            required_part_traits: &[],
        }
    }

    /// Set the required preset name and return the updated rule.
    /// 设置所需 preset 名并返回更新后的规则。
    pub const fn require_preset(mut self, preset: &'static str) -> Self {
        self.required_preset = Some(preset);
        self
    }

    /// Set the required part names and return the updated rule.
    /// 设置所需 part 名称并返回更新后的规则。
    pub const fn require_parts(mut self, parts: &'static [&'static str]) -> Self {
        self.required_parts = parts;
        self
    }

    /// Set the required export names and return the updated rule.
    /// 设置所需导出名称并返回更新后的规则。
    pub const fn require_exports(mut self, exports: &'static [&'static str]) -> Self {
        self.required_exports = exports;
        self
    }

    /// Set the required handle trait names and return the updated rule.
    /// 设置所需 handle trait 名称并返回更新后的规则。
    pub const fn require_handle_traits(mut self, traits: &'static [&'static str]) -> Self {
        self.required_handle_traits = traits;
        self
    }

    /// Set the required parts trait names and return the updated rule.
    /// 设置所需 parts trait 名称并返回更新后的规则。
    pub const fn require_part_traits(mut self, traits: &'static [&'static str]) -> Self {
        self.required_part_traits = traits;
        self
    }

    /// Return one message per unmet structural requirement for `info`; an empty
    /// result means the declaration may enter the registry.
    /// 针对 `info` 的每项未满足结构要求各返回一条消息;结果为空表示该声明可进入注册机。
    pub fn validate(&self, info: &RegistrationInfo) -> Vec<String> {
        validate_registration_requirements(RegistrationRequirementCheck {
            required_preset: self.required_preset,
            required_parts: self.required_parts,
            required_exports: self.required_exports,
            required_handle_traits: self.required_handle_traits,
            required_part_traits: self.required_part_traits,
            preset: info.preset,
            provided_parts: info.contract.provided_parts,
            exports: info.exports,
            handle: info.handle,
            handle_traits: info.handle_traits,
            parts: info.parts,
            part_traits: info.part_traits,
        })
    }

    /// Copy this rule into the owned form a snapshot can retain.
    /// 将该规则复制为快照可长期持有的拥有所有权形式。
    pub fn into_owned(self) -> OwnedRegistrationRule {
        OwnedRegistrationRule {
            required_preset: self.required_preset.map(str::to_owned),
            required_parts: self
                .required_parts
                .iter()
                .map(|value| (*value).to_owned())
                .collect(),
            required_exports: self
                .required_exports
                .iter()
                .map(|value| (*value).to_owned())
                .collect(),
            required_handle_traits: self
                .required_handle_traits
                .iter()
                .map(|value| (*value).to_owned())
                .collect(),
            required_part_traits: self
                .required_part_traits
                .iter()
                .map(|value| (*value).to_owned())
                .collect(),
        }
    }
}

impl Default for RegistrationRule {
    fn default() -> Self {
        Self::new()
    }
}

/// Declarative information for an ordinary object or a registry owner.
/// 普通 object 或注册机拥有者的声明式注册信息。
#[derive(Clone, Copy, Debug)]
pub struct RegistrationInfo {
    /// Package namespace that owns this declaration.
    pub namespace: &'static str,
    /// Stable node identity assigned to this face.
    /// 分配给本注册面的稳定节点身份。
    pub id: NodeId,
    /// Node identity of the face this one is registered under.
    /// 本注册面所挂载到的父节点身份。
    pub parent: NodeId,
    /// Face kind name, for example `Button`.
    /// 注册面种类名,例如 `Button`。
    pub kind: &'static str,
    /// Preset type path that constructs this face.
    /// 构造本注册面的 preset 类型路径。
    pub preset: &'static str,
    /// Parts type path that supplies this face's construction parts.
    /// 提供本注册面构造 parts 的 parts 类型路径。
    pub parts: &'static str,
    /// Parameter type path this face declares for its construction input.
    /// 本注册面为其构造输入声明的参数类型路径。
    pub params: &'static str,
    /// Handle type path that exposes this face to its owner.
    /// 向其拥有者暴露本注册面的 handle 类型路径。
    pub handle: &'static str,
    /// Optional author-owned identity that survives source moves.
    /// 可选的作者逻辑身份,可跨源码文件移动保持不变。
    pub stable_name: Option<&'static str>,
    /// Localized display name shown to authors.
    /// 向作者显示的本地化名称。
    pub name: LocalizedText,
    /// Localized one-line description shown alongside the name.
    /// 与名称一同显示的本地化单行描述。
    pub summary: LocalizedText,
    /// Export names this face declares.
    /// 本注册面声明的导出名称。
    pub exports: &'static [&'static str],
    /// Whether this face owns a child Registry.
    /// 本注册面是否拥有一个子注册机。
    pub needs_registry: bool,
    /// Name of that child Registry, used to build its path; ignored otherwise.
    /// 子注册机的名称,用于生成其路径;不需要子注册机时忽略。
    pub registry_name: &'static str,
    /// Name of an external registry this face is provisioned from, if any.
    /// 本注册面从其获取内容的外部注册机名(如果有)。
    pub getting_from_other_registry: Option<&'static str>,
    /// Source path that produced the registry rule, kept for diagnostics.
    /// 产出注册规范的源码路径,用于诊断。
    pub registry_rule_path: &'static str,
    /// Rule for faces entering the Registry owned by this face.
    /// 该注册面拥有的 Registry 所使用的注册规范。
    pub registry_rule: RegistrationRule,
    /// External dependency gate for this face's registry.
    /// 该注册面所属注册机对外部依赖的门禁。
    pub admission: Admission,
    /// Capability requirements this face declares.
    /// 本注册面声明的能力需求。
    pub requires: &'static [RequirementSpec],
    /// Capability names this face makes available to other faces.
    /// 本注册面向其他注册面提供的能力名称。
    pub provides: &'static [&'static str],
    /// Construction contract comparing required and supplied parts.
    /// 比较所需 parts 与实际提供 parts 的构造合同。
    pub contract: ObjectContract,
    /// Automatically comparable input/output contract for grafting.
    /// 供嫁接自动比较的输入/输出合同。
    pub flow: crate::FlowContract,
    /// Type that supplied the compile-time flow contract, when explicit.
    /// 显式提供编译期数据流合同的类型路径(如果有)。
    pub flow_provider: Option<&'static str>,
    /// Interface names declared by the handle type on this registration face.
    /// 此注册面的 handle 类型声明实现的接口名称。
    pub handle_traits: &'static [&'static str],
    /// Interface names declared by the parts type on this registration face.
    /// 此注册面的 parts 类型声明实现的接口名称。
    pub part_traits: &'static [&'static str],
    /// Runtime value checks the host applies to this face; empty accepts any value.
    /// 宿主对本注册面取值执行的运行期校验;为空时接受任何取值。
    pub runtime_checks: &'static [RuntimeCheckSpec],
    /// Optional provenance for a face supplied by an external plugin crate.
    /// 外部插件 crate 提供注册面时,可附带插件来源元数据。
    pub plugin: Option<crate::PluginManifest>,
    /// Declaration site this metadata was captured from.
    /// 捕获这份元数据时所在的声明位置。
    pub source: SourceLocation,
}

impl RegistrationInfo {
    /// Return the opt-in logical identity for this face.
    /// 返回该注册面的可选逻辑稳定身份。
    pub const fn stable_face_id(self) -> StableFaceId {
        let name = match self.stable_name {
            Some(name) => name,
            None => self.kind,
        };
        StableFaceId::from_name(name)
    }

    /// Return the stable identity only when the declaration opted into one.
    /// 只有声明显式选择稳定名称时才返回稳定身份。
    ///
    /// The fallback used by `stable_face_id` is useful for diagnostics, but it
    /// is not a uniqueness promise: several independent faces may all be
    /// named `Button`. Only an explicit name can be checked globally.
    /// `stable_face_id` 的回退值适合诊断,但不代表全局唯一;多个独立注册面
    /// 可以同名为 `Button`。只有显式名称才需要做全局冲突检查。
    pub const fn explicit_stable_face_id(self) -> Option<StableFaceId> {
        match self.stable_name {
            Some(name) => Some(StableFaceId::from_name(name)),
            None => None,
        }
    }

    /// Copy a compiled declaration into an independently owned snapshot.
    /// 将编译期声明复制为独立拥有所有权的快照。
    pub fn into_snapshot(self) -> RegistrationSnapshot {
        RegistrationSnapshot {
            namespace: self.namespace.to_owned(),
            id: self.id,
            parent: self.parent,
            kind: self.kind.to_owned(),
            preset: self.preset.to_owned(),
            parts: self.parts.to_owned(),
            params: self.params.to_owned(),
            handle: self.handle.to_owned(),
            stable_name: self.stable_name.map(str::to_owned),
            name: OwnedLocalizedText {
                zh: self.name.zh.to_owned(),
                en: self.name.en.to_owned(),
            },
            summary: OwnedLocalizedText {
                zh: self.summary.zh.to_owned(),
                en: self.summary.en.to_owned(),
            },
            exports: self
                .exports
                .iter()
                .map(|value| (*value).to_owned())
                .collect(),
            needs_registry: self.needs_registry,
            registry_name: self.registry_name.to_owned(),
            getting_from_other_registry: self.getting_from_other_registry.map(str::to_owned),
            registry_rule_path: self.registry_rule_path.to_owned(),
            registry_rule: self.registry_rule.into_owned(),
            admission: self.admission.into_owned(),
            requires: self
                .requires
                .iter()
                .map(|requirement| OwnedRequirementSpec {
                    capability: requirement.capability.to_owned(),
                    provider: requirement.provider.to_owned(),
                })
                .collect(),
            provides: self
                .provides
                .iter()
                .map(|value| (*value).to_owned())
                .collect(),
            contract: self.contract.into_owned(),
            flow: self.flow.into(),
            flow_provider: self.flow_provider.map(str::to_owned),
            handle_traits: self
                .handle_traits
                .iter()
                .map(|value| (*value).to_owned())
                .collect(),
            part_traits: self
                .part_traits
                .iter()
                .map(|value| (*value).to_owned())
                .collect(),
            runtime_checks: self.runtime_checks.to_vec(),
            plugin: self.plugin,
            source: OwnedSourceLocation {
                file: self.source.file.to_owned(),
                line: self.source.line,
                column: self.source.column,
                function: self.source.function.to_owned(),
            },
        }
    }
}

// ---------------------------------------------------------------------------
// Runtime check values and specifications.
// These types are declared here (rather than in the runtime crate) because
// `RegistrationInfo`/`RegistrationSnapshot` carry them; the runtime crate
// re-exports them at its historical paths.
// 以下类型因被 RegistrationInfo/RegistrationSnapshot 持有而定义在 kernel;
// runtime crate 会在原路径上重导出它们。

/// The face fields in the order the authoring macros accept them.
/// 作者侧宏接受的注册面字段顺序。
///
/// This is the one place the vocabulary is ordered. The face macros declare it
/// for an editor, and the macro front end sorts an author's fields into it, so
/// a face may be written in any order and still reach the same declaration.
/// 这是词表顺序的唯一来源。注册面宏据此为编辑器声明字段,宏前端据此把作者写的
/// 字段排成这个顺序——因此注册面可以用任意顺序书写,最终仍落到同一份声明。
pub const FACE_FIELD_ORDER: &[&str] = &[
    // `source` belongs to the external form only (`external_object!`), which
    // names the file explicitly because an external crate is not part of the
    // host's generated tree. It comes first because that matcher expects it
    // right after `collector`.
    // `source` 只属于外部形式(`external_object!`):外部 crate 不在宿主的生成树里,
    // 因此要显式指出文件。它排在首位,因为那个 matcher 期望它紧跟 `collector`。
    "source",
    "kind",
    "preset",
    "parts",
    "name",
    "summary",
    "exports",
    "stable_name",
    "needs_registry",
    "parent",
    "getting_from_other_registry",
    "registry_rule_path",
    "registry_rule",
    "admission",
    "handle_traits",
    "handle_contracts",
    "part_traits",
    "part_contracts",
    "requires",
    "provides",
    "flow",
    "flow_provider",
    // The spelling lives in `lexicon` because the build step and the macro
    // front end look the field up by name; one text, one definition.
    // 该拼写住在 `lexicon`:构建步骤与宏前端都按名字查找这个字段,一份文本一个定义点。
    crate::registry_core::lexicon::FACE_FIELD_PLUGIN,
    "runtime_checks",
];