use ion_rs;
use ion_rs::IonReader;
use ion_rs::IonType;
use ion_rs::IonWriter;
use ion_rs::ReaderBuilder;
use crate::core::api::API;
use crate::core::decoder_api::Decoder;
use crate::core::encoder_api::Encoder;
use crate::core::typed_api::Typed;
use crate::api::envelope::envelope::Envelope;
const DATA_TYPE: &str = "result";
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ResultDTO {
is_ok: bool,
description: Option<String>,
value: Option<Envelope>,
}
impl API for ResultDTO { }
impl ResultDTO {
pub fn new(
is_ok: bool,
description: Option<&str>,
value: Option<Envelope>
) -> Self {
Self {
is_ok,
description: description.map(|id| id.into()),
value
}
}
pub fn is_ok(&self) -> bool {
self.is_ok
}
pub fn get_description(&self) -> Result<&str, &str> {
self.description
.as_deref()
.map_or_else(|| Err("There is no description provided"), Ok)
}
pub fn into_inner(self) -> Option<Envelope> {
self.value
}
}
impl Encoder for ResultDTO {
fn encode(&self) -> Vec<u8> {
let buffer: Vec<u8> = Vec::new();
let binary_writer_builder = ion_rs::BinaryWriterBuilder::new();
let mut writer = binary_writer_builder.build(buffer.clone()).unwrap();
writer.step_in(IonType::Struct).expect("Error while creating an ion struct");
writer.set_field_name("is_ok");
writer.write_bool(self.is_ok).unwrap();
writer.set_field_name("description");
match &self.description {
Some(description) => writer.write_string(description).unwrap(),
None => writer.write_null(ion_rs::IonType::String).unwrap(),
};
writer.set_field_name("value");
match &self.value {
Some(value) => writer.write_blob(value.encode()).unwrap(),
None => writer.write_null(ion_rs::IonType::Blob).unwrap(),
};
writer.step_out().unwrap();
writer.flush().unwrap();
writer.output().as_slice().into()
}
}
impl Decoder for ResultDTO {
fn decode(data: &[u8]) -> Self {
let mut binary_user_reader = ReaderBuilder::new().build(data).unwrap();
binary_user_reader.next().unwrap();
binary_user_reader.step_in().unwrap();
binary_user_reader.next().unwrap();
let is_ok = binary_user_reader.read_bool().unwrap();
let binding;
binary_user_reader.next().unwrap();
let description = match binary_user_reader.current() {
ion_rs::StreamItem::Value(_) => {
binding = binary_user_reader.read_string().unwrap();
Some(binding.text())
},
ion_rs::StreamItem::Null(_) => {
None
},
ion_rs::StreamItem::Nothing => todo!(),
};
binary_user_reader.next().unwrap();
let value = match binary_user_reader.current() {
ion_rs::StreamItem::Value(_) => {
Some(Envelope::decode(binary_user_reader.read_blob().unwrap().as_slice()))
},
ion_rs::StreamItem::Null(_) => {
None
},
ion_rs::StreamItem::Nothing => todo!(),
};
binary_user_reader.step_out().unwrap();
ResultDTO::new(
is_ok,
description,
value
)
}
}
impl Typed for ResultDTO {
fn get_data_type() -> &'static str {
DATA_TYPE
}
fn get_type(&self) -> &str {
Self::get_data_type()
}
}
#[cfg(test)]
mod tests {
use ion_rs::IonType;
use ion_rs::IonReader;
use ion_rs::ReaderBuilder;
use ion_rs::StreamItem;
use crate::core::decoder_api::Decoder;
use crate::core::encoder_api::Encoder;
use crate::core::typed_api::Typed;
use crate::api::envelope::envelope::Envelope;
use crate::api::result::result::ResultDTO;
#[test]
fn reader_correctly_read_encoded_result() {
const IS_OK: bool = true;
const DESCRIPTION: Option<&str> = Some("DESCRIPTION");
const TENANT_ID: &str = "TENANT_ID";
const ENVELOPE_TYPE: &str = "ENVELOPE_TYPE";
const ENVELOPE_DATA: &[u8] = "ENVELOPE_DATA".as_bytes();
let inner_value: Option<Envelope> = Some(
Envelope::new(
TENANT_ID,
ENVELOPE_TYPE,
ENVELOPE_DATA
)
);
let request_result = ResultDTO::new(
IS_OK,
DESCRIPTION,
inner_value.clone()
);
let mut binary_user_reader = ReaderBuilder::new().build(request_result.encode()).unwrap();
assert_eq!(StreamItem::Value(IonType::Struct), binary_user_reader.next().unwrap());
binary_user_reader.step_in().unwrap();
assert_eq!(StreamItem::Value(IonType::Bool), binary_user_reader.next().unwrap());
assert_eq!("is_ok", binary_user_reader.field_name().unwrap());
assert_eq!(IS_OK, binary_user_reader.read_bool().unwrap());
assert_eq!(StreamItem::Value(IonType::String), binary_user_reader.next().unwrap());
assert_eq!("description", binary_user_reader.field_name().unwrap());
assert_eq!(DESCRIPTION.unwrap(), binary_user_reader.read_string().unwrap().text());
assert_eq!(StreamItem::Value(IonType::Blob), binary_user_reader.next().unwrap());
assert_eq!("value", binary_user_reader.field_name().unwrap());
assert_eq!(inner_value.unwrap(), Envelope::decode(binary_user_reader.read_blob().unwrap().as_slice()));
binary_user_reader.step_out().unwrap();
}
#[test]
fn endec_result() {
const IS_OK: bool = true;
const DESCRIPTION: Option<&str> = Some("DESCRIPTION");
const TENANT_ID: &str = "TENANT_ID";
const ENVELOPE_TYPE: &str = "ENVELOPE_TYPE";
const ENVELOPE_DATA: &[u8] = "ENVELOPE_DATA".as_bytes();
let inner_value: Option<Envelope> = Some(
Envelope::new(
TENANT_ID,
ENVELOPE_TYPE,
ENVELOPE_DATA
)
);
let request_result = ResultDTO::new(
IS_OK,
DESCRIPTION,
inner_value.clone()
);
assert_eq!(request_result, ResultDTO::decode(&request_result.encode()));
}
#[test]
fn test_getting_data_types() {
const IS_OK: bool = true;
const DESCRIPTION: Option<&str> = Some("DESCRIPTION");
const TENANT_ID: &str = "TENANT_ID";
const ENVELOPE_TYPE: &str = "ENVELOPE_TYPE";
const ENVELOPE_DATA: &[u8] = "ENVELOPE_DATA".as_bytes();
let inner_value: Option<Envelope> = Some(
Envelope::new(
TENANT_ID,
ENVELOPE_TYPE,
ENVELOPE_DATA
)
);
let request_result = ResultDTO::new(
IS_OK,
DESCRIPTION,
inner_value.clone()
);
assert_eq!(request_result.get_type(), ResultDTO::get_data_type());
assert_eq!(request_result.get_type(), super::DATA_TYPE);
}
}