1use std::ffi::{CStr, CString};
2use std::path::Path;
3use std::ptr::{null, null_mut};
4
5use tract_api::*;
6use tract_proxy_sys as sys;
7
8use anyhow::{Context, Result};
9use ndarray::*;
10
11macro_rules! check {
12 ($expr:expr) => {
13 unsafe {
14 if $expr == sys::TRACT_RESULT_TRACT_RESULT_KO {
15 let buf = CStr::from_ptr(sys::tract_get_last_error());
16 Err(anyhow::anyhow!(buf.to_string_lossy().to_string()))
17 } else {
18 Ok(())
19 }
20 }
21 };
22}
23
24macro_rules! wrapper {
25 ($new_type:ident, $c_type:ident, $dest:ident $(, $typ:ty )*) => {
26 #[derive(Debug, Clone)]
27 pub struct $new_type(*mut sys::$c_type $(, $typ)*);
28
29 impl Drop for $new_type {
30 fn drop(&mut self) {
31 unsafe {
32 sys::$dest(&mut self.0);
33 }
34 }
35 }
36 };
37}
38
39pub fn nnef() -> Result<Nnef> {
40 let mut nnef = null_mut();
41 check!(sys::tract_nnef_create(&mut nnef))?;
42 Ok(Nnef(nnef))
43}
44
45pub fn onnx() -> Result<Onnx> {
46 let mut onnx = null_mut();
47 check!(sys::tract_onnx_create(&mut onnx))?;
48 Ok(Onnx(onnx))
49}
50
51pub fn version() -> &'static str {
52 unsafe { CStr::from_ptr(sys::tract_version()).to_str().unwrap() }
53}
54
55wrapper!(Nnef, TractNnef, tract_nnef_destroy);
56impl NnefInterface for Nnef {
57 type Model = Model;
58 fn model_for_path(&self, path: impl AsRef<Path>) -> Result<Model> {
59 let path = path.as_ref();
60 let path = CString::new(
61 path.to_str().with_context(|| format!("Failed to re-encode {path:?} to uff-8"))?,
62 )?;
63 let mut model = null_mut();
64 check!(sys::tract_nnef_model_for_path(self.0, path.as_ptr(), &mut model))?;
65 Ok(Model(model))
66 }
67
68 fn transform_model(&self, model: &mut Self::Model, transform_spec: &str) -> Result<()> {
69 let t = CString::new(transform_spec)?;
70 check!(sys::tract_nnef_transform_model(self.0, model.0, t.as_ptr()))
71 }
72
73 fn enable_tract_core(&mut self) -> Result<()> {
74 check!(sys::tract_nnef_enable_tract_core(self.0))
75 }
76
77 fn enable_tract_extra(&mut self) -> Result<()> {
78 check!(sys::tract_nnef_enable_tract_extra(self.0))
79 }
80
81 fn enable_tract_transformers(&mut self) -> Result<()> {
82 check!(sys::tract_nnef_enable_tract_transformers(self.0))
83 }
84
85 fn enable_onnx(&mut self) -> Result<()> {
86 check!(sys::tract_nnef_enable_onnx(self.0))
87 }
88
89 fn enable_pulse(&mut self) -> Result<()> {
90 check!(sys::tract_nnef_enable_pulse(self.0))
91 }
92
93 fn enable_extended_identifier_syntax(&mut self) -> Result<()> {
94 check!(sys::tract_nnef_enable_extended_identifier_syntax(self.0))
95 }
96
97 fn write_model_to_dir(&self, path: impl AsRef<Path>, model: &Model) -> Result<()> {
98 let path = path.as_ref();
99 let path = CString::new(
100 path.to_str().with_context(|| format!("Failed to re-encode {path:?} to uff-8"))?,
101 )?;
102 check!(sys::tract_nnef_write_model_to_dir(self.0, path.as_ptr(), model.0))?;
103 Ok(())
104 }
105
106 fn write_model_to_tar(&self, path: impl AsRef<Path>, model: &Model) -> Result<()> {
107 let path = path.as_ref();
108 let path = CString::new(
109 path.to_str().with_context(|| format!("Failed to re-encode {path:?} to uff-8"))?,
110 )?;
111 check!(sys::tract_nnef_write_model_to_tar(self.0, path.as_ptr(), model.0))?;
112 Ok(())
113 }
114
115 fn write_model_to_tar_gz(&self, path: impl AsRef<Path>, model: &Model) -> Result<()> {
116 let path = path.as_ref();
117 let path = CString::new(
118 path.to_str().with_context(|| format!("Failed to re-encode {path:?} to uff-8"))?,
119 )?;
120 check!(sys::tract_nnef_write_model_to_tar_gz(self.0, path.as_ptr(), model.0))?;
121 Ok(())
122 }
123}
124
125wrapper!(Onnx, TractOnnx, tract_onnx_destroy);
127
128impl OnnxInterface for Onnx {
129 type InferenceModel = InferenceModel;
130 fn model_for_path(&self, path: impl AsRef<Path>) -> Result<InferenceModel> {
131 let path = path.as_ref();
132 let path = CString::new(
133 path.to_str().with_context(|| format!("Failed to re-encode {path:?} to uff-8"))?,
134 )?;
135 let mut model = null_mut();
136 check!(sys::tract_onnx_model_for_path(self.0, path.as_ptr(), &mut model))?;
137 Ok(InferenceModel(model))
138 }
139}
140
141wrapper!(InferenceModel, TractInferenceModel, tract_inference_model_destroy);
143impl InferenceModelInterface for InferenceModel {
144 type Model = Model;
145 type InferenceFact = InferenceFact;
146 fn set_output_names(
147 &mut self,
148 outputs: impl IntoIterator<Item = impl AsRef<str>>,
149 ) -> Result<()> {
150 let c_strings: Vec<CString> =
151 outputs.into_iter().map(|a| Ok(CString::new(a.as_ref())?)).collect::<Result<_>>()?;
152 let ptrs: Vec<_> = c_strings.iter().map(|cs| cs.as_ptr()).collect();
153 check!(sys::tract_inference_model_set_output_names(
154 self.0,
155 c_strings.len(),
156 ptrs.as_ptr()
157 ))?;
158 Ok(())
159 }
160
161 fn input_count(&self) -> Result<usize> {
162 let mut count = 0;
163 check!(sys::tract_inference_model_input_count(self.0, &mut count))?;
164 Ok(count)
165 }
166
167 fn output_count(&self) -> Result<usize> {
168 let mut count = 0;
169 check!(sys::tract_inference_model_output_count(self.0, &mut count))?;
170 Ok(count)
171 }
172
173 fn input_name(&self, id: usize) -> Result<String> {
174 let mut ptr = null_mut();
175 check!(sys::tract_inference_model_input_name(self.0, id, &mut ptr))?;
176 unsafe {
177 let ret = CStr::from_ptr(ptr).to_str()?.to_owned();
178 sys::tract_free_cstring(ptr);
179 Ok(ret)
180 }
181 }
182
183 fn output_name(&self, id: usize) -> Result<String> {
184 let mut ptr = null_mut();
185 check!(sys::tract_inference_model_output_name(self.0, id, &mut ptr))?;
186 unsafe {
187 let ret = CStr::from_ptr(ptr).to_str()?.to_owned();
188 sys::tract_free_cstring(ptr);
189 Ok(ret)
190 }
191 }
192
193 fn input_fact(&self, id: usize) -> Result<InferenceFact> {
194 let mut ptr = null_mut();
195 check!(sys::tract_inference_model_input_fact(self.0, id, &mut ptr))?;
196 Ok(InferenceFact(ptr))
197 }
198
199 fn set_input_fact(
200 &mut self,
201 id: usize,
202 fact: impl AsFact<Self, Self::InferenceFact>,
203 ) -> Result<()> {
204 let fact = fact.as_fact(self)?;
205 check!(sys::tract_inference_model_set_input_fact(self.0, id, fact.0))?;
206 Ok(())
207 }
208
209 fn output_fact(&self, id: usize) -> Result<InferenceFact> {
210 let mut ptr = null_mut();
211 check!(sys::tract_inference_model_output_fact(self.0, id, &mut ptr))?;
212 Ok(InferenceFact(ptr))
213 }
214
215 fn set_output_fact(
216 &mut self,
217 id: usize,
218 fact: impl AsFact<InferenceModel, InferenceFact>,
219 ) -> Result<()> {
220 let fact = fact.as_fact(self)?;
221 check!(sys::tract_inference_model_set_output_fact(self.0, id, fact.0))?;
222 Ok(())
223 }
224
225 fn analyse(&mut self) -> Result<()> {
226 check!(sys::tract_inference_model_analyse(self.0))?;
227 Ok(())
228 }
229
230 fn into_typed(mut self) -> Result<Self::Model> {
231 let mut ptr = null_mut();
232 check!(sys::tract_inference_model_into_typed(&mut self.0, &mut ptr))?;
233 Ok(Model(ptr))
234 }
235
236 fn into_optimized(mut self) -> Result<Self::Model> {
237 let mut ptr = null_mut();
238 check!(sys::tract_inference_model_into_optimized(&mut self.0, &mut ptr))?;
239 Ok(Model(ptr))
240 }
241}
242
243wrapper!(Model, TractModel, tract_model_destroy);
245
246impl ModelInterface for Model {
247 type Fact = Fact;
248 type Value = Value;
249 type Runnable = Runnable;
250 fn input_count(&self) -> Result<usize> {
251 let mut count = 0;
252 check!(sys::tract_model_input_count(self.0, &mut count))?;
253 Ok(count)
254 }
255
256 fn output_count(&self) -> Result<usize> {
257 let mut count = 0;
258 check!(sys::tract_model_output_count(self.0, &mut count))?;
259 Ok(count)
260 }
261
262 fn input_name(&self, id: usize) -> Result<String> {
263 let mut ptr = null_mut();
264 check!(sys::tract_model_input_name(self.0, id, &mut ptr))?;
265 unsafe {
266 let ret = CStr::from_ptr(ptr).to_str()?.to_owned();
267 sys::tract_free_cstring(ptr);
268 Ok(ret)
269 }
270 }
271
272 fn output_name(&self, id: usize) -> Result<String> {
273 let mut ptr = null_mut();
274 check!(sys::tract_model_output_name(self.0, id, &mut ptr))?;
275 unsafe {
276 let ret = CStr::from_ptr(ptr).to_str()?.to_owned();
277 sys::tract_free_cstring(ptr);
278 Ok(ret)
279 }
280 }
281
282 fn set_output_names(
283 &mut self,
284 outputs: impl IntoIterator<Item = impl AsRef<str>>,
285 ) -> Result<()> {
286 let c_strings: Vec<CString> =
287 outputs.into_iter().map(|a| Ok(CString::new(a.as_ref())?)).collect::<Result<_>>()?;
288 let ptrs: Vec<_> = c_strings.iter().map(|cs| cs.as_ptr()).collect();
289 check!(sys::tract_model_set_output_names(self.0, c_strings.len(), ptrs.as_ptr()))?;
290 Ok(())
291 }
292
293 fn input_fact(&self, id: usize) -> Result<Fact> {
294 let mut ptr = null_mut();
295 check!(sys::tract_model_input_fact(self.0, id, &mut ptr))?;
296 Ok(Fact(ptr))
297 }
298
299 fn output_fact(&self, id: usize) -> Result<Fact> {
300 let mut ptr = null_mut();
301 check!(sys::tract_model_output_fact(self.0, id, &mut ptr))?;
302 Ok(Fact(ptr))
303 }
304
305 fn declutter(&mut self) -> Result<()> {
306 check!(sys::tract_model_declutter(self.0))?;
307 Ok(())
308 }
309
310 fn optimize(&mut self) -> Result<()> {
311 check!(sys::tract_model_optimize(self.0))?;
312 Ok(())
313 }
314
315 fn into_decluttered(self) -> Result<Model> {
316 check!(sys::tract_model_declutter(self.0))?;
317 Ok(self)
318 }
319
320 fn into_optimized(self) -> Result<Model> {
321 check!(sys::tract_model_optimize(self.0))?;
322 Ok(self)
323 }
324
325 fn into_runnable(self) -> Result<Runnable> {
326 let mut model = self;
327 let mut runnable = null_mut();
328 check!(sys::tract_model_into_runnable(&mut model.0, &mut runnable))?;
329 Ok(Runnable(runnable))
330 }
331
332 fn concretize_symbols(
333 &mut self,
334 values: impl IntoIterator<Item = (impl AsRef<str>, i64)>,
335 ) -> Result<()> {
336 let (names, values): (Vec<_>, Vec<_>) = values.into_iter().unzip();
337 let c_strings: Vec<CString> =
338 names.into_iter().map(|a| Ok(CString::new(a.as_ref())?)).collect::<Result<_>>()?;
339 let ptrs: Vec<_> = c_strings.iter().map(|cs| cs.as_ptr()).collect();
340 check!(sys::tract_model_concretize_symbols(
341 self.0,
342 ptrs.len(),
343 ptrs.as_ptr(),
344 values.as_ptr()
345 ))?;
346 Ok(())
347 }
348
349 fn transform(&mut self, transform: &str) -> Result<()> {
350 let t = CString::new(transform)?;
351 check!(sys::tract_model_transform(self.0, t.as_ptr()))?;
352 Ok(())
353 }
354
355 fn pulse(&mut self, name: impl AsRef<str>, value: impl AsRef<str>) -> Result<()> {
356 let name = CString::new(name.as_ref())?;
357 let value = CString::new(value.as_ref())?;
358 check!(sys::tract_model_pulse_simple(&mut self.0, name.as_ptr(), value.as_ptr()))?;
359 Ok(())
360 }
361
362 fn cost_json(&self) -> Result<String> {
363 let input: Option<Vec<Value>> = None;
364 let states: Option<Vec<Value>> = None;
365 self.profile_json(input, states)
366 }
367
368 fn profile_json<I, IV, IE, S, SV, SE>(
369 &self,
370 inputs: Option<I>,
371 state_initializers: Option<S>,
372 ) -> Result<String>
373 where
374 I: IntoIterator<Item = IV>,
375 IV: TryInto<Self::Value, Error = IE>,
376 IE: Into<anyhow::Error>,
377 S: IntoIterator<Item = SV>,
378 SV: TryInto<Self::Value, Error = SE>,
379 SE: Into<anyhow::Error>,
380 {
381 let inputs = if let Some(inputs) = inputs {
382 let inputs = inputs
383 .into_iter()
384 .map(|i| i.try_into().map_err(|e| e.into()))
385 .collect::<Result<Vec<Value>>>()?;
386 anyhow::ensure!(self.input_count()? == inputs.len());
387 Some(inputs)
388 } else {
389 None
390 };
391 let mut iptrs: Option<Vec<*mut sys::TractValue>> =
392 inputs.as_ref().map(|is| is.iter().map(|v| v.0).collect());
393 let mut json: *mut i8 = null_mut();
394 let values = iptrs.as_mut().map(|it| it.as_mut_ptr()).unwrap_or(null_mut());
395
396 let (state_inits, n_states) = if let Some(state_vec) = state_initializers {
397 let mut states: Vec<*const _> = vec![];
398
399 for v in state_vec {
400 let val: Value = v.try_into().map_err(|e| e.into())?;
401 states.push(val.0);
402 }
403 let len = states.len();
404 (Some(states), len)
405 } else {
406 (None, 0)
407 };
408
409 let states = state_inits.map(|is| is.as_ptr()).unwrap_or(null());
410 check!(sys::tract_model_profile_json(self.0, values, states, n_states, &mut json))?;
411 anyhow::ensure!(!json.is_null());
412 unsafe {
413 let s = CStr::from_ptr(json).to_owned();
414 sys::tract_free_cstring(json);
415 Ok(s.to_str()?.to_owned())
416 }
417 }
418
419 fn property_keys(&self) -> Result<Vec<String>> {
420 let mut len = 0;
421 check!(sys::tract_model_property_count(self.0, &mut len))?;
422 let mut keys = vec![null_mut(); len];
423 check!(sys::tract_model_property_names(self.0, keys.as_mut_ptr()))?;
424 unsafe {
425 keys.into_iter()
426 .map(|pc| {
427 let s = CStr::from_ptr(pc).to_str()?.to_owned();
428 sys::tract_free_cstring(pc);
429 Ok(s)
430 })
431 .collect()
432 }
433 }
434
435 fn property(&self, name: impl AsRef<str>) -> Result<Value> {
436 let mut v = null_mut();
437 let name = CString::new(name.as_ref())?;
438 check!(sys::tract_model_property(self.0, name.as_ptr(), &mut v))?;
439 Ok(Value(v))
440 }
441}
442
443wrapper!(Runnable, TractRunnable, tract_runnable_release);
445
446impl RunnableInterface for Runnable {
447 type Value = Value;
448 type State = State;
449
450 fn run<I, V, E>(&self, inputs: I) -> Result<Vec<Value>>
451 where
452 I: IntoIterator<Item = V>,
453 V: TryInto<Value, Error = E>,
454 E: Into<anyhow::Error>,
455 {
456 self.spawn_state()?.run(inputs)
457 }
458
459 fn spawn_state(&self) -> Result<State> {
460 let mut state = null_mut();
461 check!(sys::tract_runnable_spawn_state(self.0, &mut state))?;
462 Ok(State(state))
463 }
464
465 fn input_count(&self) -> Result<usize> {
466 let mut count = 0;
467 check!(sys::tract_runnable_input_count(self.0, &mut count))?;
468 Ok(count)
469 }
470
471 fn output_count(&self) -> Result<usize> {
472 let mut count = 0;
473 check!(sys::tract_runnable_output_count(self.0, &mut count))?;
474 Ok(count)
475 }
476}
477
478wrapper!(State, TractState, tract_state_destroy);
480
481impl StateInterface for State {
482 type Value = Value;
483 type Fact = Fact;
484
485 fn run<I, V, E>(&mut self, inputs: I) -> Result<Vec<Value>>
486 where
487 I: IntoIterator<Item = V>,
488 V: TryInto<Value, Error = E>,
489 E: Into<anyhow::Error>,
490 {
491 let inputs = inputs
492 .into_iter()
493 .map(|i| i.try_into().map_err(|e| e.into()))
494 .collect::<Result<Vec<Value>>>()?;
495 let mut outputs = vec![null_mut(); self.output_count()?];
496 let mut inputs: Vec<_> = inputs.iter().map(|v| v.0).collect();
497 check!(sys::tract_state_run(self.0, inputs.as_mut_ptr(), outputs.as_mut_ptr()))?;
498 let outputs = outputs.into_iter().map(Value).collect();
499 Ok(outputs)
500 }
501
502 fn input_count(&self) -> Result<usize> {
503 let mut count = 0;
504 check!(sys::tract_state_input_count(self.0, &mut count))?;
505 Ok(count)
506 }
507
508 fn output_count(&self) -> Result<usize> {
509 let mut count = 0;
510 check!(sys::tract_state_output_count(self.0, &mut count))?;
511 Ok(count)
512 }
513
514 fn initializable_states_count(&self) -> Result<usize> {
515 let mut n_states = 0;
516 check!(sys::tract_state_initializable_states_count(self.0, &mut n_states))?;
517 Ok(n_states)
518 }
519
520 fn get_states_facts(&self) -> Result<Vec<Fact>> {
521 let n_states = self.initializable_states_count()?;
522 let mut fptrs = vec![null_mut(); n_states];
523
524 check!(sys::tract_state_get_states_facts(self.0, fptrs.as_mut_ptr()))?;
525
526 let res = fptrs.into_iter().map(|value| Ok(Fact(value))).collect::<Result<Vec<Fact>>>();
527
528 res
529 }
530
531 fn set_states<I, V, E>(&mut self, state_initializers: I) -> Result<()>
532 where
533 I: IntoIterator<Item = V>,
534 V: TryInto<Self::Value, Error = E>,
535 E: Into<anyhow::Error>,
536 {
537 let sptrs = {
538 let mut states: Vec<*const _> = vec![];
539
540 for s in state_initializers {
541 let val: Value = s.try_into().map_err(|e| e.into())?;
542 states.push(val.0);
543 }
544
545 let len = states.len();
546 anyhow::ensure!(
547 len == self.initializable_states_count()?,
548 "Expected {} states, got {len}",
549 self.initializable_states_count()?
550 );
551 Some(states)
552 };
553
554 let sptrs = sptrs.map(|it| it.as_ptr()).unwrap_or(null());
555 check!(sys::tract_state_set_states(self.0, sptrs))?;
556
557 Ok(())
558 }
559
560 fn get_states(&self) -> Result<Vec<Self::Value>> {
561 let n_states = self.initializable_states_count()?;
562
563 let mut sptrs = vec![null_mut(); n_states];
564 check!(sys::tract_state_get_states(self.0, sptrs.as_mut_ptr()))?;
565
566 let res = sptrs.into_iter().map(|value| Ok(Value(value))).collect::<Result<Vec<Value>>>();
567
568 res
569 }
570}
571
572wrapper!(Value, TractValue, tract_value_destroy);
574
575impl ValueInterface for Value {
576 fn from_bytes(dt: DatumType, shape: &[usize], data: &[u8]) -> Result<Self> {
577 anyhow::ensure!(data.len() == shape.iter().product::<usize>() * dt.size_of());
578 let mut value = null_mut();
579 check!(sys::tract_value_from_bytes(
580 dt as _,
581 shape.len(),
582 shape.as_ptr(),
583 data.as_ptr() as _,
584 &mut value
585 ))?;
586 Ok(Value(value))
587 }
588
589 fn as_bytes(&self) -> Result<(DatumType, &[usize], &[u8])> {
590 let mut rank = 0;
591 let mut dt = sys::DatumType_TRACT_DATUM_TYPE_BOOL as _;
592 let mut shape = null();
593 let mut data = null();
594 check!(sys::tract_value_as_bytes(self.0, &mut dt, &mut rank, &mut shape, &mut data))?;
595 unsafe {
596 let dt: DatumType = std::mem::transmute(dt);
597 let shape = std::slice::from_raw_parts(shape, rank);
598 let len: usize = shape.iter().product();
599 let data = std::slice::from_raw_parts(data as *const u8, len * dt.size_of());
600 Ok((dt, shape, data))
601 }
602 }
603}
604
605value_from_to_ndarray!();
606
607wrapper!(Fact, TractFact, tract_fact_destroy);
609
610impl Fact {
611 fn new(model: &mut Model, spec: impl ToString) -> Result<Fact> {
612 let cstr = CString::new(spec.to_string())?;
613 let mut fact = null_mut();
614 check!(sys::tract_fact_parse(model.0, cstr.as_ptr(), &mut fact))?;
615 Ok(Fact(fact))
616 }
617
618 fn dump(&self) -> Result<String> {
619 let mut ptr = null_mut();
620 check!(sys::tract_fact_dump(self.0, &mut ptr))?;
621 unsafe {
622 let s = CStr::from_ptr(ptr).to_owned();
623 sys::tract_free_cstring(ptr);
624 Ok(s.to_str()?.to_owned())
625 }
626 }
627}
628
629impl FactInterface for Fact {}
630
631impl std::fmt::Display for Fact {
632 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
633 match self.dump() {
634 Ok(s) => f.write_str(&s),
635 Err(_) => Err(std::fmt::Error),
636 }
637 }
638}
639
640wrapper!(InferenceFact, TractInferenceFact, tract_inference_fact_destroy);
642
643impl InferenceFact {
644 fn new(model: &mut InferenceModel, spec: impl ToString) -> Result<InferenceFact> {
645 let cstr = CString::new(spec.to_string())?;
646 let mut fact = null_mut();
647 check!(sys::tract_inference_fact_parse(model.0, cstr.as_ptr(), &mut fact))?;
648 Ok(InferenceFact(fact))
649 }
650
651 fn dump(&self) -> Result<String> {
652 let mut ptr = null_mut();
653 check!(sys::tract_inference_fact_dump(self.0, &mut ptr))?;
654 unsafe {
655 let s = CStr::from_ptr(ptr).to_owned();
656 sys::tract_free_cstring(ptr);
657 Ok(s.to_str()?.to_owned())
658 }
659 }
660}
661
662impl InferenceFactInterface for InferenceFact {
663 fn empty() -> Result<InferenceFact> {
664 let mut fact = null_mut();
665 check!(sys::tract_inference_fact_empty(&mut fact))?;
666 Ok(InferenceFact(fact))
667 }
668}
669
670impl Default for InferenceFact {
671 fn default() -> Self {
672 Self::empty().unwrap()
673 }
674}
675
676impl std::fmt::Display for InferenceFact {
677 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
678 match self.dump() {
679 Ok(s) => f.write_str(&s),
680 Err(_) => Err(std::fmt::Error),
681 }
682 }
683}
684
685as_inference_fact_impl!(InferenceModel, InferenceFact);
686as_fact_impl!(Model, Fact);