narust_158/language/base/
serde.rs

1//! 为[`Term`]定制的序列反序列化方法
2//! * 🎯节省序列化后的占用空间
3//!   * 📄在JSON中不再需要是一个object,是一个`[f, c, a]`三元组就行
4use super::Term;
5use narsese::conversion::string::impl_lexical::format_instances::FORMAT_ASCII;
6use serde::{Deserialize, Deserializer, Serialize, Serializer};
7
8impl Serialize for Term {
9    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
10    where
11        S: Serializer,
12    {
13        // * 🚩为保证稳定性,此处不使用`Term::format_ascii`
14        // 转换为词法Narsese
15        let lexical = self.to_lexical();
16        // 再变为字符串
17        let s = FORMAT_ASCII.format(&lexical);
18        s.serialize(serializer)
19    }
20}
21
22impl<'de> Deserialize<'de> for Term {
23    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
24    where
25        D: Deserializer<'de>,
26    {
27        // 先反序列化到字符串
28        let s: String = Deserialize::deserialize(deserializer)?;
29        // 再词法解析
30        let lexical = FORMAT_ASCII
31            .parse_term(&s)
32            .map_err(serde::de::Error::custom)?;
33        // 最后词法折叠
34        Term::from_lexical(lexical).map_err(serde::de::Error::custom)
35    }
36}
37
38#[cfg(test)]
39mod tests {
40    use crate::{language::Term, ok, test_term as term, util::AResult};
41    use nar_dev_utils::macro_once;
42
43    /// 测试「序列反序列化」的正确性
44    /// * 🎯一次「序列化→反序列化」过程后,结果要和自身一致
45    ///   * 📄强一致性:不论任何term输入,均能如此
46    ///   * 📄弱一致性:经过一次「序列反序列化」之后(的词项),能通过「强一致性」的条件
47    ///
48    /// ! ⚠️【2024-08-12 01:09:41】暂且只满足「弱一致性」
49    /// * 💫不是很能处理「无序词项+变量」的问题
50    ///   * 📄存在「序列反序列化后,因变量id导致无序词项内部顺序变化」的情况
51    ///     * "<(&&,<(*,{SELF},$1,FALSE) --> #3>,<(*,{SELF},$1) --> #2>) ==> <(*,{SELF},$1) --> afraid_of>>"
52    ///   * 😮‍💨【2024-08-12 01:11:37】所幸这类情况并不多见,且仍满足「弱一致性」
53    ///
54    /// TODO: 🎯【2024-08-12 01:21:56】后续实现「强一致性」以彻底解决edge cases
55    #[test]
56    fn test_soundness() -> AResult {
57        fn test(term: Term) {
58            // * 强一致性 * //
59            let mut strong_soundness = true;
60            // 序列化-反序列化
61            let ser = serde_json::to_string(&term).expect("词项序列化失败");
62            let de = serde_json::from_str::<Term>(&ser).expect("词项反序列化失败");
63            strong_soundness &= term == de;
64            // assert_eq!(
65            //     term, de,
66            //     "序列化-反序列化 不可靠! {term} vs\n{de}\nfrom {ser:?}"
67            // );
68            // 重序列化
69            let ser2 = serde_json::to_string(&de).expect("词项重序列化失败");
70            strong_soundness &= ser == ser2;
71            // assert_eq!(
72            //     ser, ser2,
73            //     "反序列化-序列化 不可靠! {ser} vs\n{ser2}\nfrom {de}"
74            // );
75
76            // ! 🚩【2024-08-12 01:14:38】目前仅警告
77            if !strong_soundness {
78                eprintln!("【警告】当前序列反序列化机制 不满足强一致性!\n1 {term} vs\n3 {de}\nfrom\n2 {ser} vs\n4 {ser2}");
79            }
80
81            // * 弱一致性 * //
82            // 重反序列化
83            let de2 = serde_json::from_str::<Term>(&ser2).expect("词项反序列化失败");
84            assert_eq!(
85                de, de2,
86                "序列化-反序列化 不可靠! {de} vs\n{de2}\nfrom {ser2:?}"
87            );
88            // 重序列化
89            let ser3 = serde_json::to_string(&de2).expect("词项重序列化失败");
90            assert_eq!(
91                ser2, ser3,
92                "反序列化-序列化 不可靠! {ser} vs\n{ser3}\nfrom {de}"
93            );
94        }
95        macro_once! {
96            // * 🚩格式:词项内容字符串
97            macro test( $($term:literal)* ) {
98                $( test( term!($term) ); )*
99            }
100            "(&&,<#1 --> object>,<#1 --> [unscrewing]>)"
101            "<(&&,<$1 --> [pliable]>,<(*,{SELF},$1) --> #reshape>) ==> <$1 --> [hardened]>>"
102            "<(&&,<(*,$1,plastic) --> made_of>,<(*,{SELF},$1) --> #lighter>) ==> <$1 --> [heated]>>"
103            "<(&&,<(*,{SELF},wolf) --> close_to>,#1000) ==> <{SELF} --> [hurt]>>"
104            "<(&&,<(*,{SELF},$1,FALSE) --> #want>,<(*,{SELF},$1) --> #anticipate>) ==> <(*,{SELF},$1) --> afraid_of>>"
105            "<(*,cup,plastic) --> made_of>"
106            "<(*,toothbrush,plastic) --> made_of>"
107            "<(*,{SELF},?what) --> afraid_of>"
108            "<(*,{SELF},wolf) --> close_to>"
109            "<(*,{tom},(&,[black],glasses)) --> own>"
110            "<(*,{tom},sunglasses) --> own>"
111            "<<$1 --> (/,livingIn,_,{graz})> ==> <$1 --> murder>>"
112            "<<$1 --> [aggressive]> ==> <$1 --> murder>>"
113            "<<$1 --> [hardened]> ==> <$1 --> [unscrewing]>>"
114            "<<$1 --> [heated]> ==> <$1 --> [melted]>>"
115            "<<$1 --> [melted]> <=> <$1 --> [pliable]>>"
116            "<<(*,$1,sunglasses) --> own> ==> <$1 --> [aggressive]>>"
117            "<?1 ==> <c --> C>>"
118            "<a --> A>"
119            "<b --> B>"
120            "<c --> C>"
121            "<cup --> [bendable]>"
122            "<cup --> object>"
123            "<sunglasses --> (&,[black],glasses)>"
124            "<toothbrush --> [bendable]>"
125            "<toothbrush --> object>"
126            "<{?who} --> murder>"
127            "<{SELF} --> [hurt]>"
128            "<{tim} --> (/,livingIn,_,{graz})>"
129
130            "(&&,<#1 --> lock>,<<$2 --> key> ==> <#1 --> (/,open,$2,_)>>)"
131            "(&&,<#x --> (/,open,#y,_)>,<#x --> lock>,<#y --> key>)"
132            "(&&,<#x --> bird>,<#x --> swimmer>)"
133            "(&&,<#x --> key>,<{lock1} --> (/,open,#x,_)>)"
134            "(&&,<robin --> [flying]>,<robin --> swimmer>)"
135            "(&&,<robin --> swimmer>,<robin --> [flying]>)"
136            "(--,<robin --> [flying]>)"
137            "(||,<robin --> [flying]>,<robin --> swimmer>)"
138            "<(&&,<#1 --> lock>,<#1 --> (/,open,$2,_)>) ==> <$2 --> key>>"
139            "<(&&,<$x --> [chirping]>,<$x --> [with_wings]>) ==> <$x --> bird>>"
140            "<(&&,<$x --> flyer>,<$x --> [chirping]>) ==> <$x --> bird>>"
141            "<(&&,<$x --> flyer>,<$x --> [chirping]>, <(*, $x, worms) --> food>) ==> <$x --> bird>>"
142            "<(&&,<$x --> flyer>,<(*,$x,worms) --> food>) ==> <$x --> bird>>"
143            "<(&&,<$x --> key>,<$y --> lock>) ==> <$y --> (/,open,$x,_)>>"
144            "<(&&,<robin --> [chirping]>,<robin --> [flying]>) ==> <robin --> bird>>"
145            "<(&&,<robin --> [chirping]>,<robin --> [flying]>,<robin --> [with_wings]>) ==> <robin --> bird>>"
146            "<(&&,<robin --> [flying]>,<robin --> [with_wings]>) ==> <robin --> [living]>>"
147            "<(&&,<robin --> [flying]>,<robin --> bird>) ==> <robin --> [living]>>"
148            "<(&&,<robin --> bird>,<robin --> [living]>) ==> <robin --> animal>>"
149            "<(&,<{Tweety} --> bird>,<bird --> fly>) --> claimedByBob>"
150            "<(&,bird,swimmer) --> (&,animal,swimmer)>"
151            "<(&,swan,swimmer) --> bird>"
152            "<(*,(*,(*,0))) --> num>"
153            "<(*,a,b) --> like>"
154            "<(*,bird,plant) --> ?x>"
155            "<(-,swimmer,animal) --> (-,swimmer,bird)>"
156            "<(--,<robin --> [flying]>) ==> <robin --> bird>>"
157            "<(--,<robin --> bird>) ==> <robin --> [flying]>>"
158            "<(/,neutralization,_,base) --> ?x>"
159            r"<(\,(\,REPRESENT,_,<(*,CAT,FISH) --> FOOD>),_,eat,fish) --> cat>"
160            r"<(\,REPRESENT,_,CAT) --> cat>"
161            r"<(\,neutralization,acid,_) --> ?x>"
162            "<(|,boy,girl) --> youth>"
163            "<(~,boy,girl) --> [strong]>"
164            "<(~,swimmer,swan) --> bird>"
165            "<0 --> (/,num,_)>"
166            "<0 --> num>"
167            "<<$1 --> lock> ==> (&&,<#2 --> key>,<$1 --> (/,open,#2,_)>)>"
168            "<<$1 --> num> ==> <(*,$1) --> num>>"
169            "<<$x --> animal> <=> <$x --> bird>>"
170            "<<$x --> bird> ==> <$x --> animal>>"
171            "<<$x --> key> ==> <{lock1} --> (/,open,$x,_)>>"
172            "<<$y --> [with_wings]> ==> <$y --> flyer>>"
173            "<<$y --> flyer> ==> <$y --> [with_wings]>>"
174            "<<(&,<#1 --> $2>,<$3 --> #1>) --> claimedByBob> ==> <<$3 --> $2> --> claimedByBob>>"
175            "<<(*,$1,$2) --> like> <=> <(*,$2,$1) --> like>>"
176            "<<bird --> $x> ==> <robin --> $x>>"
177            "<<lock1 --> (/,open,$1,_)> ==> <$1 --> key>>"
178            "<<robin --> [flying]> ==> <robin --> [with_beak]>>"
179            "<<robin --> [flying]> ==> <robin --> animal>>"
180            "<<robin --> animal> <=> <robin --> bird>>"
181            "<<robin --> bird> <=> <robin --> [flying]>>"
182            "<<robin --> bird> ==> (&&,<robin --> animal>,<robin --> [flying]>)>"
183            "<<robin --> bird> ==> <robin --> [flying]>>"
184            "<<robin --> bird> ==> <robin --> animal>>"
185            "<?1 --> swimmer>"
186            "<Birdie <-> Tweety>"
187            "<Tweety {-- bird>"
188            "<Tweety {-] yellow>"
189            "<[bright] <-> [smart]>"
190            "<[smart] --> [bright]>"
191            "<acid --> (/,reaction,_,base)>"
192            "<cat --> (/,(/,REPRESENT,_,<(*,CAT,FISH) --> FOOD>),_,eat,fish)>"
193            "<neutralization --> (*,acid,base)>"
194            "<planetX --> {Mars,Pluto,Venus}>"
195            "<planetX --> {Pluto,Saturn}>"
196            "<raven --] black>"
197            "<robin --> (&,bird,swimmer)>"
198            "<robin --> (-,bird,swimmer)>"
199            "<robin --> (|,bird,swimmer)>"
200            "<robin --> [flying]>"
201            "<{?1} --> swimmer>"
202            "<{Birdie} <-> {Tweety}>"
203            "<{Tweety} --> [with_wings]>"
204            "<{Tweety} --> flyer>"
205            "<{Tweety} --> {Birdie}>"
206            "<{key1} --> (/,open,_,{lock1})>"
207
208            // ! edge cases
209            "(&&,<(*,1,FALSE) --> #3>,<(*,1) --> #2>)" // ! ❌【2024-08-12 01:19:45】破坏强一致性 最小例
210        }
211        ok!()
212    }
213}