bmi_rs/
bmi.rs

1use crate::errors::{BmiIndexOutOfBounds, BmiNotImplementedError};
2use std::error::Error;
3
4pub const MAX_COMPONENT_NAME: u32 = 2048;
5pub const MAX_VAR_NAME: u32 = 2048;
6pub const MAX_UNITS_NAME: u32 = 2048;
7pub const MAX_TYPE_NAME: u32 = 2048;
8
9/// Bmi variable grid
10/// [element location](https://bmi.csdms.io/en/stable/bmi.var_funcs.html#get-var-location).
11#[derive(Debug, Clone, Copy)]
12pub enum Location {
13    Node,
14    Edge,
15    Face,
16}
17
18impl std::fmt::Display for Location {
19    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20        match self {
21            Location::Node => write!(f, "node"),
22            Location::Edge => write!(f, "edge"),
23            Location::Face => write!(f, "face"),
24        }
25    }
26}
27
28/// Bmi
29/// [grid type](https://bmi.csdms.io/en/stable/bmi.grid_funcs.html#get-grid-type).
30#[derive(Debug, Clone, Copy)]
31pub enum GridType {
32    Scalar,
33    Points,
34    Vector,
35    Unstructured,
36    StructuredQuadrilateral,
37    Rectilinear,
38    UniformRectilinear,
39}
40
41impl std::fmt::Display for GridType {
42    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43        match self {
44            GridType::Scalar => write!(f, "scalar"),
45            GridType::Points => write!(f, "points"),
46            GridType::Vector => write!(f, "vector"),
47            GridType::Unstructured => write!(f, "unstructured"),
48            GridType::StructuredQuadrilateral => write!(f, "structured_quadrilateral"),
49            GridType::Rectilinear => write!(f, "rectilinear"),
50            GridType::UniformRectilinear => write!(f, "uniform_rectilinear"),
51        }
52    }
53}
54
55// TODO: how to add isize and usize?
56/// Represents the numeric data type of an item in a [`Bmi`] variable's array.
57#[derive(Debug, Copy, Clone)]
58pub enum ValueType {
59    /// signed 16 bit int
60    I16,
61    /// unsigned 16 bit int
62    U16,
63    /// signed 32 bit int
64    I32,
65    /// unsigned 32 bit int
66    U32,
67    /// signed 64 bit int
68    I64,
69    /// unsigned 64 bit int
70    U64,
71    /// signed 32 bit float
72    F32,
73    /// signed 64 bit float
74    F64,
75}
76
77impl ValueType {
78    /// Return the size in bytes of the variant's analogous numeric type.
79    pub fn bytes(&self) -> usize {
80        match self {
81            ValueType::I16 | ValueType::U16 => 2,
82            ValueType::I32 | ValueType::U32 | ValueType::F32 => 4,
83            ValueType::I64 | ValueType::U64 | ValueType::F64 => 8,
84        }
85    }
86}
87
88// NOTE: consider a more generic container type than Vec<T>, maybe Box<[T]>?
89/// An owned `Vec` of a numeric type wrapped with type information.
90#[derive(Debug, Clone)]
91pub enum Values {
92    I16(Vec<i16>), // short
93    U16(Vec<u16>), // unsigned short
94    I32(Vec<i32>), // usually int
95    U32(Vec<u32>), // usually unsigned int
96    I64(Vec<i64>), // long or usually long long
97    U64(Vec<u64>), // unsigned long or usually unsigned long long
98    F32(Vec<f32>), // float
99    F64(Vec<f64>), // double
100}
101
102impl<'a> From<&'a Values> for RefValues<'a> {
103    fn from(value: &'a Values) -> Self {
104        match value {
105            Values::I16(items) => RefValues::I16(&items),
106            Values::U16(items) => RefValues::U16(&items),
107            Values::I32(items) => RefValues::I32(&items),
108            Values::U32(items) => RefValues::U32(&items),
109            Values::I64(items) => RefValues::I64(&items),
110            Values::U64(items) => RefValues::U64(&items),
111            Values::F32(items) => RefValues::F32(&items),
112            Values::F64(items) => RefValues::F64(&items),
113        }
114    }
115}
116
117macro_rules! impl_value_type {
118    ($t:ty; $($name:ident),*$(,)?) => {
119        impl $t {
120            pub fn value_type(&self) -> ValueType {
121                match self {
122                    $(Self::$name(_) => ValueType::$name,)*
123                }
124            }
125        }
126    };
127}
128
129macro_rules! impl_len {
130    ($t:ty; $($name:ident),*$(,)?) => {
131        impl $t {
132            pub fn len(&self) -> usize {
133                match self {
134                    $(Self::$name(v) => v.len(),)*
135                }
136            }
137        }
138    };
139}
140
141macro_rules! impl_from_vec_for_values {
142    ($($name:ident; $t:ty),*$(,)?) => {
143        $(
144        impl From<Vec<$t>> for Values {
145            fn from(v: Vec<$t>) -> Self {
146                Values::$name(v)
147            }
148        }
149    )*
150    };
151}
152
153impl_from_vec_for_values!(
154    I16;i16,
155    U16;u16,
156    I32;i32,
157    U32;u32,
158    I64;i64,
159    U64;u64,
160    F32;f32,
161    F64;f64,
162);
163impl_value_type!(Values; I16, U16, I32, U32, I64, U64, F32, F64,);
164impl_len!(Values; I16, U16, I32, U32, I64, U64, F32, F64,);
165
166// See: https://github.com/NOAA-OWP/ngen/blob/52f43540239e202328c7c9350149f9f5b8f1f409/include/realizations/catchment/Bmi_Module_Formulation.hpp#L779
167/// A ref to a slice of numerics wrapped with type information.
168#[derive(Debug)]
169pub enum RefValues<'a> {
170    I16(&'a [i16]), // short
171    U16(&'a [u16]), // unsigned short
172    I32(&'a [i32]), // usually int
173    U32(&'a [u32]), // usually unsigned int
174    I64(&'a [i64]), // long or usually long long
175    U64(&'a [u64]), // unsigned long or usually unsigned long long
176    F32(&'a [f32]), // float
177    F64(&'a [f64]), // double
178}
179
180macro_rules! impl_from_ref_t_for_ref_values {
181    ($container:ident; $($name:ident; $t:ty),*$(,)?) => {
182    $(
183        impl<'a> From<&'a $container<$t>> for RefValues<'a> {
184            fn from(v: &'a Vec<$t>) -> Self {
185                RefValues::$name(v)
186            }
187        }
188    )*
189    };
190    ($($name:ident; $t:ty),*$(,)?) => {
191    $(
192        impl<'a> From<&'a [$t]> for RefValues<'a> {
193            fn from(v: &'a [$t]) -> Self {
194                RefValues::$name(v)
195            }
196        }
197    )*
198    };
199}
200impl_from_ref_t_for_ref_values!(
201    Vec;
202    I16;i16,
203    U16;u16,
204    I32;i32,
205    U32;u32,
206    I64;i64,
207    U64;u64,
208    F32;f32,
209    F64;f64,
210);
211
212impl_from_ref_t_for_ref_values!(
213    I16;i16,
214    U16;u16,
215    I32;i32,
216    U32;u32,
217    I64;i64,
218    U64;u64,
219    F32;f32,
220    F64;f64,
221);
222
223impl_len!(RefValues<'_>; I16, U16, I32, U32, I64, U64, F32, F64,);
224impl_value_type!(RefValues<'_>; I16, U16, I32, U32, I64, U64, F32, F64,);
225
226pub type BmiResult<T> = Result<T, Box<dyn Error>>;
227
228macro_rules! values_at_indices {
229    ($t:ty, $inds:expr, $values:expr) => {{
230        let mut v = Vec::<$t>::with_capacity($inds.len());
231        for i in $inds {
232            if *i >= $values.len() as u32 {
233                return Err(Box::new(BmiIndexOutOfBounds));
234            }
235            v.push($values[*i as usize]);
236        }
237        Ok(Values::from(v))
238    }};
239}
240
241/// [CSDMS Basic Model Interface (BMI)](https://bmi.csdms.io/en/latest/index.html)
242/// _like_ trait.
243///
244/// Types that implement this trait can be exposed over the
245/// [bmi-c interface](https://github.com/csdms/bmi-c) via
246/// [`register_model`].
247pub trait Bmi {
248    /// [`Bmi`] implementations should perform the majority of tasks that are to take place before
249    /// entering the model’s time loop in this method.
250    /// Exceptions to this are [`Bmi`] implementations that expose model parameters settable for
251    /// configuration or calibration purposes.
252    ///
253    /// Code using [`Bmi`] implementations are expected to call the implementation's `initialize`
254    /// member before any other [`Bmi`] trait members.
255    ///
256    /// See
257    /// [csdms bmi `initialize`](https://bmi.csdms.io/en/stable/bmi.control_funcs.html#initialize)
258    /// docs for more info.
259    fn initialize(&mut self, config_file: &str) -> BmiResult<()>;
260
261    /// Advance the model by a single [`get_time_step`] sized time step.
262    ///
263    /// See
264    /// [csdms bmi `update`](https://bmi.csdms.io/en/stable/bmi.control_funcs.html#update)
265    /// docs for more info.
266    ///
267    /// [`get_time_step`]: #tymethod.get_time_step
268    fn update(&mut self) -> BmiResult<()>;
269
270    // TODO: consider using something like Chrono instead of f64
271    /// Advance the model to the time at `then`.
272    /// Once called, the value returned by the [`get_current_time`] function must return the
273    /// provided time to reflect that the model was updated to the requested time.
274    ///
275    /// See
276    /// [csdms bmi `update_until`](https://bmi.csdms.io/en/stable/bmi.control_funcs.html#update-until)
277    /// docs for more info.
278    ///
279    /// [`get_current_time`]: #tymethod.get_current_time
280    fn update_until(&mut self, then: f64) -> BmiResult<()>;
281
282    /// Perform any necessary tasks after exiting the model’s time loop.
283    /// Note, the implementing type is not consumed and therefore not dropped.
284    ///
285    /// Code using [`Bmi`] implementations are expected to call the implementation's [`finalize`]
286    /// member as the last _[`Bmi`]_ interaction with the implementing type.
287    ///
288    /// FFI methods that wrap [`finalize`] _should_ drop the implementing type.
289    ///
290    /// See
291    /// [csdms bmi `finalize`](https://bmi.csdms.io/en/stable/bmi.control_funcs.html#finalize)
292    /// docs for more info.
293    ///
294    /// [`finalize`]: #tymethod.finalize
295    fn finalize(&mut self) -> BmiResult<()>;
296
297    /* Exchange items */
298    /// Return the model's name.
299    ///
300    /// See
301    /// [csdms bmi `get_component_name`](https://bmi.csdms.io/en/stable/bmi.info_funcs.html#get-component-name)
302    /// docs for more info.
303    fn get_component_name(&self) -> &str;
304
305    /// Return the number of model _input variables_ settable via [`set_value`].
306    /// The count is given by the length of slice returned by [`get_input_var_names`].
307    ///
308    /// Note, [`Bmi`] implementations that expose model parameters settable strictly for
309    /// configuration or calibration purposes should not include these parameters in their
310    /// [`get_input_item_count`] count.
311    ///
312    /// See
313    /// [csdms bmi `get_input_item_count`](https://bmi.csdms.io/en/stable/bmi.info_funcs.html#get-input-item-count)
314    /// docs for more info.
315    ///
316    /// [`set_value`]: #tymethod.set_value
317    /// [`get_input_var_names`]: #tymethod.get_input_var_names
318    /// [`get_input_item_count`]: #tymethod.get_input_item_count
319    fn get_input_item_count(&self) -> u32 {
320        self.get_input_var_names().len() as u32
321    }
322
323    /// Return the number of _model output_ variables retrievable via [`get_value_ptr`].
324    /// The count is given by the length of slice returned by [`get_output_var_names`].
325    ///
326    /// See
327    /// [csdms bmi `get_output_item_count`](https://bmi.csdms.io/en/stable/bmi.info_funcs.html#get-output-item-count)
328    /// docs for more info.
329    ///
330    /// [`get_value_ptr`]: #tymethod.get_value_ptr
331    /// [`get_output_var_names`]: #tymethod.get_output_var_names
332    fn get_output_item_count(&self) -> u32 {
333        self.get_output_var_names().len() as u32
334    }
335
336    /// Return the implementing model's input variable names.
337    /// The length of the array is given by [`get_input_item_count`].
338    ///
339    /// Names are preferably in the form of
340    /// [CSDMS Standard Names](https://csdms.colorado.edu/wiki/CSDMS_Standard_Names).
341    ///
342    /// See
343    /// [csdms bmi `get_input_var_names`](https://bmi.csdms.io/en/stable/bmi.info_funcs.html#get-input-var-names)
344    /// docs for more info.
345    ///
346    /// [`get_input_item_count`]: #tymethod.get_input_item_count
347    fn get_input_var_names(&self) -> &[&str];
348
349    /// Return the implementing model's output variable names.
350    /// The length of the array is given by [`get_output_item_count`].
351    ///
352    /// See
353    /// [csdms bmi `get_output_var_names`](https://bmi.csdms.io/en/stable/bmi.info_funcs.html#get-output-var-names)
354    /// docs for more info.
355    ///
356    /// [`get_output_item_count`]: #tymethod.get_output_item_count
357    fn get_output_var_names(&self) -> &[&str];
358
359    /* Variable information */
360    /// Return the input or output variable's grid type.
361    ///
362    /// See
363    /// [csdms bmi `get_var_grid`](https://bmi.csdms.io/en/stable/bmi.var_funcs.html#get-var-grid)
364    /// docs for more info.
365    fn get_var_grid(&self, name: &str) -> BmiResult<i32>;
366
367    /// Return a variable's inner type.
368    ///
369    /// See
370    /// [csdms bmi `get_var_type`](https://bmi.csdms.io/en/stable/bmi.var_funcs.html#get-var-type)
371    /// docs for more info.
372    fn get_var_type(&self, name: &str) -> BmiResult<ValueType>;
373
374    /// Return a variable's units.
375    /// Units should be returned in lower case in
376    /// [UDUNIT2 format](https://docs.unidata.ucar.edu/udunits/current/#Database).
377    /// For example, `"meters"` / `"m"` or `"seconds"` / `"s"`.
378    ///
379    /// See
380    /// [csdms bmi `get_var_units`](https://bmi.csdms.io/en/stable/bmi.var_funcs.html#get-var-units)
381    /// docs for more info.
382    fn get_var_units(&self, name: &str) -> BmiResult<&str>;
383
384    /// Return the size, in bytes, of a single element of the variable.
385    /// For example, a variable stored as a `Vec<f64>` has an itemsize of 8.
386    ///
387    /// See
388    /// [csdms bmi `get_var_itemsize`](https://bmi.csdms.io/en/stable/bmi.var_funcs.html#get-var-itemsize)
389    /// docs for more info.
390    fn get_var_itemsize(&self, name: &str) -> BmiResult<u32> {
391        Ok(self.get_var_type(name)?.bytes() as u32)
392    }
393
394    /// Return the total number of bytes used to store a variable.
395    /// i.e., the number of items multiplied by the size of each item.
396    ///
397    /// See
398    /// [csdms bmi `get_var_nbytes`](https://bmi.csdms.io/en/stable/bmi.var_funcs.html#get-var-nbytes)
399    /// docs for more info.
400    fn get_var_nbytes(&self, name: &str) -> BmiResult<u32>;
401
402    /// Return a variable's grid element type.
403    ///
404    /// See
405    /// [csdms bmi `get_var_location`](https://bmi.csdms.io/en/stable/bmi.var_funcs.html#get-var-location)
406    /// docs for more info.
407    fn get_var_location(&self, name: &str) -> BmiResult<Location>;
408
409    /* Time information */
410    /// Return the model's current time.
411    ///
412    /// See
413    /// [csdms bmi `get_current_time`](https://bmi.csdms.io/en/stable/bmi.time_funcs.html#get-current-time)
414    /// docs for more info.
415    fn get_current_time(&self) -> f64;
416
417    /// Return the model's simulation start time.
418    /// Default: `0.0`.
419    ///
420    /// Note, the start time is typically `0.0`.
421    ///
422    /// See
423    /// [csdms bmi `get_start_time`](https://bmi.csdms.io/en/stable/bmi.time_funcs.html#get-start-time)
424    /// docs for more info.
425    fn get_start_time(&self) -> f64 {
426        0.
427    }
428
429    /// Return the model's simulation end time.
430    /// Default: [`f64::MAX`].
431    ///
432    /// Note, if an end time does not conceptually make sense, [`f64::MAX`] should be used.
433    ///
434    /// See
435    /// [csdms bmi `get_end_time`](https://bmi.csdms.io/en/stable/bmi.time_funcs.html#get-end-time)
436    /// docs for more info.
437    ///
438    /// [`f64::MAX`]: https://doc.rust-lang.org/std/primitive.f64.html#associatedconstant.MAX
439    fn get_end_time(&self) -> f64 {
440        f64::MAX
441    }
442
443    /// Return the model's time unit.
444    ///
445    /// Units in CF conventions are recommended.
446    ///
447    /// e.g. `s` | `sec` | `second`, `min` | `minute`, `h` | `hr` | `hour`, or `d` | `day`.
448    ///
449    /// See
450    /// [csdms bmi `get_time_units`](https://bmi.csdms.io/en/stable/bmi.time_funcs.html#get-time-units)
451    /// docs for more info.
452    fn get_time_units(&self) -> &str;
453
454    /// Return the model's time step size in [`get_time_units`] units.
455    ///
456    /// See
457    /// [csdms bmi `get_time_step`](https://bmi.csdms.io/en/stable/bmi.time_funcs.html#get-time-step)
458    /// docs for more info.
459    ///
460    /// [`get_time_units`]: #tymethod.get_time_units
461    fn get_time_step(&self) -> f64;
462
463    /* Getters */
464    /// Return a reference to a flattened slice of values for a given variable.
465    ///
466    /// Note, [`Bmi`] does not include the BMI `get_value` method in its method set.
467    /// This may change in the future.
468    /// Likewise, the return type of [`get_value_ptr`] may change in future versions.
469    /// See discussion in [#3](https://github.com/aaraney/bmi-rs/issues/3).
470    ///
471    /// See
472    /// [csdms bmi `get_value_ptr`](https://bmi.csdms.io/en/stable/bmi.getter_setter.html#get-value-ptr)
473    /// docs for more info.
474    ///
475    /// [`get_value_ptr`]: #tymethod.get_value_ptr
476    fn get_value_ptr(&self, name: &str) -> BmiResult<RefValues<'_>>;
477
478    /// Return an owned copy of a variable’s values at the `inds` specified.
479    ///
480    /// Note, the default implementation copies from values via [`get_value_ptr`].
481    ///
482    /// See
483    /// [csdms bmi `get_value_at_indices`](https://bmi.csdms.io/en/stable/bmi.getter_setter.html#get-value-at-indices)
484    /// docs for more info.
485    ///
486    /// [`get_value_ptr`]: #tymethod.get_value_ptr
487    fn get_value_at_indices(&self, name: &str, inds: &[u32]) -> BmiResult<Values> {
488        match self.get_value_ptr(name)? {
489            RefValues::I16(items) => values_at_indices!(i16, inds, items),
490            RefValues::U16(items) => values_at_indices!(u16, inds, items),
491            RefValues::I32(items) => values_at_indices!(i32, inds, items),
492            RefValues::U32(items) => values_at_indices!(u32, inds, items),
493            RefValues::I64(items) => values_at_indices!(i64, inds, items),
494            RefValues::U64(items) => values_at_indices!(u64, inds, items),
495            RefValues::F32(items) => values_at_indices!(f32, inds, items),
496            RefValues::F64(items) => values_at_indices!(f64, inds, items),
497        }
498    }
499
500    /* Setters */
501    /// Copy values from `src` into the model's `name` variable.
502    /// `src`'s [`RefValues`] variant and slice length _must_ match the analogous type _and_ length of
503    /// the model's internal `name` variable.
504    /// For example, if `src` is a [`RefValues::F64`] an _item_ in model's `name` variable array
505    /// must be an `f64`.
506    ///
507    /// The type and length of a model's variable can be determined through calls to
508    /// [`get_var_type`] and [`get_var_nbytes`].
509    ///
510    /// See
511    /// [csdms bmi `set_value`](https://bmi.csdms.io/en/stable/bmi.getter_setter.html#set-value)
512    /// docs for more info.
513    ///
514    /// [`get_var_type`]: #tymethod.get_var_type
515    /// [`get_var_nbytes`]: #tymethod.get_var_nbytes
516    fn set_value(&mut self, name: &str, src: RefValues) -> BmiResult<()>;
517
518    /// Copy values from `src` into the model's `name` variable at the provided `inds` indices.
519    ///
520    /// See
521    /// [csdms bmi `set_value_at_indices`](https://bmi.csdms.io/en/stable/bmi.getter_setter.html#set-value-at-indices)
522    /// docs for more info.
523    fn set_value_at_indices(&mut self, name: &str, inds: &[u32], src: RefValues) -> BmiResult<()>;
524
525    // NOTE: can we implement a default here?
526    /// Return the [`GridType`] for a given grid identifier.
527    ///
528    /// Default implementation returns Err([`BmiNotImplementedError`]).
529    ///
530    /// See
531    /// [csdms bmi `get_grid_type`](https://bmi.csdms.io/en/stable/bmi.grid_funcs.html#get-grid-type)
532    /// docs for more info.
533    #[allow(unused_variables)]
534    fn get_grid_type(&self, grid: i32) -> BmiResult<GridType> {
535        BmiNotImplementedError.into()
536    }
537
538    /* Grid information */
539    /// Return the grid
540    /// [rank](https://bmi.csdms.io/en/stable/glossary.html#term-rank)
541    /// for a given grid identifier.
542    ///
543    /// This function is needed for every
544    /// [grid type](https://bmi.csdms.io/en/stable/model_grids.html#model-grids).
545    /// Default implementation returns Err([`BmiNotImplementedError`]).
546    ///
547    /// See
548    /// [csdms bmi `get_grid_rank`](https://bmi.csdms.io/en/stable/bmi.grid_funcs.html#get-grid-rank)
549    /// docs for more info.
550    #[allow(unused_variables)]
551    fn get_grid_rank(&self, grid: i32) -> BmiResult<u32> {
552        BmiNotImplementedError.into()
553    }
554
555    /// Return the total number of elements (or
556    /// [nodes](https://bmi.csdms.io/en/stable/glossary.html#term-node)
557    /// ) for a given grid identifier.
558    ///
559    /// This function is needed for every
560    /// [grid type](https://bmi.csdms.io/en/stable/model_grids.html#model-grids).
561    ///
562    /// Default implementation returns Err([`BmiNotImplementedError`]).
563    ///
564    /// See
565    /// [csdms bmi `get_grid_size`](https://bmi.csdms.io/en/stable/bmi.grid_funcs.html#get-grid-size)
566    /// docs for more info.
567    #[allow(unused_variables)]
568    fn get_grid_size(&self, grid: i32) -> BmiResult<u32> {
569        BmiNotImplementedError.into()
570    }
571
572    /* Uniform rectilinear */
573    /// Return the dimensions of the model grid for a given a grid identifier.
574    /// The length of the returned slice is [`get_grid_rank`] long.
575    ///
576    /// This function is used for describing all
577    /// [structured grids](https://bmi.csdms.io/en/stable/model_grids.html#structured-grids).
578    ///
579    /// Default implementation returns Err([`BmiNotImplementedError`]).
580    ///
581    /// See
582    /// [csdms bmi `get_grid_shape`](https://bmi.csdms.io/en/stable/bmi.grid_funcs.html#get-grid-shape)
583    /// docs for more info.
584    ///
585    /// [`get_grid_rank`]: #tymethod.get_grid_rank
586    #[allow(unused_variables)]
587    fn get_grid_shape(&self, grid: i32) -> BmiResult<&[u32]> {
588        BmiNotImplementedError.into()
589    }
590
591    /// Return the distance between the
592    /// [nodes](https://bmi.csdms.io/en/stable/glossary.html#term-node)
593    /// of the model grid.
594    ///
595    /// This function is used for describing
596    /// [uniform rectilinear](https://bmi.csdms.io/en/stable/model_grids.html#uniform-rectilinear)
597    /// grids.
598    ///
599    /// Default implementation returns Err([`BmiNotImplementedError`]).
600    ///
601    /// See
602    /// [csdms bmi `get_grid_spacing`](https://bmi.csdms.io/en/stable/bmi.grid_funcs.html#get-grid-spacing)
603    /// docs for more info.
604    #[allow(unused_variables)]
605    fn get_grid_spacing(&self, grid: i32) -> BmiResult<&[f64]> {
606        BmiNotImplementedError.into()
607    }
608
609    /// Return the coordinates of the lower-left corner of the model grid.
610    ///
611    /// This function is used for describing
612    /// [uniform rectilinear](https://bmi.csdms.io/en/stable/model_grids.html#uniform-rectilinear)
613    /// grids.
614    ///
615    /// Default implementation returns Err([`BmiNotImplementedError`]).
616    ///
617    /// See
618    /// [csdms bmi `get_grid_origin`](https://bmi.csdms.io/en/stable/bmi.grid_funcs.html#get-grid-origin)
619    /// docs for more info.
620    #[allow(unused_variables)]
621    fn get_grid_origin(&self, grid: i32) -> BmiResult<&[f64]> {
622        BmiNotImplementedError.into()
623    }
624
625    /* Non-uniform rectilinear, curvilinear */
626    /// Return locations of the grid
627    /// [nodes](https://bmi.csdms.io/en/stable/glossary.html#term-node)
628    /// in the first coordinate direction.
629    ///
630    /// The length of the resulting one-dimensional array depends on the grid type.
631    ///
632    /// This function is used for describing
633    /// [rectilinear](https://bmi.csdms.io/en/stable/model_grids.html#rectilinear),
634    /// [structured quadrilateral](https://bmi.csdms.io/en/stable/model_grids.html#structured-quad),
635    /// and all
636    /// [unstructured](https://bmi.csdms.io/en/stable/model_grids.html#unstructured-grids)
637    /// grids.
638    ///
639    /// Default implementation returns Err([`BmiNotImplementedError`]).
640    ///
641    /// See
642    /// [csdms bmi `get_grid_rank`](https://bmi.csdms.io/en/stable/bmi.grid_funcs.html#get-grid-x)
643    /// docs for more info.
644    #[allow(unused_variables)]
645    fn get_grid_x(&self, grid: i32) -> BmiResult<&[f64]> {
646        BmiNotImplementedError.into()
647    }
648
649    /// Return locations of the grid
650    /// [nodes](https://bmi.csdms.io/en/stable/glossary.html#term-node)
651    /// in the second coordinate direction.
652    ///
653    /// The length of the resulting one-dimensional array depends on the grid type.
654    ///
655    /// This function is used for describing
656    /// [rectilinear](https://bmi.csdms.io/en/stable/model_grids.html#rectilinear),
657    /// [structured quadrilateral](https://bmi.csdms.io/en/stable/model_grids.html#structured-quad),
658    /// and all
659    /// [unstructured](https://bmi.csdms.io/en/stable/model_grids.html#unstructured-grids)
660    /// grids.
661    ///
662    /// Default implementation returns Err([`BmiNotImplementedError`]).
663    ///
664    /// See
665    /// [csdms bmi `get_grid_rank`](https://bmi.csdms.io/en/stable/bmi.grid_funcs.html#get-grid-y)
666    /// docs for more info.
667    #[allow(unused_variables)]
668    fn get_grid_y(&self, grid: i32) -> BmiResult<&[f64]> {
669        BmiNotImplementedError.into()
670    }
671
672    /// Return locations of the grid
673    /// [nodes](https://bmi.csdms.io/en/stable/glossary.html#term-node)
674    /// in the third coordinate direction.
675    ///
676    /// The length of the resulting one-dimensional array depends on the grid type.
677    ///
678    /// This function is used for describing
679    /// [rectilinear](https://bmi.csdms.io/en/stable/model_grids.html#rectilinear),
680    /// [structured quadrilateral](https://bmi.csdms.io/en/stable/model_grids.html#structured-quad),
681    /// and all
682    /// [unstructured](https://bmi.csdms.io/en/stable/model_grids.html#unstructured-grids)
683    /// grids.
684    ///
685    /// Default implementation returns Err([`BmiNotImplementedError`]).
686    ///
687    /// See
688    /// [csdms bmi `get_grid_rank`](https://bmi.csdms.io/en/stable/bmi.grid_funcs.html#get-grid-z)
689    /// docs for more info.
690    #[allow(unused_variables)]
691    fn get_grid_z(&self, grid: i32) -> BmiResult<&[f64]> {
692        BmiNotImplementedError.into()
693    }
694
695    /* Unstructured */
696    /// Get the number of
697    /// [nodes](https://bmi.csdms.io/en/stable/glossary.html#term-node)
698    /// in the grid.
699    ///
700    /// This function is used for describing
701    /// [unstructured](https://bmi.csdms.io/en/stable/model_grids.html#unstructured-grids)
702    /// grids.
703    ///
704    /// Default implementation returns Err([`BmiNotImplementedError`]).
705    ///
706    /// See
707    /// [csdms bmi `get_grid_node_count`](https://bmi.csdms.io/en/stable/bmi.grid_funcs.html#get-grid-node-count)
708    /// docs for more info.
709    #[allow(unused_variables)]
710    fn get_grid_node_count(&self, grid: i32) -> BmiResult<u32> {
711        BmiNotImplementedError.into()
712    }
713
714    /// Get the number of
715    /// [edges](https://bmi.csdms.io/en/stable/glossary.html#term-edge)
716    /// in the grid.
717    ///
718    /// This function is used for describing
719    /// [unstructured](https://bmi.csdms.io/en/stable/model_grids.html#unstructured-grids)
720    /// grids.
721    ///
722    /// Default implementation returns Err([`BmiNotImplementedError`]).
723    ///
724    /// See
725    /// [csdms bmi `get_grid_edge_count`](https://bmi.csdms.io/en/stable/bmi.grid_funcs.html#get-grid-edge-count)
726    /// docs for more info.
727    #[allow(unused_variables)]
728    fn get_grid_edge_count(&self, grid: i32) -> BmiResult<u32> {
729        BmiNotImplementedError.into()
730    }
731
732    /// Get the number of
733    /// [faces](https://bmi.csdms.io/en/stable/glossary.html#term-face)
734    /// in the grid.
735    ///
736    /// This function is used for describing
737    /// [unstructured](https://bmi.csdms.io/en/stable/model_grids.html#unstructured-grids)
738    /// grids.
739    ///
740    /// Default implementation returns Err([`BmiNotImplementedError`]).
741    ///
742    /// See
743    /// [csdms bmi `get_grid_face_count`](https://bmi.csdms.io/en/stable/bmi.grid_funcs.html#get-grid-face-count)
744    /// docs for more info.
745    #[allow(unused_variables)]
746    fn get_grid_face_count(&self, grid: i32) -> BmiResult<u32> {
747        BmiNotImplementedError.into()
748    }
749
750    /// Return the edge-node connectivity.
751    /// The total length of the slice is 2 * [`get_grid_edge_count`].
752    ///
753    /// This function is used for describing
754    /// [unstructured](https://bmi.csdms.io/en/stable/model_grids.html#unstructured-grids)
755    /// grids.
756    ///
757    /// Default implementation returns Err([`BmiNotImplementedError`]).
758    ///
759    /// See
760    /// [csdms bmi `get_grid_edge_nodes`](https://bmi.csdms.io/en/stable/bmi.grid_funcs.html#get-grid-edge-nodes)
761    /// docs for more info.
762    ///
763    /// [`get_grid_edge_count`]: #tymethod.get_grid_edge_count
764    #[allow(unused_variables)]
765    fn get_grid_edge_nodes(&self, grid: i32) -> BmiResult<&[u32]> {
766        BmiNotImplementedError.into()
767    }
768
769    /// Return the face-edge connectivity.
770    /// The length of the returned slice is the sum of the values of [`get_grid_nodes_per_face`].
771    ///
772    /// This function is used for describing
773    /// [unstructured](https://bmi.csdms.io/en/stable/model_grids.html#unstructured-grids)
774    /// grids.
775    ///
776    /// Default implementation returns Err([`BmiNotImplementedError`]).
777    ///
778    /// See
779    /// [csdms bmi `get_grid_face_edges`](https://bmi.csdms.io/en/stable/bmi.grid_funcs.html#get-grid-face-edges)
780    /// docs for more info.
781    ///
782    /// [`get_grid_nodes_per_face`]: #tymethod.get_grid_nodes_per_face
783    #[allow(unused_variables)]
784    fn get_grid_face_edges(&self, grid: i32) -> BmiResult<&[u32]> {
785        BmiNotImplementedError.into()
786    }
787
788    /// Return the face-node connectivity.
789    ///
790    /// This function is used for describing
791    /// [unstructured](https://bmi.csdms.io/en/stable/model_grids.html#unstructured-grids)
792    /// grids.
793    ///
794    /// Default implementation returns Err([`BmiNotImplementedError`]).
795    ///
796    /// See
797    /// [csdms bmi `get_grid_face_nodes`](https://bmi.csdms.io/en/stable/bmi.grid_funcs.html#get-grid-face-nodes)
798    /// docs for more info.
799    #[allow(unused_variables)]
800    fn get_grid_face_nodes(&self, grid: i32) -> BmiResult<&[u32]> {
801        BmiNotImplementedError.into()
802    }
803
804    /// Return the number of nodes for each face.
805    /// The returned array has a length of [`get_grid_face_count`].
806    ///
807    /// This function is used for describing
808    /// [unstructured](https://bmi.csdms.io/en/stable/model_grids.html#unstructured-grids)
809    /// grids.
810    ///
811    /// Default implementation returns Err([`BmiNotImplementedError`]).
812    ///
813    /// See
814    /// [csdms bmi `get_grid_nodes_per_face`](https://bmi.csdms.io/en/stable/bmi.grid_funcs.html#get-grid-nodes-per-face)
815    /// docs for more info.
816    ///
817    /// [`get_grid_face_count`]: #tymethod.get_grid_face_count
818    #[allow(unused_variables)]
819    fn get_grid_nodes_per_face(&self, grid: i32) -> BmiResult<&[u32]> {
820        BmiNotImplementedError.into()
821    }
822}
823
824/// Bootstraps the `model` so it can be called through the
825/// [bmi-c](https://github.com/csdms/bmi-c/blob/031c5abf0ff0e75bec7aea48a064611138a0de64/bmi.h)
826/// interface.
827///
828/// Example:
829/// ```compile_fail
830/// #[unsafe(no_mangle)]
831///  pub extern "C" fn register_bmi_simple(handle: *mut ffi::Bmi) -> *mut ffi::Bmi {
832///      let model = Model::new();
833///      bmi_rs::register_model(handle, model);
834///      return handle;
835///  }
836///  ```
837pub fn register_model<T: Bmi>(handle: *mut ffi::Bmi, model: T) {
838    assert!(!handle.is_null(), "pointer is null");
839    let handle: &mut ffi::Bmi = unsafe { handle.as_mut() }.unwrap();
840    setup_fn_ptrs::<T>(handle);
841
842    let data: Box<T> = Box::new(model);
843    let data = Box::into_raw(data);
844    handle.data = data as *mut std::ffi::c_void;
845}
846
847fn setup_fn_ptrs<T: Bmi>(handle: &mut ffi::Bmi) {
848    handle.initialize = Some(crate::wrapper::initialize::<T>);
849    handle.update = Some(crate::wrapper::update::<T>);
850    handle.update_until = Some(crate::wrapper::update_until::<T>);
851    handle.finalize = Some(crate::wrapper::finalize::<T>);
852    handle.get_component_name = Some(crate::wrapper::get_component_name::<T>);
853    handle.get_input_item_count = Some(crate::wrapper::get_input_item_count::<T>);
854    handle.get_output_item_count = Some(crate::wrapper::get_output_item_count::<T>);
855    handle.get_input_var_names = Some(crate::wrapper::get_input_var_names::<T>);
856    handle.get_output_var_names = Some(crate::wrapper::get_output_var_names::<T>);
857    handle.get_var_grid = Some(crate::wrapper::get_var_grid::<T>);
858    handle.get_var_type = Some(crate::wrapper::get_var_type::<T>);
859    handle.get_var_units = Some(crate::wrapper::get_var_units::<T>);
860    handle.get_var_itemsize = Some(crate::wrapper::get_var_itemsize::<T>);
861    handle.get_var_nbytes = Some(crate::wrapper::get_var_nbytes::<T>);
862    handle.get_var_location = Some(crate::wrapper::get_var_location::<T>);
863    handle.get_current_time = Some(crate::wrapper::get_current_time::<T>);
864    handle.get_start_time = Some(crate::wrapper::get_start_time::<T>);
865    handle.get_end_time = Some(crate::wrapper::get_end_time::<T>);
866    handle.get_time_units = Some(crate::wrapper::get_time_units::<T>);
867    handle.get_time_step = Some(crate::wrapper::get_time_step::<T>);
868    handle.get_value = Some(crate::wrapper::get_value::<T>);
869    handle.get_value_ptr = Some(crate::wrapper::get_value_ptr::<T>);
870    handle.get_value_at_indices = Some(crate::wrapper::get_value_at_indices::<T>);
871    handle.set_value = Some(crate::wrapper::set_value::<T>);
872    handle.set_value_at_indices = Some(crate::wrapper::set_value_at_indices::<T>);
873    handle.get_grid_rank = Some(crate::wrapper::get_grid_rank::<T>);
874    handle.get_grid_size = Some(crate::wrapper::get_grid_size::<T>);
875    handle.get_grid_type = Some(crate::wrapper::get_grid_type::<T>);
876    handle.get_grid_shape = Some(crate::wrapper::get_grid_shape::<T>);
877    handle.get_grid_spacing = Some(crate::wrapper::get_grid_spacing::<T>);
878    handle.get_grid_origin = Some(crate::wrapper::get_grid_origin::<T>);
879    handle.get_grid_x = Some(crate::wrapper::get_grid_x::<T>);
880    handle.get_grid_y = Some(crate::wrapper::get_grid_y::<T>);
881    handle.get_grid_z = Some(crate::wrapper::get_grid_z::<T>);
882    handle.get_grid_node_count = Some(crate::wrapper::get_grid_node_count::<T>);
883    handle.get_grid_edge_count = Some(crate::wrapper::get_grid_edge_count::<T>);
884    handle.get_grid_face_count = Some(crate::wrapper::get_grid_face_count::<T>);
885    handle.get_grid_edge_nodes = Some(crate::wrapper::get_grid_edge_nodes::<T>);
886    handle.get_grid_face_edges = Some(crate::wrapper::get_grid_face_edges::<T>);
887    handle.get_grid_face_nodes = Some(crate::wrapper::get_grid_face_nodes::<T>);
888    handle.get_grid_nodes_per_face = Some(crate::wrapper::get_grid_nodes_per_face::<T>);
889}
890
891#[cfg(test)]
892mod tests {
893    use super::*;
894    fn case(vs: &[u16], idx: &[u32]) -> Result<Values, Box<dyn Error>> {
895        values_at_indices!(u16, idx, vs)
896    }
897    #[test]
898    fn test_empty() {
899        let vs: [u16; 0] = [];
900        let inds: [u32; 0] = [];
901        assert!(case(&vs, &inds).is_ok());
902
903        let vs: [u16; 1] = [42];
904        let inds: [u32; 0] = [];
905        assert!(case(&vs, &inds).is_ok());
906    }
907
908    #[test]
909    fn test_one() {
910        let vs: [u16; 1] = [42];
911        let inds: [u32; 1] = [0];
912        match case(&vs, &inds) {
913            Ok(values) => match values {
914                Values::U16(values) => {
915                    let i = inds[0] as usize;
916                    assert_eq!(values[i], vs[i]);
917                }
918                _ => assert!(false),
919            },
920            _ => assert!(false),
921        }
922    }
923
924    #[test]
925    fn test_many() {
926        let vs: [u16; 2] = [0, 1];
927        let inds: [u32; 2] = [0, 1];
928        match case(&vs, &inds) {
929            Ok(values) => match values {
930                Values::U16(values) => {
931                    for i in &inds {
932                        let i = *i as usize;
933                        assert_eq!(values[i], vs[i]);
934                    }
935                }
936                _ => assert!(false),
937            },
938            _ => assert!(false),
939        }
940    }
941
942    #[test]
943    fn test_out_of_bounds() {
944        let vs: [u16; 0] = [];
945        let inds: [u32; 1] = [1];
946        match case(&vs, &inds) {
947            Err(err) => {
948                assert!(err.is::<crate::errors::BmiIndexOutOfBounds>());
949            }
950            _ => assert!(false),
951        }
952    }
953}