motorcortex-rust 0.5.0

Motorcortex Rust: a Rust client for the Motorcortex Core real-time control system (async + blocking).
Documentation
use crate::{DataType, GetParameterValue, SetParameterValue};

pub fn encode_parameter_value<V>(data_type: u32, value: &V) -> Vec<u8>
where
    V: SetParameterValue,
{
    // Unknown / out-of-range wire codes fall through to an empty
    // buffer — same behaviour as the explicit "_ => Vec::new()"
    // below. The prior `.unwrap()` here would panic if a server
    // ever sent a dtype the proto enum didn't know about.
    let Ok(dtype) = DataType::try_from(data_type as i32) else {
        return Vec::new();
    };
    match dtype {
        DataType::Bool => value.to_bytes_as_bool(),
        DataType::Int8 => value.to_bytes_as_i8(),
        DataType::Uint8 => value.to_bytes_as_u8(),
        DataType::Int16 => value.to_bytes_as_i16(),
        DataType::Uint16 => value.to_bytes_as_u16(),
        DataType::Int32 => value.to_bytes_as_i32(),
        DataType::Uint32 => value.to_bytes_as_u32(),
        DataType::Int64 => value.to_bytes_as_i64(),
        DataType::Uint64 => value.to_bytes_as_u64(),
        DataType::Float => value.to_bytes_as_f32(),
        DataType::Double => value.to_bytes_as_f64(),
        DataType::String => value.to_bytes_as_string(),
        _ => Vec::new(),
    }
}
pub fn decode_parameter_value<V>(data_type: u32, bytes: &[u8]) -> V
where
    V: GetParameterValue + Default,
{
    // Unknown / out-of-range wire codes fall through to `V::default`
    // — same semantics as the explicit "_ =>" arm below. The prior
    // `.unwrap()` would have panicked on a malformed server reply.
    let Ok(dtype) = DataType::try_from(data_type as i32) else {
        return V::default();
    };
    match dtype {
        DataType::Bool => {
            return V::from_bytes_as_bool(bytes).unwrap();
        }
        DataType::Int8 => {
            return V::from_bytes_as_i8(bytes).unwrap();
        }
        DataType::Uint8 => {
            return V::from_bytes_as_u8(bytes).unwrap();
        }
        DataType::Int16 => {
            return V::from_bytes_as_i16(bytes).unwrap();
        }
        DataType::Uint16 => {
            return V::from_bytes_as_u16(bytes).unwrap();
        }
        DataType::Int32 => {
            return V::from_bytes_as_i32(bytes).unwrap();
        }
        DataType::Uint32 => {
            return V::from_bytes_as_u32(bytes).unwrap();
        }
        DataType::Int64 => {
            return V::from_bytes_as_i64(bytes).unwrap();
        }
        DataType::Uint64 => {
            return V::from_bytes_as_u64(bytes).unwrap();
        }
        DataType::Float => {
            return V::from_bytes_as_f32(bytes).unwrap();
        }
        DataType::Double => {
            return V::from_bytes_as_f64(bytes).unwrap();
        }
        DataType::String => {
            return V::from_bytes_as_string(bytes).unwrap();
        }
        // Bytes / Char / UserType / Undefined are valid enum variants
        // but don't have a wire codec here — return the default.
        _ => {}
    }
    V::default()
}

#[cfg(test)]
mod tests {
    //! Exercise the `_` arms in both dispatchers. `Bytes`, `Char`,
    //! `UserType`, and `Undefined` are valid `DataType` variants but
    //! aren't listed in either match — both functions fall through to
    //! "empty Vec" / "default value" rather than erroring.
    //!
    //! Encoder/decoder helpers aren't re-exported from the crate root,
    //! so this coverage lives inside the module as `#[cfg(test)]`.

    use super::*;

    const UNSUPPORTED: &[DataType] = &[
        DataType::Undefined,
        DataType::Char,
        DataType::Bytes,
        DataType::UserType,
    ];

    #[test]
    fn encode_unsupported_dtypes_return_empty_vec() {
        for &dtype in UNSUPPORTED {
            let bytes = encode_parameter_value(dtype as u32, &42i32);
            assert!(bytes.is_empty(), "{dtype:?} must fall through to empty");
        }
    }

    #[test]
    fn decode_unsupported_dtypes_return_default() {
        for &dtype in UNSUPPORTED {
            let value: i32 = decode_parameter_value(dtype as u32, &[]);
            assert_eq!(value, 0, "{dtype:?} must fall through to Default");
        }
    }

    #[test]
    fn encode_out_of_range_dtype_does_not_panic() {
        // A u32 that doesn't map to any DataType variant — mustn't
        // panic. The prior `.unwrap()` would have; fallthrough now
        // produces an empty buffer.
        let bytes = encode_parameter_value(u32::MAX, &42i32);
        assert!(bytes.is_empty());
    }

    #[test]
    fn decode_out_of_range_dtype_returns_default() {
        let value: i32 = decode_parameter_value(u32::MAX, &[]);
        assert_eq!(value, 0);
    }
}