use anyhow::anyhow;
use indexmap::IndexMap;
use num_traits::FromPrimitive;
use serde::{Deserialize, Deserializer, Serialize, Serializer, ser::SerializeStruct};
use crate::variant::{VariantTypeId, VariantValue};
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct MechCommandRegisterValue {
pub type_id: VariantTypeId,
pub value_len: u32,
pub num_columns: u32,
pub num_rows: u32,
pub data: [u8; 255],
}
impl MechCommandRegisterValue {
pub fn new() -> Self {
Self {
type_id: VariantTypeId::Null,
data: [0; 255],
value_len: 0,
num_columns: 1,
num_rows: 1,
}
}
pub fn from_bool(value: bool) -> Self {
let mut data = [0u8; 255];
data[0] = value as u8;
Self {
type_id: VariantTypeId::Bit,
value_len: 1,
data,
num_columns: 1,
num_rows: 1,
}
}
pub fn from_byte(value: u8) -> Self {
let mut data = [0u8; 255];
data[0] = value;
Self {
type_id: VariantTypeId::Byte,
value_len: 1,
data,
num_columns: 1,
num_rows: 1,
}
}
pub fn from_sbyte(value: i8) -> Self {
let mut data = [0u8; 255];
data[0] = value as u8;
Self {
type_id: VariantTypeId::SByte,
value_len: 1,
data,
num_columns: 1,
num_rows: 1,
}
}
pub fn from_int16(value: i16) -> Self {
let mut data = [0u8; 255];
data[..2].copy_from_slice(&value.to_le_bytes());
Self {
type_id: VariantTypeId::Int16,
value_len: 2,
data,
num_columns: 1,
num_rows: 1,
}
}
pub fn from_uint16(value: u16) -> Self {
let mut data = [0u8; 255];
data[..2].copy_from_slice(&value.to_le_bytes());
Self {
type_id: VariantTypeId::UInt16,
value_len: 2,
data,
num_columns: 1,
num_rows: 1,
}
}
pub fn from_int32(value: i32) -> Self {
let mut data = [0u8; 255];
data[..4].copy_from_slice(&value.to_le_bytes());
Self {
type_id: VariantTypeId::Int32,
value_len: 4,
data,
num_columns: 1,
num_rows: 1,
}
}
pub fn from_uint32(value: u32) -> Self {
let mut data = [0u8; 255];
data[..4].copy_from_slice(&value.to_le_bytes());
Self {
type_id: VariantTypeId::UInt32,
value_len: 4,
data,
num_columns: 1,
num_rows: 1,
}
}
pub fn from_int64(value: i64) -> Self {
let mut data = [0u8; 255];
data[..8].copy_from_slice(&value.to_le_bytes());
Self {
type_id: VariantTypeId::Int64,
value_len: 8,
data,
num_columns: 1,
num_rows: 1,
}
}
pub fn from_uint64(value: u64) -> Self {
let mut data = [0u8; 255];
data[..8].copy_from_slice(&value.to_le_bytes());
Self {
type_id: VariantTypeId::UInt64,
value_len: 8,
data,
num_columns: 1,
num_rows: 1,
}
}
pub fn from_real32(value: f32) -> Self {
let mut data = [0u8; 255];
data[..4].copy_from_slice(&value.to_le_bytes());
Self {
type_id: VariantTypeId::Real32,
value_len: 4,
data,
num_columns: 1,
num_rows: 1,
}
}
pub fn from_real64(value: f64) -> Self {
let mut data = [0u8; 255];
data[..8].copy_from_slice(&value.to_le_bytes());
Self {
type_id: VariantTypeId::Real64,
value_len: 8,
data,
num_columns: 1,
num_rows: 1,
}
}
pub fn from_string(value: &str) -> Self {
let bytes = value.as_bytes();
let mut data = [0u8; 255];
let copy_len = std::cmp::min(bytes.len(), 255);
data[..copy_len].copy_from_slice(&bytes[..copy_len]);
Self {
type_id: VariantTypeId::String,
value_len: copy_len as u32,
data,
num_columns: 1,
num_rows: 1,
}
}
pub fn to_bytes(&self) -> [u8; 269] {
let mut ret = [0 as u8; 269];
ret[0..2].copy_from_slice(&(self.type_id as i16).to_le_bytes());
ret[2..6].copy_from_slice(&self.value_len.to_le_bytes());
ret[6..10].copy_from_slice(&self.num_columns.to_le_bytes());
ret[10..14].copy_from_slice(&self.num_rows.to_le_bytes());
ret[14..269].copy_from_slice(&self.data);
return ret;
}
pub fn from_variant(s: &VariantValue) -> Self {
let bytes = postcard::to_allocvec(s).unwrap();
let mut data = [0u8; 255];
let copy_len = std::cmp::min(bytes.len(), 255);
data[..copy_len].copy_from_slice(&bytes[..copy_len]);
Self {
type_id: s.get_type_id(),
value_len: bytes.len() as u32,
data: data,
num_columns: 1,
num_rows: 1,
}
}
pub fn to_bool(&self) -> Result<bool, anyhow::Error> {
if self.type_id == VariantTypeId::Bit {
return Ok(self.data[0] != 0);
} else {
return Err(anyhow!(
"Cannot convert type_id {:?} to bool!",
self.type_id
));
}
}
pub fn to_byte(&self) -> Result<u8, anyhow::Error> {
if self.type_id == VariantTypeId::Byte || self.type_id == VariantTypeId::SByte {
return Ok(self.data[0]);
} else {
return Err(anyhow!(
"Cannot convert type_id {:?} to byte!",
self.type_id
));
}
}
pub fn to_sbyte(&self) -> Result<i8, anyhow::Error> {
if self.type_id == VariantTypeId::SByte || self.type_id == VariantTypeId::Byte {
return Ok(self.data[0] as i8);
} else {
return Err(anyhow!(
"Cannot convert type_id {:?} to sbyte!",
self.type_id
));
}
}
pub fn to_int16(&self) -> Result<i16, anyhow::Error> {
if self.type_id == VariantTypeId::Int16 || self.type_id == VariantTypeId::UInt16 {
let deserialized: i16 = postcard::from_bytes(&self.data[..2])?;
Ok(deserialized)
} else {
return Err(anyhow!(
"Cannot convert type_id {:?} to int16!",
self.type_id
));
}
}
pub fn to_uint16(&self) -> Result<u16, anyhow::Error> {
if self.type_id == VariantTypeId::Int16 || self.type_id == VariantTypeId::UInt16 {
let deserialized: u16 = postcard::from_bytes(&self.data[..2])?;
Ok(deserialized)
} else {
return Err(anyhow!(
"Cannot convert type_id {:?} to uint16!",
self.type_id
));
}
}
pub fn to_int32(&self) -> Result<i32, anyhow::Error> {
if self.type_id == VariantTypeId::Int32 || self.type_id == VariantTypeId::UInt32 {
let deserialized: i32 = postcard::from_bytes(&self.data[..4])?;
Ok(deserialized)
} else {
return Err(anyhow!(
"Cannot convert type_id {:?} to int32!",
self.type_id
));
}
}
pub fn to_uint32(&self) -> Result<u32, anyhow::Error> {
if self.type_id == VariantTypeId::Int32 || self.type_id == VariantTypeId::UInt32 {
let deserialized: u32 = postcard::from_bytes(&self.data[..4])?;
Ok(deserialized)
} else {
return Err(anyhow!(
"Cannot convert type_id {:?} to uint32!",
self.type_id
));
}
}
pub fn to_int64(&self) -> Result<i64, anyhow::Error> {
if self.type_id == VariantTypeId::Int64 || self.type_id == VariantTypeId::UInt64 {
let deserialized: i64 = postcard::from_bytes(&self.data[..8])?;
Ok(deserialized)
} else {
return Err(anyhow!(
"Cannot convert type_id {:?} to int64!",
self.type_id
));
}
}
pub fn to_uint64(&self) -> Result<u64, anyhow::Error> {
if self.type_id == VariantTypeId::Int64 || self.type_id == VariantTypeId::UInt64 {
let deserialized: u64 = postcard::from_bytes(&self.data[..8])?;
Ok(deserialized)
} else {
return Err(anyhow!(
"Cannot convert type_id {:?} to uint64!",
self.type_id
));
}
}
pub fn to_real32(&self) -> Result<f32, anyhow::Error> {
if self.type_id == VariantTypeId::Real32 {
let deserialized: f32 = postcard::from_bytes(&self.data[..4])?;
Ok(deserialized)
} else {
return Err(anyhow!(
"Cannot convert type_id {:?} to real32!",
self.type_id
));
}
}
pub fn to_real64(&self) -> Result<f64, anyhow::Error> {
if self.type_id == VariantTypeId::Real64 {
let deserialized: f64 = postcard::from_bytes(&self.data[..8])?;
Ok(deserialized)
} else {
return Err(anyhow!(
"Cannot convert type_id {:?} to real64!",
self.type_id
));
}
}
pub fn to_string(&self) -> Result<String, anyhow::Error> {
match self.type_id {
VariantTypeId::String => {
match String::from_utf8(self.data[..self.value_len as usize].to_vec()) {
Ok(val) => return Ok(val),
Err(err) => {
return Err(anyhow!("Failed to deserialize string: {}", err));
}
}
}
VariantTypeId::Bit => match self.to_bool() {
Ok(ret) => {
return Ok(ret.to_string());
}
_ => {
return Err(anyhow!("Failed to convert Bit value to bool."));
}
},
VariantTypeId::Byte => match self.to_byte() {
Ok(ret) => {
return Ok(ret.to_string());
}
_ => {
return Err(anyhow!("Failed to convert Byte value to u8."));
}
},
VariantTypeId::SByte => match self.to_sbyte() {
Ok(ret) => {
return Ok(ret.to_string());
}
_ => {
return Err(anyhow!("Failed to convert SByte value to i8."));
}
},
VariantTypeId::Int16 => match self.to_int16() {
Ok(ret) => {
return Ok(ret.to_string());
}
_ => {
return Err(anyhow!("Failed to convert Int16 value to i16."));
}
},
VariantTypeId::UInt16 => match self.to_uint16() {
Ok(ret) => {
return Ok(ret.to_string());
}
_ => {
return Err(anyhow!("Failed to convert UInt16 value to u16."));
}
},
VariantTypeId::Int32 => match self.to_int32() {
Ok(ret) => {
return Ok(ret.to_string());
}
_ => {
return Err(anyhow!("Failed to convert Int32 value to i32."));
}
},
VariantTypeId::UInt32 => match self.to_uint32() {
Ok(ret) => {
return Ok(ret.to_string());
}
_ => {
return Err(anyhow!("Failed to convert UInt32 value to u32."));
}
},
VariantTypeId::Int64 => match self.to_int64() {
Ok(ret) => {
return Ok(ret.to_string());
}
_ => {
return Err(anyhow!("Failed to convert Int64 value to i64."));
}
},
VariantTypeId::UInt64 => match self.to_uint64() {
Ok(ret) => {
return Ok(ret.to_string());
}
_ => {
return Err(anyhow!("Failed to convert UInt64 value to u64."));
}
},
VariantTypeId::Real32 => match self.to_real32() {
Ok(ret) => {
return Ok(ret.to_string());
}
_ => {
return Err(anyhow!("Failed to convert Real32 value to f32."));
}
},
VariantTypeId::Real64 => match self.to_real64() {
Ok(ret) => {
return Ok(ret.to_string());
}
_ => {
return Err(anyhow!("Failed to convert Real64 value to f64."));
}
},
VariantTypeId::Null => Ok("<NULL>".to_string()),
VariantTypeId::Array => Ok("[ARRAY]".to_string()),
VariantTypeId::Object => Ok("{OBJECT}".to_string()),
}
}
pub fn to_variant(&self) -> Result<VariantValue, anyhow::Error> {
match self.type_id {
VariantTypeId::Null => {
return Ok(VariantValue::Null);
}
VariantTypeId::Bit => match self.to_bool() {
Ok(ret) => return Ok(VariantValue::Bit(ret)),
Err(err) => return Err(anyhow!("Failed to conver to bool: {}", err)),
},
VariantTypeId::Byte => match self.to_byte() {
Ok(ret) => return Ok(VariantValue::Byte(ret)),
Err(err) => return Err(anyhow!("Failed to convert to byte: {}", err)),
},
VariantTypeId::SByte => match self.to_sbyte() {
Ok(ret) => return Ok(VariantValue::SByte(ret)),
Err(err) => return Err(anyhow!("Failed to convert to sbyte: {}", err)),
},
VariantTypeId::Int16 => match self.to_int16() {
Ok(ret) => return Ok(VariantValue::Int16(ret)),
Err(err) => return Err(anyhow!("Failed to convert to int16: {}", err)),
},
VariantTypeId::UInt16 => match self.to_uint16() {
Ok(ret) => return Ok(VariantValue::UInt16(ret)),
Err(err) => return Err(anyhow!("Failed to convert to int16: {}", err)),
},
VariantTypeId::Int32 => match self.to_int32() {
Ok(ret) => return Ok(VariantValue::Int32(ret)),
Err(err) => return Err(anyhow!("Failed to convert to int32: {}", err)),
},
VariantTypeId::UInt32 => match self.to_uint32() {
Ok(ret) => return Ok(VariantValue::UInt32(ret)),
Err(err) => return Err(anyhow!("Failed to convert to uint32: {}", err)),
},
VariantTypeId::Int64 => match self.to_int64() {
Ok(ret) => return Ok(VariantValue::Int64(ret)),
Err(err) => return Err(anyhow!("Failed to convert to int64: {}", err)),
},
VariantTypeId::UInt64 => match self.to_uint64() {
Ok(ret) => return Ok(VariantValue::UInt64(ret)),
Err(err) => return Err(anyhow!("Failed to convert to uint64: {}", err)),
},
VariantTypeId::Real32 => match self.to_real32() {
Ok(ret) => return Ok(VariantValue::Real32(ret)),
Err(err) => return Err(anyhow!("Failed to convert to real32: {}", err)),
},
VariantTypeId::Real64 => match self.to_real64() {
Ok(ret) => return Ok(VariantValue::Real64(ret)),
Err(err) => return Err(anyhow!("Failed to convert to real64: {}", err)),
},
VariantTypeId::String => match self.to_string() {
Ok(ret) => return Ok(VariantValue::String(ret)),
Err(err) => return Err(anyhow!("Failed to convert to string: {}", err)),
},
VariantTypeId::Array => {
return Err(anyhow!("Conversion to array not currently supported."));
}
VariantTypeId::Object => {
return Err(anyhow!("Conversion to object not currently supported."));
}
}
}
}
impl Serialize for MechCommandRegisterValue {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut state = serializer.serialize_struct("MechCommandRegisterValue", 5)?;
state.serialize_field("type_id", &(self.type_id as i16))?;
state.serialize_field("data", &self.data[0..self.value_len as usize])?;
state.serialize_field("value_len", &self.value_len)?;
state.serialize_field("num_columns", &self.num_columns)?;
state.serialize_field("num_rows", &self.num_rows)?;
return state.end();
}
}
impl<'de> Deserialize<'de> for MechCommandRegisterValue {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
#[derive(Deserialize)]
struct MechCommandRegisterValueHelper {
type_id: VariantTypeId,
data: Vec<u8>,
value_len: u32,
num_columns: u32,
num_rows: u32,
}
let helper = MechCommandRegisterValueHelper::deserialize(deserializer)?;
let mut data_bytes = [0u8; 255];
let source_length = helper.value_len as usize;
data_bytes[..source_length].copy_from_slice(&helper.data[..source_length]);
return Ok(MechCommandRegisterValue {
type_id: helper.type_id,
data: data_bytes,
value_len: helper.value_len,
num_columns: helper.num_columns,
num_rows: helper.num_rows,
});
}
}
impl TryInto<VariantValue> for MechCommandRegisterValue {
type Error = anyhow::Error;
fn try_into(self) -> Result<VariantValue, anyhow::Error> {
let mut map = IndexMap::new();
map.insert(
"type_id".to_string(),
VariantValue::Int16(self.type_id as i16),
);
map.insert(
"value_len".to_string(),
VariantValue::UInt32(self.value_len),
);
map.insert(
"num_columns".to_string(),
VariantValue::UInt32(self.num_columns),
);
map.insert("num_rows".to_string(), VariantValue::UInt32(self.num_rows));
let mut var_data = Vec::new();
for item in self.data {
var_data.push(VariantValue::Byte(item));
}
map.insert("data".to_string(), VariantValue::Array(var_data));
let ret = VariantValue::Object(Box::new(map));
return Ok(ret);
}
}
impl TryFrom<VariantValue> for MechCommandRegisterValue {
type Error = anyhow::Error;
fn try_from(value: VariantValue) -> Result<Self, Self::Error> {
match value.clone() {
VariantValue::Object(map) => {
let type_id = map
.get("type_id")
.and_then(|v| v.to_int16().ok())
.and_then(|v| VariantTypeId::from_i16(v))
.unwrap_or(VariantTypeId::Null);
let value_len = map
.get("value_len")
.and_then(|v| v.to_uint32().ok())
.and_then(|v| Some(v))
.unwrap_or(0);
let num_columns = map
.get("num_columns")
.and_then(|v| v.to_uint32().ok())
.and_then(|v| Some(v))
.unwrap_or(0);
let num_rows = map
.get("num_rows")
.and_then(|v| v.to_uint32().ok())
.and_then(|v| Some(v))
.unwrap_or(0);
let mut data = [0 as u8; 255];
match map.get("data") {
Some(VariantValue::Array(array)) => {
for (i, item) in array.into_iter().enumerate() {
if let VariantValue::Byte(b) = item {
data[i] = *b;
}
}
}
_ => {
return Err(anyhow!(
"VariantValue::Object data menu is not Object type."
));
}
}
Ok(Self {
type_id: type_id,
value_len: value_len,
num_columns: num_columns,
num_rows: num_rows,
data: data,
})
}
_ => {
return Err(anyhow!("VariantValue is not Object type."));
}
}
}
}