use crate::context::*;
use bytes::Bytes;
use std::convert::{TryFrom, TryInto};
use std::fmt::Debug;
#[derive(Debug, PartialEq)]
pub enum Value
{
Double(f64),
Float(f32),
Int32(i32),
Int64(i64),
UInt32(u32),
UInt64(u64),
SInt32(i32),
SInt64(i64),
Fixed32(u32),
Fixed64(u64),
SFixed32(i32),
SFixed64(i64),
Bool(bool),
String(String),
Bytes(Bytes),
Packed(PackedArray),
Message(Box<MessageValue>),
Enum(EnumValue),
Incomplete(Bytes),
Unknown(UnknownValue),
}
#[derive(Debug, PartialEq)]
pub enum PackedArray
{
Double(Vec<f64>),
Float(Vec<f32>),
Int32(Vec<i32>),
Int64(Vec<i64>),
UInt32(Vec<u32>),
UInt64(Vec<u64>),
SInt32(Vec<i32>),
SInt64(Vec<i64>),
Fixed32(Vec<u32>),
Fixed64(Vec<u64>),
SFixed32(Vec<i32>),
SFixed64(Vec<i64>),
Bool(Vec<bool>),
}
#[derive(Debug, PartialEq)]
pub enum UnknownValue
{
Varint(u128),
Fixed64(u64),
VariableLength(Bytes),
Fixed32(u32),
Invalid(Bytes),
}
#[derive(Debug, PartialEq)]
pub struct EnumValue
{
pub enum_ref: EnumRef,
pub value: i64,
}
#[derive(Debug, PartialEq)]
pub struct MessageValue
{
pub msg_ref: MessageRef,
pub fields: Vec<FieldValue>,
pub garbage: Option<Bytes>,
}
#[derive(Debug, PartialEq)]
pub struct FieldValue
{
pub number: u64,
pub value: Value,
}
impl Value
{
fn decode(data: &mut &[u8], vt: &ValueType, ctx: &Context) -> Self
{
let original = *data;
let opt = match vt {
ValueType::Double => {
try_read_8_bytes(data).map(|b| Value::Double(f64::from_le_bytes(b)))
}
ValueType::Float => try_read_4_bytes(data).map(|b| Value::Float(f32::from_le_bytes(b))),
ValueType::Int32 => i32::from_signed_varint(data).map(Value::Int32),
ValueType::Int64 => i64::from_signed_varint(data).map(Value::Int64),
ValueType::UInt32 => u32::from_unsigned_varint(data).map(Value::UInt32),
ValueType::UInt64 => u64::from_unsigned_varint(data).map(Value::UInt64),
ValueType::SInt32 => u32::from_unsigned_varint(data).map(|u| {
let sign = if u % 2 == 0 { 1i32 } else { -1i32 };
let magnitude = (u / 2) as i32;
Value::SInt32(sign * magnitude)
}),
ValueType::SInt64 => u64::from_unsigned_varint(data).map(|u| {
let sign = if u % 2 == 0 { 1i64 } else { -1i64 };
let magnitude = (u / 2) as i64;
Value::SInt64(sign * magnitude)
}),
ValueType::Fixed32 => {
try_read_4_bytes(data).map(|b| Value::Fixed32(u32::from_le_bytes(b)))
}
ValueType::Fixed64 => {
try_read_8_bytes(data).map(|b| Value::Fixed64(u64::from_le_bytes(b)))
}
ValueType::SFixed32 => {
try_read_4_bytes(data).map(|b| Value::SFixed32(i32::from_le_bytes(b)))
}
ValueType::SFixed64 => {
try_read_8_bytes(data).map(|b| Value::SFixed64(i64::from_le_bytes(b)))
}
ValueType::Bool => usize::from_unsigned_varint(data).map(|u| Value::Bool(u != 0)),
ValueType::String => read_string(data).map(Value::String),
ValueType::Bytes => read_bytes(data).map(Value::Bytes),
ValueType::Enum(eref) => i64::from_signed_varint(data).map(|v| {
Value::Enum(EnumValue {
enum_ref: *eref,
value: v,
})
}),
ValueType::Message(mref) => usize::from_unsigned_varint(data).and_then(|length| {
if data.len() < length {
*data = original;
return None;
}
let (consumed, remainder) = data.split_at(length);
*data = remainder;
Some(Value::Message(Box::new(mref.decode(consumed, ctx))))
}),
};
opt.unwrap_or_else(|| {
*data = &[];
Value::Incomplete(Bytes::copy_from_slice(original))
})
}
fn decode_packed(data: &mut &[u8], vt: &ValueType) -> Self
{
let original = *data;
let length = match usize::from_unsigned_varint(data) {
Some(len) => len,
None => {
return return_incomplete(data, original);
}
};
if data.len() < length {
return return_incomplete(data, original);
}
let mut array = &data[..length];
*data = &data[length..];
macro_rules! read_packed {
($variant:ident @ $val:ident = $try_read:expr => $insert:expr ) => {
let mut output = vec![];
loop {
if array.is_empty() {
break Value::Packed(PackedArray::$variant(output));
}
match $try_read {
Some($val) => output.push($insert),
None => return return_incomplete(&mut array, original),
}
}
};
}
match vt {
ValueType::Double => {
read_packed! { Double @ b = try_read_8_bytes(&mut array) => f64::from_le_bytes(b) }
}
ValueType::Float => {
read_packed! { Float @ b = try_read_4_bytes(&mut array) => f32::from_le_bytes(b) }
}
ValueType::Int32 => {
read_packed! { Int32 @ b = i32::from_signed_varint(&mut array) => b }
}
ValueType::Int64 => {
read_packed! { Int64 @ b = i64::from_signed_varint(&mut array) => b }
}
ValueType::UInt32 => {
read_packed! { UInt32 @ b = u32::from_signed_varint(&mut array) => b }
}
ValueType::UInt64 => {
read_packed! { UInt64 @ b = u64::from_signed_varint(&mut array) => b }
}
ValueType::SInt32 => {
read_packed! { SInt32 @ b = u32::from_signed_varint(&mut array) => {
let sign = if b % 2 == 0 { 1i32 } else { -1i32 };
let magnitude = (b / 2) as i32;
sign * magnitude
} }
}
ValueType::SInt64 => {
read_packed! { SInt64 @ b = u64::from_signed_varint(&mut array) => {
let sign = if b % 2 == 0 { 1i64 } else { -1i64 };
let magnitude = (b / 2) as i64;
sign * magnitude
} }
}
ValueType::Fixed32 => {
read_packed! { Fixed32 @ b = try_read_4_bytes(&mut array) => u32::from_le_bytes(b) }
}
ValueType::Fixed64 => {
read_packed! { Fixed64 @ b = try_read_8_bytes(&mut array) => u64::from_le_bytes(b) }
}
ValueType::SFixed32 => {
read_packed! { SFixed32 @ b = try_read_4_bytes(&mut array) => i32::from_le_bytes(b) }
}
ValueType::SFixed64 => {
read_packed! { SFixed64 @ b = try_read_8_bytes(&mut array) => i64::from_le_bytes(b) }
}
ValueType::Bool => {
read_packed! { Bool @ b = u8::from_unsigned_varint(&mut array) => b != 0 }
}
_ => panic!("Non-scalar type was handled as packed"),
}
}
fn decode_unknown(data: &mut &[u8], vt: u8) -> Value
{
let original = *data;
let value =
match vt {
0 => u128::from_unsigned_varint(data).map(UnknownValue::Varint),
1 => try_read_8_bytes(data)
.map(|value| UnknownValue::Fixed64(u64::from_le_bytes(value))),
2 => usize::from_unsigned_varint(data).and_then(|length| {
if length > data.len() {
*data = original;
return None;
}
let (consumed, remainder) = data.split_at(length);
*data = remainder;
Some(UnknownValue::VariableLength(Bytes::copy_from_slice(
consumed,
)))
}),
5 => try_read_4_bytes(data)
.map(|value| UnknownValue::Fixed32(u32::from_le_bytes(value))),
_ => {
let bytes = Bytes::copy_from_slice(data);
*data = &[];
Some(UnknownValue::Invalid(bytes))
}
};
value
.map(Value::Unknown)
.unwrap_or_else(|| Value::Incomplete(Bytes::copy_from_slice(data)))
}
}
fn return_incomplete(data: &mut &[u8], original: &[u8]) -> Value
{
*data = &[];
Value::Incomplete(Bytes::copy_from_slice(original))
}
fn try_read_8_bytes(data: &mut &[u8]) -> Option<[u8; 8]>
{
match (*data).try_into() {
Ok(v) => {
*data = &data[8..];
Some(v)
}
Err(_) => None,
}
}
fn try_read_4_bytes(data: &mut &[u8]) -> Option<[u8; 4]>
{
match (*data).try_into() {
Ok(v) => {
*data = &data[4..];
Some(v)
}
Err(_) => None,
}
}
fn read_string(data: &mut &[u8]) -> Option<String>
{
let original = *data;
let len = usize::from_unsigned_varint(data)?;
if len > data.len() {
*data = original;
return None;
}
let (str_data, remainder) = data.split_at(len);
*data = remainder;
Some(String::from_utf8_lossy(str_data).to_string())
}
fn read_bytes(data: &mut &[u8]) -> Option<Bytes>
{
let original = *data;
let len = usize::from_unsigned_varint(data)?;
if len > data.len() {
*data = original;
return None;
}
let (str_data, remainder) = data.split_at(len);
*data = remainder;
Some(Bytes::copy_from_slice(str_data))
}
impl MessageRef
{
pub fn decode(self, data: &[u8], ctx: &Context) -> MessageValue
{
ctx.resolve_message(self).decode(data, ctx)
}
}
impl MessageInfo
{
pub fn decode(&self, mut data: &[u8], ctx: &Context) -> MessageValue
{
let mut msg = MessageValue {
msg_ref: self.self_ref,
fields: vec![],
garbage: None,
};
loop {
if data.is_empty() {
break;
}
let tag = match u64::from_unsigned_varint(&mut data) {
Some(tag) => tag,
None => {
msg.garbage = Some(Bytes::copy_from_slice(data));
break;
}
};
let number = tag >> 3;
let wire_type = (tag & 0x07) as u8;
let value = match self.fields.get(&number) {
Some(field) => {
if field.multiplicity == Multiplicity::RepeatedPacked {
if wire_type == 2 {
Value::decode_packed(&mut data, &field.field_type)
} else {
Value::decode_unknown(&mut data, wire_type)
}
} else if field.field_type.wire_type() == wire_type {
Value::decode(&mut data, &field.field_type, ctx)
} else {
Value::decode_unknown(&mut data, wire_type)
}
}
_ => Value::decode_unknown(&mut data, wire_type),
};
msg.fields.push(FieldValue { number, value })
}
msg
}
}
trait FromUnsignedVarint: Sized
{
fn from_unsigned_varint(data: &mut &[u8]) -> Option<Self>;
}
impl<T: Default + TryFrom<u64>> FromUnsignedVarint for T
where
T::Error: Debug,
{
fn from_unsigned_varint(data: &mut &[u8]) -> Option<Self>
{
let mut result = 0u64;
let mut idx = 0;
loop {
if idx >= data.len() {
return None;
}
let b = data[idx];
let value = (b & 0x7f) as u64;
result += value << (idx * 7);
idx += 1;
if b & 0x80 == 0 {
break;
}
}
let result = T::try_from(result).expect("Out of range");
*data = &data[idx..];
Some(result)
}
}
trait FromSignedVarint: Sized
{
fn from_signed_varint(data: &mut &[u8]) -> Option<Self>;
}
impl<T: Default + TryFrom<i64>> FromSignedVarint for T
where
T::Error: Debug,
{
fn from_signed_varint(data: &mut &[u8]) -> Option<Self>
{
let mut result = 0i64;
let mut idx = 0;
loop {
if idx >= data.len() {
return None;
}
let b = data[idx];
let value = i64::from(b & 0x7f);
result += value << (idx * 7);
idx += 1;
if b & 0x80 == 0 {
break;
}
}
let result = T::try_from(result).expect("Out of range");
*data = &data[idx..];
Some(result)
}
}