1use serde::{Deserialize, Serialize};
33
34pub use crate::uniffi_types::{
36 BenchErrorVariant, BenchReportTemplate, BenchSampleTemplate, BenchSpecTemplate, FromSdkError,
37 FromSdkReport, FromSdkSample, FromSdkSpec,
38};
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct BenchSpecFfi {
45 pub name: String,
47 pub iterations: u32,
49 pub warmup: u32,
51}
52
53impl From<crate::BenchSpec> for BenchSpecFfi {
54 fn from(spec: crate::BenchSpec) -> Self {
55 Self {
56 name: spec.name,
57 iterations: spec.iterations,
58 warmup: spec.warmup,
59 }
60 }
61}
62
63impl From<BenchSpecFfi> for crate::BenchSpec {
64 fn from(spec: BenchSpecFfi) -> Self {
65 Self {
66 name: spec.name,
67 iterations: spec.iterations,
68 warmup: spec.warmup,
69 }
70 }
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct BenchSampleFfi {
76 pub duration_ns: u64,
78}
79
80impl From<crate::BenchSample> for BenchSampleFfi {
81 fn from(sample: crate::BenchSample) -> Self {
82 Self {
83 duration_ns: sample.duration_ns,
84 }
85 }
86}
87
88impl From<BenchSampleFfi> for crate::BenchSample {
89 fn from(sample: BenchSampleFfi) -> Self {
90 Self {
91 duration_ns: sample.duration_ns,
92 }
93 }
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct BenchReportFfi {
99 pub spec: BenchSpecFfi,
101 pub samples: Vec<BenchSampleFfi>,
103}
104
105impl From<crate::RunnerReport> for BenchReportFfi {
106 fn from(report: crate::RunnerReport) -> Self {
107 Self {
108 spec: report.spec.into(),
109 samples: report.samples.into_iter().map(Into::into).collect(),
110 }
111 }
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize)]
116pub enum BenchErrorFfi {
117 InvalidIterations,
119 UnknownFunction { name: String },
121 ExecutionFailed { reason: String },
123 ConfigError { message: String },
125 IoError { message: String },
127}
128
129impl From<crate::types::BenchError> for BenchErrorFfi {
130 fn from(err: crate::types::BenchError) -> Self {
131 match err {
132 crate::types::BenchError::Runner(runner_err) => match runner_err {
133 crate::timing::TimingError::NoIterations { .. } => BenchErrorFfi::InvalidIterations,
134 crate::timing::TimingError::Execution(msg) => {
135 BenchErrorFfi::ExecutionFailed { reason: msg }
136 }
137 },
138 crate::types::BenchError::UnknownFunction(name, _) => {
139 BenchErrorFfi::UnknownFunction { name }
140 }
141 crate::types::BenchError::Execution(msg) => {
142 BenchErrorFfi::ExecutionFailed { reason: msg }
143 }
144 crate::types::BenchError::Io(e) => BenchErrorFfi::IoError {
145 message: e.to_string(),
146 },
147 crate::types::BenchError::Serialization(e) => BenchErrorFfi::ConfigError {
148 message: e.to_string(),
149 },
150 crate::types::BenchError::Config(msg) => BenchErrorFfi::ConfigError { message: msg },
151 crate::types::BenchError::Build(msg) => BenchErrorFfi::ExecutionFailed {
152 reason: format!("build error: {}", msg),
153 },
154 }
155 }
156}
157
158pub trait IntoFfi<T> {
160 fn into_ffi(self) -> T;
162}
163
164pub trait FromFfi<T> {
166 fn from_ffi(ffi: T) -> Self;
168}
169
170impl<T, U> IntoFfi<U> for T
172where
173 U: From<T>,
174{
175 fn into_ffi(self) -> U {
176 U::from(self)
177 }
178}
179
180impl<T, U> FromFfi<U> for T
181where
182 T: From<U>,
183{
184 fn from_ffi(ffi: U) -> Self {
185 T::from(ffi)
186 }
187}
188
189#[cfg(feature = "full")]
193pub fn run_benchmark_ffi(spec: BenchSpecFfi) -> Result<BenchReportFfi, BenchErrorFfi> {
194 let sdk_spec: crate::BenchSpec = spec.into();
195 crate::run_benchmark(sdk_spec)
196 .map(Into::into)
197 .map_err(Into::into)
198}
199
200#[cfg(test)]
201mod tests {
202 use super::*;
203
204 #[test]
205 fn test_bench_spec_ffi_conversion() {
206 let sdk_spec = crate::BenchSpec {
207 name: "test".to_string(),
208 iterations: 100,
209 warmup: 10,
210 };
211
212 let ffi: BenchSpecFfi = sdk_spec.clone().into();
213 assert_eq!(ffi.name, "test");
214 assert_eq!(ffi.iterations, 100);
215 assert_eq!(ffi.warmup, 10);
216
217 let back: crate::BenchSpec = ffi.into();
218 assert_eq!(back.name, sdk_spec.name);
219 }
220
221 #[test]
222 fn test_bench_sample_ffi_conversion() {
223 let sdk_sample = crate::BenchSample { duration_ns: 12345 };
224 let ffi: BenchSampleFfi = sdk_sample.into();
225 assert_eq!(ffi.duration_ns, 12345);
226 }
227
228 #[test]
229 fn test_bench_report_ffi_conversion() {
230 let report = crate::RunnerReport {
231 spec: crate::BenchSpec {
232 name: "test".to_string(),
233 iterations: 2,
234 warmup: 1,
235 },
236 samples: vec![
237 crate::BenchSample { duration_ns: 100 },
238 crate::BenchSample { duration_ns: 200 },
239 ],
240 };
241
242 let ffi: BenchReportFfi = report.into();
243 assert_eq!(ffi.spec.name, "test");
244 assert_eq!(ffi.samples.len(), 2);
245 assert_eq!(ffi.samples[0].duration_ns, 100);
246 }
247
248 #[test]
249 fn test_into_ffi_trait() {
250 let spec = crate::BenchSpec {
251 name: "test".to_string(),
252 iterations: 50,
253 warmup: 5,
254 };
255
256 let ffi: BenchSpecFfi = spec.into_ffi();
257 assert_eq!(ffi.iterations, 50);
258 }
259}