treasury_import/
dependencies.rs1use treasury_id::AssetId;
2
3use crate::{Dependency, NOT_FOUND, NOT_UTF8, SUCCESS};
4
5pub trait Dependencies {
6 fn get(&self, source: &str, target: &str) -> Result<Option<AssetId>, String>;
8
9 fn get_or_append(
10 &self,
11 source: &str,
12 target: &str,
13 missing: &mut Vec<Dependency>,
14 ) -> Result<Option<AssetId>, String> {
15 match self.get(source, target) {
16 Err(err) => Err(err),
17 Ok(Some(id)) => Ok(Some(id)),
18 Ok(None) => {
19 missing.push(Dependency {
20 source: source.to_owned(),
21 target: target.to_owned(),
22 });
23 Ok(None)
24 }
25 }
26 }
27}
28
29#[repr(transparent)]
30pub struct DependenciesOpaque(u8);
31
32pub type DependenciesGetFn = unsafe extern "C" fn(
33 dependencies: *mut DependenciesOpaque,
34 source_ptr: *const u8,
35 source_len: u32,
36 target_ptr: *const u8,
37 target_len: u32,
38 id_ptr: *mut u64,
39) -> i32;
40
41unsafe extern "C" fn dependencies_get_ffi<F>(
42 dependencies: *mut DependenciesOpaque,
43 source_ptr: *const u8,
44 source_len: u32,
45 target_ptr: *const u8,
46 target_len: u32,
47 id_ptr: *mut u64,
48) -> i32
49where
50 F: FnMut(&str, &str) -> Option<AssetId>,
51{
52 let source =
53 match std::str::from_utf8(std::slice::from_raw_parts(source_ptr, source_len as usize)) {
54 Ok(source) => source,
55 Err(_) => return NOT_UTF8,
56 };
57 let target =
58 match std::str::from_utf8(std::slice::from_raw_parts(target_ptr, target_len as usize)) {
59 Ok(target) => target,
60 Err(_) => return NOT_UTF8,
61 };
62
63 let f = dependencies as *mut F;
64 let f = &mut *f;
65
66 match f(source, target) {
67 None => return NOT_FOUND,
68 Some(id) => {
69 std::ptr::write(id_ptr, id.value().get());
70 return SUCCESS;
71 }
72 }
73}
74
75pub struct DependenciesFFI {
76 pub opaque: *mut DependenciesOpaque,
77 pub get: DependenciesGetFn,
78}
79
80impl DependenciesFFI {
81 pub fn new<F>(f: &mut F) -> Self
82 where
83 F: FnMut(&str, &str) -> Option<AssetId>,
84 {
85 DependenciesFFI {
86 opaque: f as *mut F as _,
87 get: dependencies_get_ffi::<F>,
88 }
89 }
90}
91
92impl Dependencies for DependenciesFFI {
93 fn get(&self, source: &str, target: &str) -> Result<Option<AssetId>, String> {
94 let mut id = 0u64;
95 let result = unsafe {
96 (self.get)(
97 self.opaque,
98 source.as_ptr(),
99 source.len() as u32,
100 target.as_ptr(),
101 target.len() as u32,
102 &mut id,
103 )
104 };
105
106 match result {
107 SUCCESS => match AssetId::new(id) {
108 None => Err(format!("Null AssetId returned from `Dependencies::get`")),
109 Some(id) => Ok(Some(id)),
110 },
111 NOT_FOUND => Ok(None),
112 NOT_UTF8 => Err(format!("Source is not UTF8 while stored in `str`")),
113
114 _ => Err(format!(
115 "Unexpected return code from `Sources::get` FFI: {}",
116 result
117 )),
118 }
119 }
120}