1use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
8pub enum Value {
9 Symbol(String),
10 Text(String),
11}
12
13impl Value {
14 pub fn as_str(&self) -> &str {
15 match self {
16 Value::Symbol(s) => s,
17 Value::Text(s) => s,
18 }
19 }
20}
21
22impl std::fmt::Display for Value {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 match self {
25 Value::Symbol(s) => write!(f, "{s}"),
26 Value::Text(s) => write!(f, "\"{s}\""),
27 }
28 }
29}
30
31#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
33pub enum FactSource {
34 Asserted,
36 Extracted { confidence: f32 },
38 Inferred { rule_name: Option<String> },
40}
41
42#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
44pub struct Fact {
45 pub subject: Value,
46 pub predicate: Value,
47 pub object: Value,
48 pub source: FactSource,
49 pub confidence: f32,
50}
51
52impl Fact {
53 pub fn asserted(subject: Value, predicate: Value, object: Value) -> Self {
54 Fact {
55 subject,
56 predicate,
57 object,
58 source: FactSource::Asserted,
59 confidence: 1.0,
60 }
61 }
62
63 pub fn same_triple(&self, other: &Fact) -> bool {
66 self.subject == other.subject
67 && self.predicate == other.predicate
68 && self.object == other.object
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75
76 #[test]
77 fn same_triple_ignores_source_and_confidence() {
78 let a = Fact::asserted(
79 Value::Symbol("TypeScript".into()),
80 Value::Symbol("is".into()),
81 Value::Text("programming language".into()),
82 );
83 let mut b = a.clone();
84 b.source = FactSource::Extracted { confidence: 0.5 };
85 b.confidence = 0.5;
86 assert!(a.same_triple(&b));
87 }
88
89 #[test]
90 fn different_object_is_not_same_triple() {
91 let a = Fact::asserted(
92 Value::Symbol("TypeScript".into()),
93 Value::Symbol("is".into()),
94 Value::Text("programming language".into()),
95 );
96 let b = Fact::asserted(
97 Value::Symbol("TypeScript".into()),
98 Value::Symbol("is".into()),
99 Value::Text("markup language".into()),
100 );
101 assert!(!a.same_triple(&b));
102 }
103
104 #[test]
105 fn serde_round_trip() {
106 let fact = Fact::asserted(
107 Value::Symbol("TypeScript".into()),
108 Value::Symbol("has".into()),
109 Value::Text("type system".into()),
110 );
111 let json = serde_json::to_string(&fact).unwrap();
112 let back: Fact = serde_json::from_str(&json).unwrap();
113 assert_eq!(fact, back);
114 }
115
116 #[test]
117 fn value_display() {
118 assert_eq!(Value::Symbol("TypeScript".into()).to_string(), "TypeScript");
119 assert_eq!(
120 Value::Text("type system".into()).to_string(),
121 "\"type system\""
122 );
123 }
124}