eclair_bindings/
lib.rs

1pub mod bindings;
2pub mod internal;
3pub mod marshal;
4
5use std::marker::PhantomData;
6
7pub struct Program<T> {
8    prog: internal::Program,
9    _marker: PhantomData<T>,
10}
11
12// Structs used to indicate fact direction at the type level
13pub struct Input;
14pub struct Output;
15pub struct InputOutput;
16
17pub trait Fact<Prog> {
18    type DIRECTION: Direction;
19    const COLUMN_COUNT: u32;
20    const FACT_NAME: &'static str;
21}
22
23impl<P> Program<P> {
24    pub fn new(_handle: P) -> Self {
25        Self {
26            prog: internal::Program::new(),
27            _marker: PhantomData,
28        }
29    }
30
31    pub fn run(&mut self) {
32        self.prog.run()
33    }
34
35    // NOTE: for now mut is needed since we need to potentially
36    // mutate the runtime (by encoding a Eclair string)
37    // TODO: create a "try_lookup_string" in Eclair that does no mutation
38    pub fn get_facts<FactType>(&mut self) -> ReadBufferIterator<FactType>
39    where
40        PhantomData<FactType>: Fact<P>,
41        <PhantomData<FactType> as Fact<P>>::DIRECTION: IsOutput,
42    {
43        let name = <PhantomData<FactType> as Fact<P>>::FACT_NAME;
44        let fact_type_idx = self.prog.encode_string(name).0;
45        ReadBufferIterator::new(&self.prog, fact_type_idx)
46    }
47
48    pub fn add_fact<FactType>(&mut self, fact: FactType)
49    where
50        PhantomData<FactType>: Fact<P>,
51        <PhantomData<FactType> as Fact<P>>::DIRECTION: IsInput,
52        FactType: marshal::Marshal,
53    {
54        let name = <PhantomData<FactType> as Fact<P>>::FACT_NAME;
55        let column_count = <PhantomData<FactType> as Fact<P>>::COLUMN_COUNT;
56        let fact_type_idx = self.prog.encode_string(name).0;
57
58        // TODO can we avoid a heap allocation here?
59        let mut vec: Vec<u32> = Vec::with_capacity(column_count as usize);
60        let buf_ptr = vec.as_mut_ptr();
61        let mut cursor = marshal::WriteCursor::new(&mut self.prog, buf_ptr);
62        fact.serialize(&mut cursor);
63        self.prog.add_fact(fact_type_idx, buf_ptr);
64    }
65
66    pub fn add_facts<FactType, Iter>(&mut self, facts: Iter)
67    where
68        Iter: ExactSizeIterator<Item = FactType>,
69        FactType: marshal::Marshal,
70        PhantomData<FactType>: Fact<P>,
71        <PhantomData<FactType> as Fact<P>>::DIRECTION: IsInput,
72    {
73        let name = <PhantomData<FactType> as Fact<P>>::FACT_NAME;
74        let fact_type_idx = self.prog.encode_string(name).0;
75        let fact_count = facts.len();
76        let column_count = <PhantomData<FactType> as Fact<P>>::COLUMN_COUNT as usize;
77        let vec_size = fact_count * column_count;
78
79        let mut vec: Vec<u32> = Vec::with_capacity(vec_size);
80        let buf_ptr = vec.as_mut_ptr();
81        let mut cursor = marshal::WriteCursor::new(&mut self.prog, buf_ptr);
82        for fact in facts {
83            fact.serialize(&mut cursor);
84        }
85
86        self.prog.add_facts(fact_type_idx, buf_ptr, fact_count);
87    }
88}
89
90pub struct ReadBufferIterator<'a, T> {
91    cursor: marshal::ReadCursor<'a>,
92    count: usize,
93    current: usize,
94    _buf: internal::Buffer, // used for automatic cleanup
95    _marker: PhantomData<T>,
96}
97
98impl<'a, T> ReadBufferIterator<'a, T> {
99    fn new(prog: &'a internal::Program, fact_type_idx: u32) -> Self {
100        let count = prog.fact_count(fact_type_idx);
101        let buf = prog.get_facts(fact_type_idx);
102        let buf_ptr = buf.ptr;
103        Self {
104            cursor: marshal::ReadCursor::new(prog, buf_ptr),
105            count,
106            current: 0,
107            _buf: buf,
108            _marker: PhantomData,
109        }
110    }
111}
112
113impl<'a, T: marshal::Marshal> Iterator for ReadBufferIterator<'a, T> {
114    type Item = T;
115
116    fn next(&mut self) -> Option<T> {
117        if self.count == self.current {
118            None
119        } else {
120            let unmarshalled = marshal::Marshal::deserialize(&mut self.cursor);
121            self.current += 1;
122            Some(unmarshalled)
123        }
124    }
125
126    fn size_hint(&self) -> (usize, Option<usize>) {
127        let count = self.len();
128        (count, Some(count))
129    }
130}
131
132impl<'a, T: marshal::Marshal> ExactSizeIterator for ReadBufferIterator<'a, T> {
133    fn len(&self) -> usize {
134        self.count
135    }
136}
137
138// Some type level programming to avoid misuse of facts
139pub trait Direction: sealed::Direction {}
140impl Direction for Input {}
141impl Direction for Output {}
142impl Direction for InputOutput {}
143
144pub trait IsInput: sealed::IsInput {}
145impl IsInput for Input {}
146impl IsInput for InputOutput {}
147
148pub trait IsOutput: sealed::IsOutput {}
149impl IsOutput for Output {}
150impl IsOutput for InputOutput {}
151
152mod sealed {
153    // Sealed traits so no external code can derive extra implementations
154    pub trait Direction {}
155    impl Direction for super::Input {}
156    impl Direction for super::Output {}
157    impl Direction for super::InputOutput {}
158
159    pub trait IsInput {}
160    impl IsInput for super::Input {}
161    impl IsInput for super::InputOutput {}
162
163    pub trait IsOutput {}
164    impl IsOutput for super::Output {}
165    impl IsOutput for super::InputOutput {}
166}