use std::collections::BTreeMap;
use std::convert::TryFrom;
use base64::{decode as decode_base64, encode as encode_base64};
use iso8601::{datetime as parse_datetime, DateTime};
use quick_xml::events::Event;
use quick_xml::{Reader, Writer};
use crate::error::{EncodingError, Error, Fault, ParseError, Result};
use crate::utils::{ReaderExt, WriterExt};
#[derive(Clone, Debug, PartialEq)]
pub enum Value {
Int(i32),
Int64(i64),
Bool(bool),
String(String),
Double(f64),
DateTime(DateTime),
Base64(Vec<u8>),
Struct(BTreeMap<String, Value>),
Array(Vec<Value>),
Nil,
}
impl Value {
pub fn stringify(&self) -> Result<String> {
let mut buf = Vec::new();
let mut writer = Writer::new(&mut buf);
writer.write_start_tag(b"value")?;
match *self {
Value::Int(i) => {
writer.write_safe_tag(b"i4", &i.to_string()[..])?;
}
Value::Int64(i) => {
writer.write_safe_tag(b"i8", &i.to_string()[..])?;
}
Value::Bool(b) => {
writer.write_safe_tag(b"boolean", if b { "1" } else { "0" })?;
}
Value::String(ref s) => {
writer.write_tag(b"string", &s[..])?;
}
Value::Double(d) => {
writer.write_safe_tag(b"double", &d.to_string()[..])?;
}
Value::DateTime(date_time) => {
writer.write_safe_tag(b"dateTime.iso8601", &format!("{}", date_time)[..])?;
}
Value::Base64(ref data) => {
writer.write_safe_tag(b"base64", &encode_base64(data)[..])?;
}
Value::Struct(ref map) => {
writer.write_start_tag(b"struct")?;
for (ref name, ref value) in map {
writer.write_start_tag(b"member")?;
writer.write_tag(b"name", &name[..])?;
writer
.write(&value.stringify()?.as_ref())
.map_err(EncodingError::from)?;
writer.write_end_tag(b"member")?;
}
writer.write_end_tag(b"struct")?;
}
Value::Array(ref array) => {
writer.write_start_tag(b"array")?;
writer.write_start_tag(b"data")?;
for value in array {
writer
.write(&value.stringify()?.as_ref())
.map_err(EncodingError::from)?;
}
writer.write_end_tag(b"data")?;
writer.write_end_tag(b"array")?;
}
Value::Nil => {
writer.write(b"<nil />").map_err(EncodingError::from)?;
}
}
writer.write_end_tag(b"value")?;
Ok(String::from_utf8(buf).map_err(EncodingError::from)?)
}
pub fn as_i32(&self) -> Option<i32> {
match *self {
Value::Int(i) => Some(i),
_ => None,
}
}
pub fn as_i64(&self) -> Option<i64> {
match *self {
Value::Int(i) => Some(i64::from(i)),
Value::Int64(i) => Some(i),
_ => None,
}
}
pub fn as_bool(&self) -> Option<bool> {
match *self {
Value::Bool(b) => Some(b),
_ => None,
}
}
pub fn as_str(&self) -> Option<&str> {
match *self {
Value::String(ref s) => Some(s),
_ => None,
}
}
pub fn as_f64(&self) -> Option<f64> {
match *self {
Value::Double(d) => Some(d),
_ => None,
}
}
pub fn as_datetime(&self) -> Option<DateTime> {
match *self {
Value::DateTime(dt) => Some(dt),
_ => None,
}
}
pub fn as_bytes(&self) -> Option<&[u8]> {
match *self {
Value::Base64(ref data) => Some(data),
_ => None,
}
}
pub fn as_struct(&self) -> Option<&BTreeMap<String, Value>> {
match *self {
Value::Struct(ref map) => Some(map),
_ => None,
}
}
pub fn as_array(&self) -> Option<&[Value]> {
match *self {
Value::Array(ref array) => Some(array),
_ => None,
}
}
}
impl Value {
pub(crate) fn read_response_from_reader(
mut reader: &mut Reader<&[u8]>,
mut buf: &mut Vec<u8>,
) -> Result<Self> {
let ret = match reader.read_event(&mut buf) {
Ok(Event::Start(ref e)) => match e.name() {
b"fault" => {
reader.expect_tag(b"value", &mut buf)?;
let val = Self::read_value_from_reader(&mut reader, &mut buf)?;
reader
.read_to_end(b"fault", &mut buf)
.map_err(ParseError::from)?;
let f = Fault::try_from(val)?;
let e = Error::from(f);
Err(e)
}
b"params" => {
reader.expect_tag(b"param", &mut buf)?;
reader.expect_tag(b"value", &mut buf)?;
let val = Self::read_value_from_reader(&mut reader, &mut buf)?;
reader
.read_to_end(b"param", &mut buf)
.map_err(ParseError::from)?;
reader
.read_to_end(b"params", &mut buf)
.map_err(ParseError::from)?;
Ok(val)
}
_ => {
return Err(ParseError::UnexpectedTag(
String::from_utf8_lossy(e.name()).into(),
"one of fault|params".into(),
)
.into())
}
},
Ok(Event::Eof) => {
return Err(ParseError::UnexpectedEOF("one of fault|params".into()).into())
}
Err(e) => return Err(ParseError::from(e).into()),
_ => return Err(ParseError::UnexpectedEvent("one of fault|params".into()).into()),
};
reader
.read_to_end(b"methodResponse", &mut buf)
.map_err(ParseError::from)?;
ret
}
pub(crate) fn read_value_from_reader(
mut reader: &mut Reader<&[u8]>,
mut buf: &mut Vec<u8>,
) -> Result<Self> {
let mut txt = Vec::new();
let ret: Self = match reader.read_event(&mut buf) {
Ok(Event::Text(e)) => e
.unescape_and_decode(reader)
.map(Value::from)
.map_err(ParseError::from)?,
Ok(Event::End(ref e)) if e.name() == b"value" => return Ok("".to_string().into()),
Ok(Event::Start(ref e)) => match e.name() {
b"i4" | b"int" => Self::read_int_from_reader(e.name(), &mut reader, &mut txt)?,
b"i8" => Self::read_long_from_reader(b"i8", &mut reader, &mut txt)?,
b"boolean" => Self::read_boolean_from_reader(b"boolean", &mut reader, &mut txt)?,
b"string" => Self::read_string_from_reader(b"string", &mut reader, &mut txt)?,
b"double" => Self::read_double_from_reader(b"double", &mut reader, &mut txt)?,
b"dateTime.iso8601" => {
Self::read_datetime_from_reader(b"dateTime.iso8601", &mut reader, &mut txt)?
}
b"base64" => Self::read_base64_from_reader(b"base64", &mut reader, &mut txt)?,
b"struct" => Self::read_struct_from_reader(b"struct", &mut reader, &mut txt)?,
b"array" => Self::read_array_from_reader(b"array", &mut reader, &mut txt)?,
b"nil" => Self::read_nil_from_reader(b"nil", &mut reader, &mut txt)?,
_ => {
return Err(ParseError::UnexpectedTag(
String::from_utf8_lossy(e.name()).into(),
"one of i4|int|i8|boolean|string|double|dateTime.iso8601|base64|struct|array|nil".into(),
).into());
}
},
Ok(Event::Eof) => return Err(ParseError::UnexpectedEOF(
"one of i4|int|i8|boolean|string|double|dateTime.iso8601|base64|struct|array|nil"
.into(),
)
.into()),
Err(e) => return Err(ParseError::from(e).into()),
_ => return Err(ParseError::UnexpectedEvent(
"one of i4|int|i8|boolean|string|double|dateTime.iso8601|base64|struct|array|nil"
.into(),
)
.into()),
};
reader
.read_to_end("value", &mut buf)
.map_err(ParseError::from)?;
Ok(ret)
}
fn read_int_from_reader<K: AsRef<[u8]>>(
end: K,
reader: &mut Reader<&[u8]>,
buf: &mut Vec<u8>,
) -> Result<Self> {
let text = reader.read_text(end, buf).map_err(ParseError::from)?;
Ok(text.parse::<i32>().map_err(ParseError::from)?.into())
}
fn read_long_from_reader<K: AsRef<[u8]>>(
end: K,
reader: &mut Reader<&[u8]>,
buf: &mut Vec<u8>,
) -> Result<Self> {
let text = reader.read_text(end, buf).map_err(ParseError::from)?;
Ok(text.parse::<i64>().map_err(ParseError::from)?.into())
}
fn read_boolean_from_reader<K: AsRef<[u8]>>(
end: K,
reader: &mut Reader<&[u8]>,
buf: &mut Vec<u8>,
) -> Result<Self> {
let val = reader.read_text(end, buf).map_err(ParseError::from)?;
let val = val.as_ref();
match val {
"1" => Ok(Value::Bool(true)),
"0" => Ok(Value::Bool(false)),
_ => Err(ParseError::BooleanDecodeError(val.into()).into()),
}
}
fn read_string_from_reader<K: AsRef<[u8]>>(
end: K,
reader: &mut Reader<&[u8]>,
buf: &mut Vec<u8>,
) -> Result<Self> {
Ok(reader
.read_text(end, buf)
.map(Value::from)
.map_err(ParseError::from)?)
}
fn read_double_from_reader<K: AsRef<[u8]>>(
end: K,
reader: &mut Reader<&[u8]>,
buf: &mut Vec<u8>,
) -> Result<Self> {
let text = reader.read_text(end, buf).map_err(ParseError::from)?;
Ok(text.parse::<f64>().map_err(ParseError::from)?.into())
}
fn read_datetime_from_reader<K: AsRef<[u8]>>(
end: K,
reader: &mut Reader<&[u8]>,
buf: &mut Vec<u8>,
) -> Result<Self> {
let text = reader.read_text(end, buf).map_err(ParseError::from)?;
Ok(parse_datetime(text.as_ref())
.map(Self::from)
.map_err(ParseError::DateTimeDecodeError)?)
}
fn read_struct_from_reader<K: AsRef<[u8]>>(
end: K,
mut reader: &mut Reader<&[u8]>,
mut buf: &mut Vec<u8>,
) -> Result<Self> {
let mut ret: BTreeMap<String, Self> = BTreeMap::new();
loop {
match reader.read_event(&mut buf) {
Ok(Event::End(ref e)) if e.name() == end.as_ref() => {
break;
}
Ok(Event::Start(ref e)) => match e.name() {
b"member" => {
reader.expect_tag(b"name", &mut buf)?;
let name = reader
.read_text(b"name", &mut buf)
.map_err(ParseError::from)?;
reader.expect_tag(b"value", &mut buf)?;
let val = Self::read_value_from_reader(&mut reader, &mut buf)?;
reader
.read_to_end(b"member", &mut buf)
.map_err(ParseError::from)?;
ret.insert(name, val);
}
_ => {
return Err(ParseError::UnexpectedTag(
String::from_utf8_lossy(e.name()).into(),
"member".into(),
)
.into());
}
},
Ok(Event::Eof) => return Err(ParseError::UnexpectedEOF("member".into()).into()),
Err(e) => return Err(ParseError::from(e).into()),
_ => return Err(ParseError::UnexpectedEvent("member".into()).into()),
}
}
Ok(ret.into())
}
fn read_base64_from_reader<K: AsRef<[u8]>>(
end: K,
reader: &mut Reader<&[u8]>,
buf: &mut Vec<u8>,
) -> Result<Self> {
let text = reader.read_text(end, buf).map_err(ParseError::from)?;
Ok(decode_base64(&text).map_err(ParseError::from)?.into())
}
fn read_array_from_reader<K: AsRef<[u8]>>(
end: K,
mut reader: &mut Reader<&[u8]>,
mut buf: &mut Vec<u8>,
) -> Result<Self> {
let mut ret: Vec<Self> = Vec::new();
reader.expect_tag(b"data", buf)?;
loop {
match reader.read_event(&mut buf) {
Ok(Event::End(ref e)) if e.name() == b"data" => {
break;
}
Ok(Event::Start(ref e)) => match e.name() {
b"value" => ret.push(Value::read_value_from_reader(&mut reader, &mut buf)?),
_ => {
return Err(ParseError::UnexpectedTag(
String::from_utf8_lossy(e.name()).into(),
"value".into(),
)
.into());
}
},
Ok(Event::Eof) => return Err(ParseError::UnexpectedEOF("value".into()).into()),
Err(e) => return Err(ParseError::from(e).into()),
_ => return Err(ParseError::UnexpectedEvent("value".into()).into()),
}
}
reader
.read_to_end(end, &mut buf)
.map_err(ParseError::from)?;
Ok(ret.into())
}
fn read_nil_from_reader<K: AsRef<[u8]>>(
end: K,
reader: &mut Reader<&[u8]>,
buf: &mut Vec<u8>,
) -> Result<Self> {
reader.read_to_end(end, buf).map_err(ParseError::from)?;
Ok(Self::Nil)
}
}
impl From<i32> for Value {
fn from(other: i32) -> Self {
Value::Int(other)
}
}
impl From<i64> for Value {
fn from(other: i64) -> Self {
Value::Int64(other)
}
}
impl From<bool> for Value {
fn from(other: bool) -> Self {
Value::Bool(other)
}
}
impl From<String> for Value {
fn from(other: String) -> Self {
Value::String(other)
}
}
impl From<&str> for Value {
fn from(other: &str) -> Self {
Value::String(other.to_string())
}
}
impl From<f64> for Value {
fn from(other: f64) -> Self {
Value::Double(other)
}
}
impl From<DateTime> for Value {
fn from(other: DateTime) -> Self {
Value::DateTime(other)
}
}
impl From<Vec<Value>> for Value {
fn from(other: Vec<Value>) -> Value {
Value::Array(other)
}
}
impl From<BTreeMap<String, Value>> for Value {
fn from(other: BTreeMap<String, Value>) -> Value {
Value::Struct(other)
}
}
impl From<Vec<u8>> for Value {
fn from(other: Vec<u8>) -> Self {
Value::Base64(other)
}
}