cameleon-genapi 0.1.8

cameleon-genapi provides parser and interpreter of GenApi XML.
Documentation
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use super::{
    elem_type::{AccessMode, MergePriority, NameSpace, Visibility},
    store::{CacheStore, NodeId, NodeStore, ValueStore},
    utils::bool_from_id,
    Device, GenApiResult, ValueCtxt,
};

pub struct NodeBase<'a> {
    pub(crate) attr: &'a NodeAttributeBase,
    pub(crate) elem: &'a NodeElementBase,
}

macro_rules! optional_string_elem_getter {
    (
        $(#[$meta:meta])*
        $name:ident
    ) => {
        $(#[$meta])*
        #[must_use] pub fn $name(&self) -> Option<&'a str> {
            self.elem.$name.as_deref()
        }
    };
}

macro_rules! optional_node_id_elem_getter {
    (
        $(#[$meta:meta])*
        $name:ident
    ) => {
        $(#[$meta])*
        #[must_use] pub fn $name(&self) -> Option<NodeId> {
            self.elem.$name
        }
    };
}

impl<'a> NodeBase<'a> {
    pub(crate) fn new(attr: &'a NodeAttributeBase, elem: &'a NodeElementBase) -> Self {
        Self { attr, elem }
    }

    #[must_use]
    pub fn id(&self) -> NodeId {
        self.attr.id
    }

    #[must_use]
    pub fn name_space(&self) -> NameSpace {
        self.attr.name_space
    }

    #[must_use]
    pub fn merge_priority(&self) -> MergePriority {
        self.attr.merge_priority
    }

    #[must_use]
    pub fn expose_static(&self) -> Option<bool> {
        self.attr.expose_static
    }

    #[must_use]
    pub fn display_name(&self) -> Option<&'a str> {
        self.elem.display_name.as_deref()
    }

    #[must_use]
    pub fn visibility(&self) -> Visibility {
        self.elem.visibility
    }

    #[must_use]
    pub fn is_deprecated(&self) -> bool {
        self.elem.is_deprecated
    }

    #[must_use]
    pub fn imposed_access_mode(&self) -> AccessMode {
        self.elem.imposed_access_mode
    }

    #[must_use]
    pub fn p_errors(&self) -> &'a [NodeId] {
        &self.elem.p_errors
    }

    #[must_use]
    pub fn event_id(&self) -> Option<u64> {
        self.elem.event_id
    }

    optional_string_elem_getter! {description}
    optional_string_elem_getter! {tooltip}
    optional_string_elem_getter! {docu_url}
    optional_node_id_elem_getter! {p_is_implemented}
    optional_node_id_elem_getter! {p_is_available}
    optional_node_id_elem_getter! {p_is_locked}
    optional_node_id_elem_getter! {p_block_polling}
    optional_node_id_elem_getter! {p_alias}
    optional_node_id_elem_getter! {p_cast_alias}
}

#[derive(Debug, Clone)]
pub(crate) struct NodeAttributeBase {
    pub(crate) id: NodeId,
    pub(crate) name_space: NameSpace,
    pub(crate) merge_priority: MergePriority,
    pub(crate) expose_static: Option<bool>,
}

#[derive(Debug, Clone)]
pub(crate) struct NodeElementBase {
    pub(crate) tooltip: Option<String>,
    pub(crate) description: Option<String>,
    pub(crate) display_name: Option<String>,
    pub(crate) visibility: Visibility,
    pub(crate) docu_url: Option<String>,
    pub(crate) is_deprecated: bool,
    pub(crate) event_id: Option<u64>,
    pub(crate) p_is_implemented: Option<NodeId>,
    pub(crate) p_is_available: Option<NodeId>,
    pub(crate) p_is_locked: Option<NodeId>,
    pub(crate) p_block_polling: Option<NodeId>,
    pub(crate) imposed_access_mode: AccessMode,
    pub(crate) p_errors: Vec<NodeId>,
    pub(crate) p_alias: Option<NodeId>,
    pub(crate) p_cast_alias: Option<NodeId>,
    /// `pInvalidator` works only for `Register` kind nodes. It is not used in this crate.
    /// See https://github.com/cameleon-rs/cameleon/issues/138 for more details.
    pub(crate) p_invalidators: Vec<NodeId>,
}

impl NodeElementBase {
    pub(super) fn is_readable<T: ValueStore, U: CacheStore>(
        &self,
        device: &mut impl Device,
        store: &impl NodeStore,
        cx: &mut ValueCtxt<T, U>,
    ) -> GenApiResult<bool> {
        Ok(self.is_implemented(device, store, cx)?
            && self.is_available(device, store, cx)?
            && matches!(self.imposed_access_mode, AccessMode::RO | AccessMode::RW))
    }

    pub(super) fn is_writable<T: ValueStore, U: CacheStore>(
        &self,
        device: &mut impl Device,
        store: &impl NodeStore,
        cx: &mut ValueCtxt<T, U>,
    ) -> GenApiResult<bool> {
        Ok(self.is_implemented(device, store, cx)?
            && self.is_available(device, store, cx)?
            && !self.is_locked(device, store, cx)?
            && matches!(self.imposed_access_mode, AccessMode::WO | AccessMode::RW))
    }

    pub(super) fn is_locked<T: ValueStore, U: CacheStore>(
        &self,
        device: &mut impl Device,
        store: &impl NodeStore,
        cx: &mut ValueCtxt<T, U>,
    ) -> GenApiResult<bool> {
        self.p_is_locked
            .map_or(Ok(false), |nid| bool_from_id(nid, device, store, cx))
    }

    pub(super) fn is_implemented<T: ValueStore, U: CacheStore>(
        &self,
        device: &mut impl Device,
        store: &impl NodeStore,
        cx: &mut ValueCtxt<T, U>,
    ) -> GenApiResult<bool> {
        self.p_is_implemented
            .map_or(Ok(true), |nid| bool_from_id(nid, device, store, cx))
    }

    pub(super) fn is_available<T: ValueStore, U: CacheStore>(
        &self,
        device: &mut impl Device,
        store: &impl NodeStore,
        cx: &mut ValueCtxt<T, U>,
    ) -> GenApiResult<bool> {
        self.p_is_available
            .map_or(Ok(true), |nid| bool_from_id(nid, device, store, cx))
    }
}