1use std::ffi::{CString, CStr};
2
3#[derive(Debug)]
4pub enum Error {
5FfiNullPtr(std::ffi::NulError),
7 NullPtr,
8}
9
10impl From<std::ffi::NulError> for Error {
11 fn from(other: std::ffi::NulError) -> Error {
12 return Error::FfiNullPtr(other);
13 }
14}
15
16type Result<T> = std::result::Result<T, Error>;
17
18mod ffi {
19 include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
20}
21
22#[derive(Debug)]
23pub struct PathInfo {
24 pub path: String,
25 pub deriver: String,
26 pub nar_hash: String,
27 pub references: String,
28 pub registration_time: i64,
29 pub nar_size: u64,
30 pub ultimate: bool,
31 pub signatures: String,
32 pub ca: String,
33}
34
35impl PathInfo {
36 fn from_cpathinfo(cpi: &ffi::CPathInfo) -> Self {
37 Self {
38 path: unsafe { CStr::from_ptr(cpi.path).to_string_lossy().to_string() },
39 deriver: unsafe { CStr::from_ptr(cpi.deriver).to_string_lossy().to_string() },
40 nar_hash: unsafe { CStr::from_ptr(cpi.narHash).to_string_lossy().to_string() },
41 references: unsafe { CStr::from_ptr(cpi.references).to_string_lossy().to_string() },
42 registration_time: cpi.registrationTime as i64,
43 nar_size: cpi.narSize,
44 ultimate: cpi.ultimate != 0,
45 signatures: unsafe { CStr::from_ptr(cpi.signatures).to_string_lossy().to_string() },
46 ca: unsafe { CStr::from_ptr(cpi.ca).to_string_lossy().to_string() },
47 }
48 }
49}
50
51#[derive(Debug)]
52pub struct Instance {
53 instp: *mut ffi::nixstorec_instance,
54}
55
56unsafe impl Send for Instance {}
57impl Drop for Instance {
58 fn drop(&mut self) {
59 unsafe { ffi::nixstorec_free_instance(self.instp) };
60 }
61}
62
63impl Instance {
64 pub fn new() -> Result<Instance> {
65 let instp = unsafe {
66 ffi::nixstorec_new_instance()
67 };
68
69 if instp == 0 as _ {
70 return Err(Error::NullPtr);
71 }
72
73 Ok(Self{
74 instp
75 })
76 }
77
78 pub fn is_valid_path<T: AsRef<str>>(&mut self, path: T) -> Result<bool> {
79 let path = std::ffi::CString::new(path.as_ref())?;
80
81 let c_path = path.as_ptr();
82
83 unsafe {
84 let ret : bool = ffi::nixstorec_is_valid_path(self.instp, c_path) != 0;
85 return Ok(ret);
86 }
87 }
88
89 pub fn query_path_info<T: AsRef<str>>(&mut self, path: T) -> Result<Option<PathInfo>> {
90 let path : CString = std::ffi::CString::new(path.as_ref())?;
91 let c_path = path.as_ptr();
92
93 let c_pathinfo_ptr = unsafe {
94 ffi::nixstorec_query_path_info(self.instp, c_path)
95 };
96
97 if c_pathinfo_ptr == 0 as _ {
98 return Ok(None);
99 }
100
101 let pathinfo = {
102 let c_pathinfo = unsafe { *c_pathinfo_ptr };
103 PathInfo::from_cpathinfo(&c_pathinfo)
104 };
105
106 unsafe { ffi::nixstorec_free_path_info(c_pathinfo_ptr); }
107
108 return Ok(Some(pathinfo));
109 }
110
111 pub fn query_path_from_hash_part<T: AsRef<str>>(&mut self, hash_part: T) -> Result<Option<String>> {
112
113 let hash_path_c = CString::new(hash_part.as_ref())?;
114
115 let path_c = unsafe { ffi::nixstorec_query_path_from_hash_part(self.instp, hash_path_c.as_ptr()) };
116
117 if path_c == 0 as _ {
118 return Err(Error::NullPtr);
119 }
120
121 let path = unsafe {
122 CStr::from_ptr(path_c).to_string_lossy().to_string()
123 };
124
125 unsafe { ffi::nixstorec_free(path_c as _); }
126
127 if path.is_empty() {
128 Ok(None)
129 } else {
130 Ok(Some(path))
131 }
132 }
133
134 pub fn query_path_from_file_hash<T: AsRef<str>>(&mut self, file_hash: T) -> Result<Option<String>> {
135
136 let file_hash_c = CString::new(file_hash.as_ref())?;
137
138 let path_c = unsafe { ffi::nixstorec_query_path_from_file_hash(self.instp, file_hash_c.as_ptr()) };
139
140 if path_c == 0 as _ {
141 return Err(Error::NullPtr);
142 }
143
144 let path = unsafe {
145 CStr::from_ptr(path_c).to_string_lossy().to_string()
146 };
147
148 let ptr = path_c as _;
149
150 unsafe {
151 ffi::nixstorec_free(ptr);
152 }
153
154 if path.is_empty() {
155 Ok(None)
156 } else {
157 Ok(Some(path))
158 }
159 }
160}
161
162
163
164#[cfg(test)]
165mod tests {
166 #[test]
167#[test]
181 fn query_path_info() {
182 for i in 0..100 {
183 let mut instance = super::Instance::new().unwrap();
184 let v = instance.query_path_info("testtesttest");
185 println!("{:?}", v);
186 assert!(v.unwrap().is_none())
187 }
188 }
189}