Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
80 changes: 76 additions & 4 deletions bmi-rs/src/bmi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T> = Result<T, Box<dyn Error>>;

macro_rules! values_at_indices {
Expand Down Expand Up @@ -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<RefValues<'_>>;

/// 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<MutPtrValues> {
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`].
Expand Down
2 changes: 1 addition & 1 deletion bmi-rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
28 changes: 11 additions & 17 deletions bmi-rs/src/wrapper.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -356,35 +356,29 @@ pub extern "C" fn get_value<T: Bmi>(
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<T: Bmi>(
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<T: Bmi>(
Expand Down