Skip to main content

oxihuman_core/
specification_pattern.rs

1// Copyright (C) 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3#![allow(dead_code)]
4
5pub struct Spec {
6    pub name: String,
7    pub predicate_desc: String,
8}
9
10pub fn new_spec(name: &str, desc: &str) -> Spec {
11    Spec {
12        name: name.to_string(),
13        predicate_desc: desc.to_string(),
14    }
15}
16
17pub fn spec_and(a: &Spec, b: &Spec) -> Spec {
18    Spec {
19        name: format!("({} AND {})", a.name, b.name),
20        predicate_desc: format!("({}) AND ({})", a.predicate_desc, b.predicate_desc),
21    }
22}
23
24pub fn spec_or(a: &Spec, b: &Spec) -> Spec {
25    Spec {
26        name: format!("({} OR {})", a.name, b.name),
27        predicate_desc: format!("({}) OR ({})", a.predicate_desc, b.predicate_desc),
28    }
29}
30
31pub fn spec_not(a: &Spec) -> Spec {
32    Spec {
33        name: format!("NOT({})", a.name),
34        predicate_desc: format!("NOT({})", a.predicate_desc),
35    }
36}
37
38pub fn spec_range(lo: i64, hi: i64) -> Spec {
39    Spec {
40        name: format!("range({},{})", lo, hi),
41        predicate_desc: format!("value in [{},{}]", lo, hi),
42    }
43}
44
45pub fn spec_name(s: &Spec) -> &str {
46    &s.name
47}
48
49pub fn spec_satisfies_range(s: &Spec, val: i64, lo: i64, hi: i64) -> bool {
50    let _ = s;
51    val >= lo && val <= hi
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57
58    #[test]
59    fn test_new_spec() {
60        /* create a spec with name and desc */
61        let s = new_spec("positive", "value > 0");
62        assert_eq!(spec_name(&s), "positive");
63    }
64
65    #[test]
66    fn test_spec_and() {
67        /* AND composition includes both names */
68        let a = new_spec("A", "a");
69        let b = new_spec("B", "b");
70        let c = spec_and(&a, &b);
71        assert!(c.name.contains("AND"));
72    }
73
74    #[test]
75    fn test_spec_or() {
76        /* OR composition includes both names */
77        let a = new_spec("A", "a");
78        let b = new_spec("B", "b");
79        let c = spec_or(&a, &b);
80        assert!(c.name.contains("OR"));
81    }
82
83    #[test]
84    fn test_spec_not() {
85        /* NOT composition wraps name */
86        let a = new_spec("A", "a");
87        let c = spec_not(&a);
88        assert!(c.name.contains("NOT"));
89    }
90
91    #[test]
92    fn test_spec_range() {
93        /* range spec has proper name */
94        let s = spec_range(0, 100);
95        assert!(s.name.contains("range"));
96    }
97
98    #[test]
99    fn test_spec_satisfies_range() {
100        /* check value in range */
101        let s = spec_range(0, 10);
102        assert!(spec_satisfies_range(&s, 5, 0, 10));
103        assert!(!spec_satisfies_range(&s, 11, 0, 10));
104    }
105}