use alloc::vec::Vec;
use core::fmt::Debug;
use crate::protocol::{
Function,
function::{ReadHoldingRegisters, ReadHoldingRegistersExact, read_registers},
};
pub trait AsyncClient {
type UnitId: Debug;
type Error: From<crate::protocol::Error>;
#[expect(async_fn_in_trait)]
async fn call<F: Function>(
&self,
unit_id: Self::UnitId,
args: F::Args,
) -> Result<F::Output, Self::Error>;
#[expect(async_fn_in_trait)]
#[cfg_attr(feature = "tracing", tracing::instrument(skip_all, level = "trace"))]
async fn read_holding_registers<V: read_registers::Value>(
&self,
unit_id: Self::UnitId,
starting_address: u16,
n_values: usize,
) -> Result<Vec<V>, Self::Error> {
#[cfg(feature = "tracing")]
tracing::trace!(?unit_id, starting_address, n_values, "reading holding registers…");
let args = read_registers::Args::new(starting_address, n_values)?;
Ok(self.call::<ReadHoldingRegisters<V>>(unit_id, args).await?.values)
}
#[expect(async_fn_in_trait)]
#[cfg_attr(feature = "tracing", tracing::instrument(skip_all, level = "trace"))]
async fn read_holding_registers_exact<const N: usize, V: read_registers::Value>(
&self,
unit_id: Self::UnitId,
starting_address: u16,
) -> Result<[V; N], Self::Error> {
#[cfg(feature = "tracing")]
tracing::trace!(?unit_id, starting_address, N, "reading holding registers…");
let args = read_registers::Args::new(starting_address, N)?;
Ok(self.call::<ReadHoldingRegistersExact<N, V>>(unit_id, args).await?.values)
}
#[expect(async_fn_in_trait)]
async fn read_holding_registers_value<V: read_registers::Value>(
&self,
unit_id: Self::UnitId,
address: u16,
) -> Result<V, Self::Error> {
let [value] = self.read_holding_registers_exact::<1, V>(unit_id, address).await?;
Ok(value)
}
}