use std::convert::{TryFrom, TryInto};
use std::marker::PhantomData;
use std::time::SystemTime;
use super::types::{ResponseFlags, TrafficDirection};
use crate::host;
use self::types::*;
pub(super) mod types {
pub struct ByteString;
pub struct _Bytes;
pub struct Int64;
pub struct UInt64;
pub struct _Float64;
pub struct Bool;
pub struct Duration;
pub struct Timestamp;
pub struct _ProtoMessage;
pub struct _ProtoMap;
pub struct _ProtoList;
}
pub(super) struct Value<T> {
bytes: Vec<u8>,
_type: PhantomData<T>,
}
impl<T> Value<T> {
pub fn new(bytes: Vec<u8>) -> Self {
Value {
bytes,
_type: PhantomData,
}
}
}
impl TryFrom<Value<ByteString>> for String {
type Error = host::Error;
fn try_from(value: Value<ByteString>) -> host::Result<Self> {
Ok(String::from_utf8(value.bytes)?)
}
}
impl TryFrom<Value<ByteString>> for host::ByteString {
type Error = host::Error;
fn try_from(value: Value<ByteString>) -> host::Result<Self> {
Ok(value.bytes.into())
}
}
impl TryFrom<Value<Int64>> for i32 {
type Error = host::Error;
fn try_from(value: Value<Int64>) -> host::Result<Self> {
let value: i64 = value.try_into()?;
Ok(value.try_into()?)
}
}
impl TryFrom<Value<Int64>> for i64 {
type Error = host::Error;
fn try_from(value: Value<Int64>) -> host::Result<Self> {
let bytes: [u8; std::mem::size_of::<Self>()] = value.bytes.as_slice().try_into()?;
Ok(Self::from_le_bytes(bytes))
}
}
impl TryFrom<Value<Int64>> for u64 {
type Error = host::Error;
fn try_from(value: Value<Int64>) -> host::Result<Self> {
let bytes: [u8; std::mem::size_of::<Self>()] = value.bytes.as_slice().try_into()?;
Ok(Self::from_le_bytes(bytes))
}
}
impl TryFrom<Value<Bool>> for bool {
type Error = host::Error;
fn try_from(value: Value<Bool>) -> host::Result<Self> {
let bytes: [u8; 1] = value.bytes.as_slice().try_into()?;
let value = u8::from_le_bytes(bytes);
Ok(value != 0)
}
}
impl TryFrom<Value<Int64>> for u16 {
type Error = host::Error;
fn try_from(value: Value<Int64>) -> host::Result<Self> {
let value: i64 = value.try_into()?;
Ok(value.try_into()?)
}
}
impl TryFrom<Value<Int64>> for u32 {
type Error = host::Error;
fn try_from(value: Value<Int64>) -> host::Result<Self> {
let value: i64 = value.try_into()?;
Ok(value.try_into()?)
}
}
impl TryFrom<Value<UInt64>> for u64 {
type Error = host::Error;
fn try_from(value: Value<UInt64>) -> host::Result<Self> {
let bytes: [u8; std::mem::size_of::<Self>()] = value.bytes.as_slice().try_into()?;
Ok(Self::from_le_bytes(bytes))
}
}
impl TryFrom<Value<Int64>> for ResponseFlags {
type Error = host::Error;
fn try_from(value: Value<Int64>) -> host::Result<Self> {
let value: u64 = value.try_into()?;
Ok(ResponseFlags::from_bits(value).unwrap_or_else(ResponseFlags::empty))
}
}
impl TryFrom<Value<Timestamp>> for i64 {
type Error = host::Error;
fn try_from(value: Value<Timestamp>) -> host::Result<Self> {
let bytes: [u8; std::mem::size_of::<Self>()] = value.bytes.as_slice().try_into()?;
Ok(Self::from_le_bytes(bytes))
}
}
impl TryFrom<Value<Timestamp>> for SystemTime {
type Error = host::Error;
fn try_from(value: Value<Timestamp>) -> host::Result<Self> {
let nanos: i64 = value.try_into()?;
let dur = std::time::Duration::from_nanos(nanos.abs() as u64);
if nanos > 0 {
Ok(SystemTime::UNIX_EPOCH + dur)
} else {
Ok(SystemTime::UNIX_EPOCH - dur)
}
}
}
impl TryFrom<Value<Duration>> for i64 {
type Error = host::Error;
fn try_from(value: Value<Duration>) -> host::Result<Self> {
let bytes: [u8; std::mem::size_of::<Self>()] = value.bytes.as_slice().try_into()?;
Ok(Self::from_le_bytes(bytes))
}
}
impl TryFrom<Value<Duration>> for std::time::Duration {
type Error = host::Error;
fn try_from(value: Value<Duration>) -> host::Result<Self> {
let nanos: i64 = value.try_into()?;
let dur = Self::from_nanos(nanos.abs() as u64);
if nanos > 0 {
Ok(dur)
} else {
Ok(Self::default())
}
}
}
impl TryFrom<Value<Int64>> for TrafficDirection {
type Error = host::Error;
fn try_from(value: Value<Int64>) -> host::Result<Self> {
let value: i32 = value.try_into()?;
Ok(match value {
0 => TrafficDirection::UNSPECIFIED,
1 => TrafficDirection::INBOUND,
2 => TrafficDirection::OUTBOUND,
_ => TrafficDirection::UNSPECIFIED,
})
}
}