mod clone;
#[cfg(feature = "ndarray")]
#[cfg_attr(docsrs, doc(cfg(feature = "ndarray")))]
mod ndarray;
mod read;
mod write;
#[cfg(feature = "ndarray")]
#[cfg_attr(docsrs, doc(cfg(feature = "ndarray")))]
pub use ndarray::RustyCodesMessage;
pub use read::{DynamicKeyType, KeyPropertiesRead, KeyRead};
pub use write::KeyWrite;
use eccodes_sys::codes_handle;
use std::{
fmt::Debug,
hash::Hash,
marker::PhantomData,
ptr::null_mut,
sync::{Arc, Mutex},
};
use tracing::{Level, event, instrument};
use crate::{CodesFile, intermediate_bindings::codes_handle_delete};
#[derive(Debug)]
pub struct CodesMessage<P: Debug> {
pub(crate) _parent: P,
pub(crate) message_handle: *mut codes_handle,
}
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd)]
#[doc(hidden)]
pub struct RefParent<'ch>(PhantomData<&'ch ()>);
#[derive(Debug, Hash, PartialEq, Eq, PartialOrd)]
#[doc(hidden)]
pub struct BufParent();
#[derive(Debug)]
#[doc(hidden)]
pub struct ArcParent<D: Debug> {
_arc_handle: Arc<Mutex<CodesFile<D>>>,
}
pub type RefMessage<'ch> = CodesMessage<RefParent<'ch>>;
pub type ArcMessage<D> = CodesMessage<ArcParent<D>>;
unsafe impl<D: Debug> Send for ArcMessage<D> {}
unsafe impl<D: Debug> Sync for ArcMessage<D> {}
pub type BufMessage = CodesMessage<BufParent>;
unsafe impl Send for BufMessage {}
unsafe impl Sync for BufMessage {}
impl RefMessage<'_> {
pub(crate) const fn new(handle: *mut codes_handle) -> Self {
RefMessage {
_parent: RefParent(PhantomData),
message_handle: handle,
}
}
}
impl<D: Debug> ArcMessage<D> {
pub(crate) fn new(handle: *mut codes_handle, parent: &Arc<Mutex<CodesFile<D>>>) -> Self {
ArcMessage {
_parent: ArcParent {
_arc_handle: parent.clone(),
},
message_handle: handle,
}
}
}
impl BufMessage {
pub(crate) const fn new(handle: *mut codes_handle) -> Self {
BufMessage {
_parent: BufParent(),
message_handle: handle,
}
}
}
impl<P: Debug> Drop for CodesMessage<P> {
#[instrument(level = "trace")]
fn drop(&mut self) {
unsafe {
codes_handle_delete(self.message_handle).unwrap_or_else(|error| {
event!(
Level::ERROR,
"codes_handle_delete() returned an error: {:?}",
&error
);
debug_assert!(false, "Error in CodesMessage::drop");
});
}
self.message_handle = null_mut();
}
}
#[cfg(test)]
mod tests {
use crate::codes_file::{CodesFile, ProductKind};
use anyhow::{Context, Result};
use fallible_iterator::FallibleIterator;
use std::path::Path;
#[test]
fn check_docs_keys() -> Result<()> {
let file_path = Path::new("./data/iceland.grib");
let product_kind = ProductKind::GRIB;
let mut handle = CodesFile::new_from_file(file_path, product_kind)?;
let current_message = handle
.ref_message_iter()
.next()?
.context("Message not some")?;
let _ = current_message.read_key_dynamic("validityDate")?;
let _ = current_message.read_key_dynamic("validityTime")?;
let _ = current_message.read_key_dynamic("level")?;
let _ = current_message.read_key_dynamic("shortName")?;
let _ = current_message.read_key_dynamic("units")?;
let _ = current_message.read_key_dynamic("values")?;
let _ = current_message.read_key_dynamic("typeOfLevel")?;
Ok(())
}
#[test]
fn message_clone_1() -> Result<()> {
let file_path = Path::new("./data/iceland.grib");
let product_kind = ProductKind::GRIB;
let mut handle = CodesFile::new_from_file(file_path, product_kind)?;
let current_message = handle
.ref_message_iter()
.next()?
.context("Message not some")?;
let cloned_message = current_message.try_clone()?;
assert_ne!(
current_message.message_handle,
cloned_message.message_handle
);
Ok(())
}
#[test]
fn message_clone_2() -> Result<()> {
let file_path = Path::new("./data/iceland.grib");
let product_kind = ProductKind::GRIB;
let mut handle = CodesFile::new_from_file(file_path, product_kind)?;
let mut mgen = handle.ref_message_iter();
let msg = mgen.next()?.context("Message not some")?.try_clone()?;
let _ = mgen.next()?;
drop(handle);
let _ = msg.read_key_dynamic("dataDate")?;
let _ = msg.read_key_dynamic("jDirectionIncrementInDegrees")?;
let _ = msg.read_key_dynamic("values")?;
let _ = msg.read_key_dynamic("name")?;
let _ = msg.read_key_dynamic("section1Padding")?;
let _ = msg.read_key_dynamic("experimentVersionNumber")?;
Ok(())
}
#[test]
fn message_clone_drop() -> Result<()> {
let file_path = Path::new("./data/iceland.grib");
let product_kind = ProductKind::GRIB;
let mut handle = CodesFile::new_from_file(file_path, product_kind)?;
let _msg_ref = handle
.ref_message_iter()
.next()?
.context("Message not some")?;
let _msg_clone = _msg_ref.try_clone()?;
drop(_msg_ref);
drop(handle);
drop(_msg_clone);
Ok(())
}
#[test]
fn ref_message_drop_null() -> Result<()> {
let file_path = Path::new("./data/iceland.grib");
let product_kind = ProductKind::GRIB;
let mut handle = CodesFile::new_from_file(file_path, product_kind)?;
let mut current_message = handle
.ref_message_iter()
.next()?
.context("Message not some")?;
current_message.message_handle = std::ptr::null_mut();
Ok(())
}
}