circle_of_confusion/
lib.rs

1#![doc = include_str!("../README.md")]
2#![cfg_attr(not(feature = "std"), no_std)]
3
4mod calculator;
5mod datamodel {
6    include!(concat!(env!("OUT_DIR"), "/circle_of_confusion.rs"));
7}
8
9pub use crate::datamodel::*;
10
11#[cfg(feature = "wasm-bindings")]
12mod wasm {
13    /// As wasm memory is linear, the memory starts at null. But this doesn't work well with LTO.
14    const PTR_OFFSET: usize = 1;
15
16    use crate::ffi_result::ResultValue;
17
18    use super::*;
19    use prost::Message;
20
21    fn get_result_protobuf() -> Result<(&'static mut [u8], FfiResult), usize> {
22        let ptr = (get_calculator_size() + PTR_OFFSET) as *mut u8;
23        let len = get_result_size();
24        let result_buffer = unsafe { core::slice::from_raw_parts_mut(ptr, len) };
25        let current_result = FfiResult::default();
26        Ok((result_buffer, current_result))
27    }
28
29    #[unsafe(no_mangle)]
30    /// Get the max size of the Calculator object.
31    pub extern "C" fn get_settings_size() -> usize {
32        size_of::<Settings>()
33            + size_of::<CameraData>()
34            + size_of::<Filmback>()
35            + size_of::<Resolution>()
36            + size_of::<WorldUnit>()
37            + size_of::<Math>()
38    }
39
40    #[unsafe(no_mangle)]
41    /// Get the max size of the Calculator object.
42    pub extern "C" fn get_calculator_size() -> usize {
43        size_of::<Calculator>() + size_of::<DepthOfField>() + get_settings_size()
44    }
45
46    #[unsafe(no_mangle)]
47    /// Get the max size of the Result object.
48    pub extern "C" fn get_result_size() -> usize {
49        size_of::<FfiResult>()
50    }
51
52    /// Wrapper for the inner calculator to work with results
53    unsafe fn initialize_calculator_inner(
54        settings_size: usize,
55    ) -> Result<Calculator, FfiError> {
56        let address = PTR_OFFSET as *mut u8;
57        let settings = unsafe {
58            let data = core::slice::from_raw_parts(address, settings_size);
59            Settings::decode(data)
60        }
61        .map_err(|_| FfiError::ProtoDecode)?;
62
63        let calculator = Calculator::new(settings);
64        let max_calculator_size = get_calculator_size();
65        calculator
66            .encode(&mut unsafe { core::slice::from_raw_parts_mut(address, max_calculator_size) })
67            .map_err(|_| FfiError::ProtoEncode)?;
68
69        Ok(calculator)
70    }
71
72    #[unsafe(no_mangle)]
73    pub extern "C" fn initialize_calculator(settings_size: usize) -> usize {
74        let (mut result_buffer, mut current_result) = match get_result_protobuf() {
75            Ok(value) => value,
76            Err(_) => return 0,
77        };
78
79        match unsafe { initialize_calculator_inner(settings_size) } {
80            Ok(calculator) => {
81                current_result.result_value =
82                    Some(ResultValue::UintValue(calculator.encoded_len() as u32))
83            }
84            Err(error) => {
85                current_result.result_value = Some(ResultValue::Error(error.into()));
86            }
87        }
88        let _ = current_result.encode(&mut result_buffer);
89        current_result.encoded_len()
90    }
91
92    #[allow(invalid_null_arguments)]
93    unsafe fn calculate_inner(calculator_size: usize, value: f32) -> Result<f32, FfiError> {
94        let ptr = PTR_OFFSET as *const u8;
95
96        let current_calculator = unsafe {
97            let data = core::slice::from_raw_parts(ptr, calculator_size);
98            Calculator::decode(data)
99        }
100        .map_err(|_| FfiError::ProtoDecode)?;
101
102        Ok(current_calculator.calculate(value))
103    }
104
105    #[unsafe(no_mangle)]
106    pub fn calculate(value: f32, calculator_size: usize) -> usize {
107        let (mut result_buffer, mut current_result) = match get_result_protobuf() {
108            Ok(value) => value,
109            Err(value) => return value,
110        };
111        match unsafe { calculate_inner(calculator_size, value) } {
112            Ok(value) => current_result.result_value = Some(ResultValue::FloatValue(value)),
113            Err(error) => current_result.result_value = Some(ResultValue::Error(error.into())),
114        };
115
116        let _ = current_result.encode(&mut result_buffer);
117        current_result.encoded_len()
118    }
119}
120
121#[cfg(feature = "wasm-bindings")]
122pub use wasm::*;
123
124#[cfg(not(feature = "wasm-bindings"))]
125pub fn initialize_calculator(settings: Settings) -> Calculator {
126    Calculator::new(settings)
127}
128
129#[cfg(not(feature = "wasm-bindings"))]
130pub fn calculate(calculator: &Calculator, value: f32) -> f32 {
131    calculator.calculate(value)
132}