dnp3 1.6.0

Rust implementation of DNP3 (IEEE 1815) with idiomatic bindings for C, C++, .NET, and Java
Documentation
use crate::app::parse::parser::HeaderCollection;
use crate::app::Iin2;
use crate::app::Sequence;
use crate::outstation::database::read::ReadHeader;
use crate::outstation::database::DatabaseHandle;
use crate::transport::FragmentInfo;

#[derive(Copy, Clone)]
pub(crate) struct DeferredInfo {
    pub(crate) hash: u64,
    pub(crate) seq: Sequence,
    pub(crate) info: FragmentInfo,
    pub(crate) iin2: Iin2,
}

impl DeferredInfo {
    fn new(hash: u64, seq: Sequence, info: FragmentInfo, iin2: Iin2) -> Self {
        DeferredInfo {
            hash,
            seq,
            info,
            iin2,
        }
    }

    fn merge(&self, iin2: Iin2) -> Self {
        Self::new(self.hash, self.seq, self.info, self.iin2 | iin2)
    }
}

pub(crate) struct DeferredRead {
    info: Option<DeferredInfo>,
    vec: Vec<ReadHeader>,
}

impl DeferredRead {
    pub(crate) fn new(header_capacity: u16) -> Self {
        Self {
            info: None,
            vec: Vec::with_capacity(header_capacity as usize),
        }
    }

    pub(crate) fn clear(&mut self) {
        self.info = None;
        self.vec.clear();
    }

    pub(crate) fn is_set(&self) -> bool {
        self.info.is_some()
    }

    pub(crate) fn set(
        &mut self,
        hash: u64,
        seq: Sequence,
        info: FragmentInfo,
        headers: HeaderCollection,
    ) {
        self.vec.clear();

        let mut iin2 = Iin2::default();

        for h in headers.iter() {
            if let Some(r) = ReadHeader::get(&h) {
                if self.vec.len() < self.vec.capacity() {
                    self.vec.push(r)
                } else {
                    tracing::warn!(
                        "insufficient capacity ({}) for READ header: {} - {}",
                        self.vec.capacity(),
                        h.variation,
                        h.details.qualifier()
                    )
                }
            } else {
                iin2 = Iin2::PARAMETER_ERROR;
            }
        }

        self.info = Some(DeferredInfo::new(hash, seq, info, iin2));
    }

    pub(crate) fn select(&mut self, database: &DatabaseHandle) -> Option<DeferredInfo> {
        match self.info {
            None => None,
            Some(x) => {
                let iin2 = database.transaction(|db| {
                    db.inner.reset();
                    let mut iin2 = Iin2::default();
                    for header in self.vec.iter() {
                        iin2 |= db.inner.select_by_header(*header);
                    }
                    iin2
                });
                self.clear();
                Some(x.merge(iin2))
            }
        }
    }
}