mod node_kind;
pub use node_kind::{
BooleanNode, CategoryNode, CommandNode, EnumEntryNode, EnumerationNode, FloatNode, IntegerNode,
Node, PortNode, RegisterNode, StringNode,
};
use std::{
convert::TryInto,
sync::{Arc, Mutex},
};
use auto_impl::auto_impl;
use cameleon_genapi::{builder::GenApiBuilder, store};
use super::{ControlError, ControlResult, DeviceControl};
pub use cameleon_genapi::{
elem_type::{AccessMode, NameSpace, Visibility},
store::{
CacheSink, CacheStore, DefaultCacheStore, DefaultNodeStore, DefaultValueStore, NodeId,
NodeStore, ValueStore,
},
GenApiError, RegisterDescription, ValueCtxt,
};
#[derive(Debug, Clone)]
pub struct ParamsCtxt<Ctrl, Ctxt> {
pub ctrl: Ctrl,
pub ctxt: Ctxt,
}
impl<Ctrl, Ctxt> ParamsCtxt<Ctrl, Ctxt>
where
Ctxt: GenApiCtxt,
{
pub fn node(&self, name: &str) -> Option<Node> {
let ns = self.ctxt.node_store();
ns.id_by_name(name).map(Node)
}
pub fn node_store(&self) -> &Ctxt::NS {
self.ctxt.node_store()
}
}
impl<Ctrl, Ctxt> ParamsCtxt<Ctrl, Ctxt>
where
Ctrl: DeviceControl,
Ctxt: GenApiCtxt,
{
pub fn enter<F, R>(&mut self, f: F) -> R
where
F: FnOnce(&mut Ctrl, &mut Ctxt) -> R,
{
f(&mut self.ctrl, &mut self.ctxt)
}
pub fn enter2<F, R>(&mut self, f: F) -> R
where
F: FnOnce(&mut Ctrl, &Ctxt::NS, &mut ValueCtxt<Ctxt::VS, Ctxt::CS>) -> R,
{
self.enter(|ctrl, ctxt| {
ctxt.enter(|node_store, value_ctxt| f(ctrl, node_store, value_ctxt))
})
}
}
impl<Ctrl, Ctxt> ParamsCtxt<Ctrl, Ctxt> {
pub fn convert_from<Ctrl2, Ctxt2>(from: ParamsCtxt<Ctrl2, Ctxt2>) -> Self
where
Ctrl: From<Ctrl2>,
Ctxt: From<Ctxt2>,
{
ParamsCtxt {
ctrl: from.ctrl.into(),
ctxt: from.ctxt.into(),
}
}
pub fn convert_into<Ctrl2, Ctxt2>(self) -> ParamsCtxt<Ctrl2, Ctxt2>
where
Ctrl: Into<Ctrl2>,
Ctxt: Into<Ctxt2>,
{
ParamsCtxt {
ctrl: self.ctrl.into(),
ctxt: self.ctxt.into(),
}
}
}
#[auto_impl(&mut, Box)]
pub trait GenApiCtxt {
type NS: NodeStore;
type VS: ValueStore;
type CS: CacheStore;
fn enter<F, R>(&mut self, f: F) -> R
where
F: FnOnce(&Self::NS, &mut ValueCtxt<Self::VS, Self::CS>) -> R;
fn node_store(&self) -> &Self::NS;
fn clear_cache(&mut self) {
self.enter(|_, value_ctxt| value_ctxt.clear_cache())
}
}
pub trait FromXml {
fn from_xml(xml: &impl AsRef<str>) -> ControlResult<Self>
where
Self: Sized + GenApiCtxt;
}
#[derive(Debug)]
pub struct DefaultGenApiCtxt {
pub node_store: store::DefaultNodeStore,
pub value_ctxt: ValueCtxt<store::DefaultValueStore, store::DefaultCacheStore>,
pub reg_desc: RegisterDescription,
}
impl GenApiCtxt for DefaultGenApiCtxt {
type NS = store::DefaultNodeStore;
type VS = store::DefaultValueStore;
type CS = store::DefaultCacheStore;
fn enter<F, R>(&mut self, f: F) -> R
where
F: FnOnce(&Self::NS, &mut ValueCtxt<Self::VS, Self::CS>) -> R,
{
f(&self.node_store, &mut self.value_ctxt)
}
fn node_store(&self) -> &Self::NS {
&self.node_store
}
}
impl FromXml for DefaultGenApiCtxt {
fn from_xml(xml: &impl AsRef<str>) -> ControlResult<Self>
where
Self: Sized + GenApiCtxt,
{
let (reg_desc, node_store, value_ctxt) = GenApiBuilder::<DefaultNodeStore>::default()
.build(xml)
.map_err(|e| ControlError::InvalidData(e.into()))?;
Ok(Self {
node_store,
value_ctxt,
reg_desc,
})
}
}
#[derive(Clone, Debug)]
pub struct SharedDefaultGenApiCtxt {
pub node_store: Arc<store::DefaultNodeStore>,
pub value_ctxt: Arc<Mutex<ValueCtxt<store::DefaultValueStore, store::DefaultCacheStore>>>,
pub reg_desc: Arc<RegisterDescription>,
}
impl GenApiCtxt for SharedDefaultGenApiCtxt {
type NS = store::DefaultNodeStore;
type VS = store::DefaultValueStore;
type CS = store::DefaultCacheStore;
fn enter<F, R>(&mut self, f: F) -> R
where
F: FnOnce(&Self::NS, &mut ValueCtxt<Self::VS, Self::CS>) -> R,
{
f(&self.node_store, &mut self.value_ctxt.lock().unwrap())
}
fn node_store(&self) -> &Self::NS {
&self.node_store
}
}
impl FromXml for SharedDefaultGenApiCtxt {
fn from_xml(xml: &impl AsRef<str>) -> ControlResult<Self>
where
Self: Sized + GenApiCtxt,
{
Ok(DefaultGenApiCtxt::from_xml(xml)?.into())
}
}
impl From<DefaultGenApiCtxt> for SharedDefaultGenApiCtxt {
fn from(ctxt: DefaultGenApiCtxt) -> Self {
Self {
node_store: Arc::new(ctxt.node_store),
value_ctxt: Arc::new(Mutex::new(ctxt.value_ctxt)),
reg_desc: Arc::new(ctxt.reg_desc),
}
}
}
#[derive(Debug)]
pub struct NoCacheGenApiCtxt {
pub node_store: store::DefaultNodeStore,
pub value_ctxt: ValueCtxt<store::DefaultValueStore, store::CacheSink>,
pub reg_desc: RegisterDescription,
}
impl GenApiCtxt for NoCacheGenApiCtxt {
type NS = store::DefaultNodeStore;
type VS = store::DefaultValueStore;
type CS = store::CacheSink;
fn enter<F, R>(&mut self, f: F) -> R
where
F: FnOnce(&Self::NS, &mut ValueCtxt<Self::VS, Self::CS>) -> R,
{
f(&self.node_store, &mut self.value_ctxt)
}
fn node_store(&self) -> &Self::NS {
&self.node_store
}
}
impl FromXml for NoCacheGenApiCtxt {
fn from_xml(xml: &impl AsRef<str>) -> ControlResult<Self>
where
Self: Sized + GenApiCtxt,
{
let (reg_desc, node_store, value_ctxt) = GenApiBuilder::<DefaultNodeStore>::default()
.no_cache()
.build(xml)
.map_err(|e| ControlError::InvalidData(e.into()))?;
Ok(Self {
node_store,
value_ctxt,
reg_desc,
})
}
}
impl From<DefaultGenApiCtxt> for NoCacheGenApiCtxt {
fn from(from: DefaultGenApiCtxt) -> Self {
Self {
node_store: from.node_store,
value_ctxt: ValueCtxt::new(from.value_ctxt.value_store, store::CacheSink::default()),
reg_desc: from.reg_desc,
}
}
}
#[derive(Clone, Debug)]
pub struct SharedNoCacheGenApiCtxt {
pub node_store: Arc<store::DefaultNodeStore>,
pub value_ctxt: Arc<Mutex<ValueCtxt<store::DefaultValueStore, store::CacheSink>>>,
pub reg_desc: Arc<RegisterDescription>,
}
impl GenApiCtxt for SharedNoCacheGenApiCtxt {
type NS = store::DefaultNodeStore;
type VS = store::DefaultValueStore;
type CS = store::CacheSink;
fn enter<F, R>(&mut self, f: F) -> R
where
F: FnOnce(&Self::NS, &mut ValueCtxt<Self::VS, Self::CS>) -> R,
{
f(&self.node_store, &mut self.value_ctxt.lock().unwrap())
}
fn node_store(&self) -> &Self::NS {
&self.node_store
}
}
impl FromXml for SharedNoCacheGenApiCtxt {
fn from_xml(xml: &impl AsRef<str>) -> ControlResult<Self>
where
Self: Sized + GenApiCtxt,
{
Ok(NoCacheGenApiCtxt::from_xml(xml)?.into())
}
}
impl From<NoCacheGenApiCtxt> for SharedNoCacheGenApiCtxt {
fn from(from: NoCacheGenApiCtxt) -> Self {
Self {
node_store: Arc::new(from.node_store),
value_ctxt: Arc::new(Mutex::new(from.value_ctxt)),
reg_desc: Arc::new(from.reg_desc),
}
}
}
impl From<DefaultGenApiCtxt> for SharedNoCacheGenApiCtxt {
fn from(from: DefaultGenApiCtxt) -> Self {
let ctxt: NoCacheGenApiCtxt = from.into();
ctxt.into()
}
}
#[derive(Debug, Clone, Copy)]
pub enum CompressionType {
Uncompressed,
Zip,
}
struct GenApiDevice<'a, T> {
inner: &'a mut T,
}
impl<'a, T> GenApiDevice<'a, T> {
fn new(inner: &'a mut T) -> Self {
Self { inner }
}
}
impl<T> cameleon_genapi::Device for GenApiDevice<'_, T>
where
T: DeviceControl,
{
fn read_mem(
&mut self,
address: i64,
data: &mut [u8],
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let address: u64 = address.try_into().map_err(|_| {
ControlError::InvalidData(
"invalid address: the given address has negative value".into(),
)
})?;
Ok(self.inner.read(address, data)?)
}
fn write_mem(
&mut self,
address: i64,
data: &[u8],
) -> std::result::Result<(), Box<dyn std::error::Error + Send + Sync>> {
let address: u64 = address.try_into().map_err(|_| {
ControlError::InvalidData(
"invalid address: the given address has negative value".into(),
)
})?;
Ok(self.inner.write(address, data)?)
}
}