diff --git a/CHANGELOG.md b/CHANGELOG.md index 7da3a79..fb7eccf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,8 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Unsafe `get_value_mut_ptr` method to `bmi_rs::Bmi` trait; analog of bmi-c's `get_value_ptr`. + Default returns `Err(BmiNotImplementedError)`. [#14](https://github.com/aaraney/bmi-rs/pull/14) + ### Changed +- bmi-c ffi `get_value_ptr` wrapper calls `bmi_rs::Bmi::get_value_mut_ptr` instead of always returning `BMI_FAILURE`. [#14](https://github.com/aaraney/bmi-rs/pull/14) + ### Deprecated ### Removed diff --git a/bmi-rs/src/bmi.rs b/bmi-rs/src/bmi.rs index 8b23db8..8521398 100644 --- a/bmi-rs/src/bmi.rs +++ b/bmi-rs/src/bmi.rs @@ -223,6 +223,41 @@ impl_from_ref_t_for_ref_values!( impl_len!(RefValues<'_>; I16, U16, I32, U32, I64, U64, F32, F64,); impl_value_type!(RefValues<'_>; I16, U16, I32, U32, I64, U64, F32, F64,); +#[derive(Debug)] +pub enum MutPtrValues { + I16(*mut i16), // short + U16(*mut u16), // unsigned short + I32(*mut i32), // usually int + U32(*mut u32), // usually unsigned int + I64(*mut i64), // long or usually long long + U64(*mut u64), // unsigned long or usually unsigned long long + F32(*mut f32), // float + F64(*mut f64), // double +} + +macro_rules! impl_from_ref_mut_slice_for_mut_ptr_values { + ($($name:ident; $t:ty),*$(,)?) => { + $( + impl From<&mut [$t]> for MutPtrValues{ + fn from(v: &mut [$t]) -> Self { + Self::$name(v.as_mut_ptr()) + } + } + )* + }; +} + +impl_from_ref_mut_slice_for_mut_ptr_values!( + I16;i16, + U16;u16, + I32;i32, + U32;u32, + I64;i64, + U64;u64, + F32;f32, + F64;f64, +); + pub type BmiResult = Result>; macro_rules! values_at_indices { @@ -463,18 +498,55 @@ pub trait Bmi { /* Getters */ /// Return a reference to a flattened slice of values for a given variable. /// - /// Note, [`Bmi`] does not include the BMI `get_value` method in its method set. - /// This may change in the future. - /// Likewise, the return type of [`get_value_ptr`] may change in future versions. - /// See discussion in [#3](https://github.com/aaraney/bmi-rs/issues/3). + /// This crate's bmi-c ffi bindings call a [`Bmi`]'s [`get_value_ptr`] method when + /// the bmi-c + /// [`get_value`](https://bmi.csdms.io/en/stable/bmi.getter_setter.html#get-value) + /// function pointer is called. + /// + /// Note, [`Bmi`] does not include the + /// [BMI `get_value`](https://bmi.csdms.io/en/stable/bmi.getter_setter.html#get-value) + /// method in its method set. + /// [`get_value_ptr`] should be used where `get_value` would typically be used, or where read-only + /// access to a variable is sufficient. + /// + /// Note, some bmi-c drivers + /// (e.g. [`ngen`](https://github.com/noaa-owp/ngen)) + /// require variables be available by raw pointer for efficiency reasons. + /// [`Bmi`] implementations should take this into consideration when deciding what variables + /// are exposed over [`get_value_ptr`] and [`get_value_mut_ptr`]. /// /// See /// [csdms bmi `get_value_ptr`](https://bmi.csdms.io/en/stable/bmi.getter_setter.html#get-value-ptr) /// docs for more info. /// /// [`get_value_ptr`]: #tymethod.get_value_ptr + /// [`get_value_mut_ptr`]: #tymethod.get_value_mut_ptr fn get_value_ptr(&self, name: &str) -> BmiResult>; + /// Return a [`MutPtrValues`] to a flattened slice of values for a given variable. + /// + /// Default implementation returns Err([`BmiNotImplementedError`]). + /// + /// This crate's bmi-c ffi bindings call a [`Bmi`]'s [`get_value_mut_ptr`] method when + /// the bmi-c + /// [`get_value_ptr`](https://bmi.csdms.io/en/stable/bmi.getter_setter.html#get-value-ptr) + /// function pointer is called. Code calling the [`Bmi`] instance + /// should use this method to read or write data to a variable the _model chooses to expose by + /// pointer_. The code calling the [`Bmi`] instance must be aware of the lifetime guarantees of + /// the returned pointer. It's recommended that [`Bmi`] instances that implement this method + /// provide a SAFETY comment documenting the lifetime guarantees of variables exposed by their + /// implementation. + /// + /// See + /// [csdms bmi `get_value_ptr`](https://bmi.csdms.io/en/stable/bmi.getter_setter.html#get-value-ptr) + /// docs for more info. + /// + /// [`get_value_mut_ptr`]: #tymethod.get_value_mut_ptr + #[allow(unused_variables)] + unsafe fn get_value_mut_ptr(&self, name: &str) -> BmiResult { + BmiNotImplementedError.into() + } + /// Return an owned copy of a variable’s values at the `inds` specified. /// /// Note, the default implementation copies from values via [`get_value_ptr`]. diff --git a/bmi-rs/src/lib.rs b/bmi-rs/src/lib.rs index 1b78e2a..44d2074 100644 --- a/bmi-rs/src/lib.rs +++ b/bmi-rs/src/lib.rs @@ -8,5 +8,5 @@ pub mod errors; mod wrapper; pub use crate::bmi::{ - Bmi, BmiResult, GridType, Location, RefValues, ValueType, Values, register_model, + Bmi, BmiResult, GridType, Location, MutPtrValues, RefValues, ValueType, Values, register_model, }; diff --git a/bmi-rs/src/wrapper.rs b/bmi-rs/src/wrapper.rs index c04e839..1df802a 100644 --- a/bmi-rs/src/wrapper.rs +++ b/bmi-rs/src/wrapper.rs @@ -1,4 +1,4 @@ -use crate::bmi::{Bmi, RefValues, ValueType, Values}; +use crate::bmi::{Bmi, MutPtrValues, RefValues, ValueType, Values}; use ffi::{BMI_FAILURE, BMI_SUCCESS}; use std::ffi::{ CStr, CString, c_char, c_double, c_float, c_int, c_long, c_short, c_uint, c_ulong, c_ushort, @@ -356,35 +356,29 @@ pub extern "C" fn get_value( BMI_SUCCESS } -/// See -/// (#3)[https://github.com/aaraney/bmi-rs/issues/3] -/// for why this returns `BMI_FAILURE`. -#[allow(unused_variables)] pub extern "C" fn get_value_ptr( self_: *mut ffi::Bmi, name: *const c_char, dest: *mut *mut c_void, ) -> c_int { - BMI_FAILURE - /* let var_name = as_str_ref_or_fail!(name); let data: &mut T = data_field!(&self_); - let value_ptr = ok_or_fail!(data.get_value_ptr(var_name)); + let value_ptr = unsafe { data.get_value_mut_ptr(var_name) }; + let value_ptr = ok_or_fail!(value_ptr); let src = match value_ptr { - RefValues::I16(v) => v.as_ptr() as *mut c_void, - RefValues::U16(v) => v.as_ptr() as *mut c_void, - RefValues::I32(v) => v.as_ptr() as *mut c_void, - RefValues::U32(v) => v.as_ptr() as *mut c_void, - RefValues::I64(v) => v.as_ptr() as *mut c_void, - RefValues::U64(v) => v.as_ptr() as *mut c_void, - RefValues::F32(v) => v.as_ptr() as *mut c_void, - RefValues::F64(v) => v.as_ptr() as *mut c_void, + MutPtrValues::I16(v) => v as *mut c_void, + MutPtrValues::U16(v) => v as *mut c_void, + MutPtrValues::I32(v) => v as *mut c_void, + MutPtrValues::U32(v) => v as *mut c_void, + MutPtrValues::I64(v) => v as *mut c_void, + MutPtrValues::U64(v) => v as *mut c_void, + MutPtrValues::F32(v) => v as *mut c_void, + MutPtrValues::F64(v) => v as *mut c_void, }; unsafe { *dest = src }; BMI_SUCCESS - */ } pub extern "C" fn get_value_at_indices(