use crate::{Gain, Scaled, ValueRange};
pub trait NumericValue {
type ScaledOut;
type ModbusValue;
fn value_range(&self) -> ValueRange;
fn scaled(&self) -> Self::ScaledOut;
}
pub trait UnitValue: std::fmt::Debug {
type Inner: NumericValue + Copy;
fn inner(&self) -> &Self::Inner;
fn new(inner: Self::Inner) -> Self;
}
impl<T> NumericValue for T
where
T: UnitValue,
{
type ScaledOut = <T::Inner as NumericValue>::ScaledOut;
type ModbusValue = <T::Inner as NumericValue>::ModbusValue;
fn value_range(&self) -> ValueRange {
self.inner().value_range()
}
fn scaled(&self) -> Self::ScaledOut {
self.inner().scaled()
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct U8(pub u8, pub Gain, pub ValueRange);
impl From<U8> for U16 {
fn from(value: U8) -> Self {
Self(value.0.into(), value.1, value.2)
}
}
impl From<U8> for U32 {
fn from(value: U8) -> Self {
Self(value.0.into(), value.1, value.2)
}
}
impl From<U8> for I16 {
fn from(value: U8) -> Self {
Self(value.0.into(), value.1, value.2)
}
}
impl From<U8> for I32 {
fn from(value: U8) -> Self {
Self(value.0.into(), value.1, value.2)
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct U16(pub u16, pub Gain, pub ValueRange);
impl NumericValue for U16 {
type ScaledOut = f32;
type ModbusValue = u16;
fn value_range(&self) -> ValueRange {
self.2
}
fn scaled(&self) -> Self::ScaledOut {
self.0.scaled(self.1)
}
}
impl std::fmt::Debug for U16 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if f.alternate() {
f.write_fmt(format_args!("{}", self.0.scaled(self.1)))
} else {
f.debug_tuple("U16")
.field(&self.0)
.field(&self.1)
.field(&self.2)
.finish()
}
}
}
impl From<U16> for U32 {
fn from(value: U16) -> Self {
Self(value.0.into(), value.1, value.2)
}
}
impl From<U16> for I32 {
fn from(value: U16) -> Self {
Self(value.0.into(), value.1, value.2)
}
}
impl From<I16> for I32 {
fn from(value: I16) -> Self {
Self(value.0.into(), value.1, value.2)
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct U32(pub u32, pub Gain, pub ValueRange);
impl std::fmt::Debug for U32 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if f.alternate() {
f.write_fmt(format_args!("{}", self.0.scaled(self.1)))
} else {
f.debug_tuple("U32")
.field(&self.0)
.field(&self.1)
.field(&self.2)
.finish()
}
}
}
impl NumericValue for U32 {
type ScaledOut = f64;
type ModbusValue = u32;
fn value_range(&self) -> ValueRange {
self.2
}
fn scaled(&self) -> Self::ScaledOut {
self.0.scaled(self.1)
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct I16(pub i16, pub Gain, pub ValueRange);
impl std::fmt::Debug for I16 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if f.alternate() {
f.write_fmt(format_args!("{}", self.0.scaled(self.1)))
} else {
f.debug_tuple("I16")
.field(&self.0)
.field(&self.1)
.field(&self.2)
.finish()
}
}
}
impl NumericValue for I16 {
type ScaledOut = f32;
type ModbusValue = i16;
fn value_range(&self) -> ValueRange {
self.2
}
fn scaled(&self) -> Self::ScaledOut {
self.0.scaled(self.1)
}
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct I32(pub i32, pub Gain, pub ValueRange);
impl std::fmt::Debug for I32 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if f.alternate() {
f.write_fmt(format_args!("{}", self.0.scaled(self.1)))
} else {
f.debug_tuple("I32")
.field(&self.0)
.field(&self.1)
.field(&self.2)
.finish()
}
}
}
impl NumericValue for I32 {
type ScaledOut = f64;
type ModbusValue = i32;
fn value_range(&self) -> ValueRange {
self.2
}
fn scaled(&self) -> Self::ScaledOut {
self.0.scaled(self.1)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Percent<T: From<U8>>(T);
impl<T: From<U8>> From<T> for Percent<T> {
fn from(value: T) -> Self {
Self(value)
}
}
impl UnitValue for Percent<U16> {
type Inner = U16;
fn inner(&self) -> &Self::Inner {
&self.0
}
fn new(inner: Self::Inner) -> Self {
Self(inner)
}
}
impl UnitValue for Percent<I16> {
type Inner = I16;
fn inner(&self) -> &Self::Inner {
&self.0
}
fn new(inner: Self::Inner) -> Self {
Self(inner)
}
}
impl UnitValue for Percent<U32> {
type Inner = U32;
fn inner(&self) -> &Self::Inner {
&self.0
}
fn new(inner: Self::Inner) -> Self {
Self(inner)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct PercentPerSecond(U32);
impl From<U32> for PercentPerSecond {
fn from(value: U32) -> Self {
Self(value)
}
}
impl UnitValue for PercentPerSecond {
type Inner = U32;
fn inner(&self) -> &Self::Inner {
&self.0
}
fn new(inner: Self::Inner) -> Self {
Self(inner)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct DegreesCelsius(I16);
impl From<I16> for DegreesCelsius {
fn from(value: I16) -> Self {
Self(value)
}
}
impl UnitValue for DegreesCelsius {
type Inner = I16;
fn inner(&self) -> &Self::Inner {
&self.0
}
fn new(inner: Self::Inner) -> Self {
Self(inner)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct A<T: Into<I32>>(T);
impl<T: Into<I32>> From<T> for A<T> {
fn from(value: T) -> Self {
Self(value)
}
}
impl UnitValue for A<I32> {
type Inner = I32;
fn inner(&self) -> &Self::Inner {
&self.0
}
fn new(inner: Self::Inner) -> Self {
Self(inner)
}
}
impl UnitValue for A<I16> {
type Inner = I16;
fn inner(&self) -> &Self::Inner {
&self.0
}
fn new(inner: Self::Inner) -> Self {
Self(inner)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Hz<T: From<U8>>(T);
impl<T: From<U8>> From<T> for Hz<T> {
fn from(value: T) -> Self {
Self(value)
}
}
impl UnitValue for Hz<U16> {
type Inner = U16;
fn inner(&self) -> &Self::Inner {
&self.0
}
fn new(inner: Self::Inner) -> Self {
Self(inner)
}
}
impl UnitValue for Hz<I16> {
type Inner = I16;
fn inner(&self) -> &Self::Inner {
&self.0
}
fn new(inner: Self::Inner) -> Self {
Self(inner)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct KVA(U32);
impl From<U32> for KVA {
fn from(value: U32) -> Self {
Self(value)
}
}
impl UnitValue for KVA {
type Inner = U32;
fn inner(&self) -> &Self::Inner {
&self.0
}
fn new(inner: Self::Inner) -> Self {
Self(inner)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct KVar(I32);
impl From<I32> for KVar {
fn from(value: I32) -> Self {
Self(value)
}
}
impl UnitValue for KVar {
type Inner = I32;
fn inner(&self) -> &Self::Inner {
&self.0
}
fn new(inner: Self::Inner) -> Self {
Self(inner)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct KW<T: From<U16>>(T);
impl<T: From<U16>> From<T> for KW<T> {
fn from(value: T) -> Self {
Self(value)
}
}
impl UnitValue for KW<U16> {
type Inner = U16;
fn inner(&self) -> &Self::Inner {
&self.0
}
fn new(inner: Self::Inner) -> Self {
Self(inner)
}
}
impl UnitValue for KW<I32> {
type Inner = I32;
fn inner(&self) -> &Self::Inner {
&self.0
}
fn new(inner: Self::Inner) -> Self {
Self(inner)
}
}
impl UnitValue for KW<U32> {
type Inner = U32;
fn inner(&self) -> &Self::Inner {
&self.0
}
fn new(inner: Self::Inner) -> Self {
Self(inner)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Wh(U32);
impl From<U32> for Wh {
fn from(value: U32) -> Self {
Self(value)
}
}
impl UnitValue for Wh {
type Inner = U32;
fn inner(&self) -> &Self::Inner {
&self.0
}
fn new(inner: Self::Inner) -> Self {
Self(inner)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct KWh(U32);
impl From<U32> for KWh {
fn from(value: U32) -> Self {
Self(value)
}
}
impl UnitValue for KWh {
type Inner = U32;
fn inner(&self) -> &Self::Inner {
&self.0
}
fn new(inner: Self::Inner) -> Self {
Self(inner)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Minutes(U16);
impl From<U16> for Minutes {
fn from(value: U16) -> Self {
Self(value)
}
}
impl UnitValue for Minutes {
type Inner = U16;
fn inner(&self) -> &Self::Inner {
&self.0
}
fn new(inner: Self::Inner) -> Self {
Self(inner)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct MΩ(U16);
impl From<U16> for MΩ {
fn from(value: U16) -> Self {
Self(value)
}
}
impl UnitValue for MΩ {
type Inner = U16;
fn inner(&self) -> &Self::Inner {
&self.0
}
fn new(inner: Self::Inner) -> Self {
Self(inner)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct V<T: From<U8>>(T);
impl<T: From<U8>> From<T> for V<T> {
fn from(value: T) -> Self {
Self(value)
}
}
impl UnitValue for V<U16> {
type Inner = U16;
fn inner(&self) -> &Self::Inner {
&self.0
}
fn new(inner: Self::Inner) -> Self {
Self(inner)
}
}
impl UnitValue for V<I16> {
type Inner = I16;
fn inner(&self) -> &Self::Inner {
&self.0
}
fn new(inner: Self::Inner) -> Self {
Self(inner)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct W<T: From<U16>>(T);
impl<T: From<U16>> From<T> for W<T> {
fn from(value: T) -> Self {
Self(value)
}
}
impl UnitValue for W<U32> {
type Inner = U32;
fn inner(&self) -> &Self::Inner {
&self.0
}
fn new(inner: Self::Inner) -> Self {
Self(inner)
}
}
impl UnitValue for W<I32> {
type Inner = I32;
fn inner(&self) -> &Self::Inner {
&self.0
}
fn new(inner: Self::Inner) -> Self {
Self(inner)
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct Bytes(Vec<u8>);
impl Bytes {
pub(crate) fn take(self) -> Vec<u8> {
self.0
}
}
impl From<Vec<u8>> for Bytes {
fn from(value: Vec<u8>) -> Self {
Self(value)
}
}
#[cfg(test)]
mod tests {
use crate::{unitvalues::NumericValue, ValueRange};
use super::{Percent, U16, U32};
#[test]
fn u16_debug_alternate() {
let val = U16(1337, 100u16.into(), ValueRange::default());
assert_eq!(format!("{val:#?}"), "13.37");
}
#[test]
fn u16_debug() {
let val = U16(1337, 100u16.into(), ValueRange::new_fixed(2, 4));
assert_eq!(
format!("{val:?}"),
"U16(1337, Fixed(100), ValueRange { min: Fixed(2), max: Fixed(4), mirrored: false })"
);
}
#[test]
fn percent_works() {
let percent1 = Percent(U16(1337, 100u8.into(), ValueRange::default()));
let percent2 = Percent(U32(1337, 10u8.into(), ValueRange::default()));
assert_eq!(percent1.scaled(), 13.37);
assert_eq!(percent2.scaled(), 133.7);
}
}