nichlink/registry_core/declaration/contract.rs
1//! Compile-time construction contracts for registration faces.
2//! 注册面的编译期构造合同。
3//!
4//! A preset declares the parts it expects, a parts type declares what it
5//! supplies, and [`assert_contract`] forces the two output types to match during
6//! macro expansion. [`ObjectContract`] is the runtime-readable record of that
7//! relationship.
8//! preset 声明它要求的 parts,parts 类型声明它提供的 parts,[`assert_contract`] 在宏
9//! 展开时强制两者的输出类型相同。[`ObjectContract`] 是这层关系的运行时可读记录。
10
11use super::*;
12
13/// A preset declares the construction shape it expects.
14/// preset 声明它要求的构造形状。
15pub trait PresetContract {
16 /// Concrete type this preset constructs.
17 /// 该 preset 构造出的具体类型。
18 type Output;
19 /// Part names that must all be supplied before the preset can construct.
20 /// 该 preset 完成构造前必须提供的全部 part 名称。
21 const REQUIRED_PARTS: &'static [&'static str];
22}
23
24/// Parts declare the construction shape an object supplies.
25/// parts 声明 object 实际提供的构造形状。
26pub trait PartsContract {
27 /// Concrete type these parts construct.
28 /// 这些 parts 构造出的具体类型。
29 type Output;
30 /// Part names this type actually supplies.
31 /// 该类型实际提供的 part 名称。
32 const PROVIDED_PARTS: &'static [&'static str];
33}
34
35/// Marker preset for a face that is constructed without a preset.
36/// 不需要 preset 即可构造的注册面所使用的标记类型。
37pub struct NoPreset;
38
39impl PresetContract for NoPreset {
40 type Output = ();
41 const REQUIRED_PARTS: &'static [&'static str] = &[];
42}
43
44/// Marker parts for a face that supplies no parts.
45/// 不提供任何 part 的注册面所使用的标记类型。
46pub struct NoParts;
47
48impl PartsContract for NoParts {
49 type Output = ();
50 const PROVIDED_PARTS: &'static [&'static str] = &[];
51}
52
53/// Force preset and parts output types to match during macro expansion.
54/// 在宏展开时强制 preset 与 parts 的输出类型相同。
55///
56/// ```compile_fail
57/// use nichlink::{assert_contract, PartsContract, PresetContract};
58///
59/// struct Expected;
60/// struct Supplied;
61/// impl PresetContract for Expected {
62/// type Output = Expected;
63/// const REQUIRED_PARTS: &'static [&'static str] = &[];
64/// }
65/// impl PartsContract for Supplied {
66/// type Output = Supplied;
67/// const PROVIDED_PARTS: &'static [&'static str] = &[];
68/// }
69///
70/// const _: () = assert_contract::<Expected, Supplied>();
71/// ```
72pub const fn assert_contract<P, T>()
73where
74 P: PresetContract,
75 T: PartsContract<Output = P::Output>,
76{
77}
78
79impl ObjectContract {
80 /// Copy this borrowed contract into the owned form a snapshot can retain.
81 /// 将该借用合同复制为快照可长期持有的拥有所有权形式。
82 pub fn into_owned(self) -> OwnedObjectContract {
83 OwnedObjectContract {
84 required_parts: self
85 .required_parts
86 .iter()
87 .map(|value| (*value).to_owned())
88 .collect(),
89 provided_parts: self
90 .provided_parts
91 .iter()
92 .map(|value| (*value).to_owned())
93 .collect(),
94 }
95 }
96
97 /// Return one message per unmet part requirement; an empty result means the
98 /// contract holds. `object` names the face being checked.
99 /// 每个未满足的 part 要求各返回一条消息;结果为空表示合同成立。
100 /// `object` 是被检查的注册面名称。
101 ///
102 /// The output half of this check is gone with the two names it compared: a
103 /// type-level `assert_contract` proves the same fact at compile time, per
104 /// face, and a graft cut proves it across two faces. This method now reports
105 /// only what the trait constants say, which is the part no compiler can see.
106 /// 本检查的输出那一半随它比较的那两个名字一起删除:同一件事由编译期
107 /// `assert_contract` 按面证明、由嫁接切口跨两个面证明。本方法现在只报告 trait 常量
108 /// 说了算的东西——那是编译器看不到的部分。
109 pub fn validate(&self, object: &str) -> Vec<String> {
110 validate_object_contract(self.required_parts, self.provided_parts, object)
111 }
112}
113
114/// Runtime-readable form of the construction contract.
115/// 构造合同的运行时可读形式。
116#[derive(Clone, Copy, Debug)]
117pub struct ObjectContract {
118 /// Part names the preset declared it needs.
119 /// preset 声明它需要的 part 名称。
120 pub required_parts: &'static [&'static str],
121 /// Part names the parts type supplied.
122 /// parts 类型实际提供的 part 名称。
123 pub provided_parts: &'static [&'static str],
124}