net-core-api 0.5.3

This crate defines core traits and types for the api defined through the net-stalker project. Amazon Ion is used as the serialization format.
Documentation
use ion_rs;

use ion_rs::IonReader;
use ion_rs::IonWriter;

use crate::core::api::API;
use crate::core::decoder_api::Decoder;
use crate::core::encoder_api::Encoder;
use crate::core::typed_api::Typed;

const DATA_TYPE: &str = "envelope";

#[derive(Debug, PartialEq, Eq, Clone)]
pub struct Envelope {
    tenant_id: String,
    envelope_type: String,
    data: Vec<u8>,
}

impl API for Envelope {}

impl Envelope {
    pub fn new(tenant_id: &str, envelope_type: &str, data: &[u8]) -> Self {
        Envelope {
            tenant_id: tenant_id.into(),
            envelope_type: envelope_type.into(),
            data: data.into()
        }
    }

    pub fn get_tenant_id(&self) -> &str {
        &self.tenant_id
    }

    pub fn get_envelope_type(&self) -> &str {
        &self.envelope_type
    }

    pub fn get_data(&self) -> &[u8] {
        &self.data
    }
}

impl Typed for Envelope {
    fn get_type(&self) -> &str {
        DATA_TYPE
    }

    fn get_data_type() -> &'static str where Self : Sized {
        DATA_TYPE
    }
}

impl Encoder for Envelope {
    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(ion_rs::IonType::Struct).expect("Error while creating an ion struct");

        writer.set_field_name("tenant_id");
        writer.write_string(&self.tenant_id).unwrap();

        writer.set_field_name("type");
        writer.write_string(&self.envelope_type).unwrap();

        writer.set_field_name("data");
        writer.write_blob(&self.data).unwrap();

        writer.step_out().unwrap();
        writer.flush().unwrap();

        writer.output().as_slice().to_owned()
    }
}

impl Decoder for Envelope {
    fn decode(data: &[u8]) -> Self {

        let mut binary_user_reader = ion_rs::ReaderBuilder::new().build(data).unwrap();
        binary_user_reader.next().unwrap();
        binary_user_reader.step_in().unwrap();

        binary_user_reader.next().unwrap();
        let binding = binary_user_reader.read_string().unwrap();
        let tenant_id = binding.text();

        binary_user_reader.next().unwrap();
        let binding = binary_user_reader.read_string().unwrap();
        let envelope_type = binding.text();

        binary_user_reader.next().unwrap();
        let binding = binary_user_reader.read_blob().unwrap();
        let data = binding.as_slice();

        Envelope::new(
            tenant_id,
            envelope_type,
            data,
        )
    }
}


#[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 super::Envelope;


    #[test]
    fn reader_correctly_read_encoded_envelope() {
        const TENANT_ID: &str = "TENANT_ID";
        const ENVELOPE_TYPE: &str = "ENVELOPE_TYPE";
        const ENVELOPE_DATA: &[u8] = "ENVELOPE_DATA".as_bytes();
        let envelope = Envelope::new(TENANT_ID, ENVELOPE_TYPE, ENVELOPE_DATA);

        let mut binary_user_reader = ReaderBuilder::new().build(envelope.encode()).unwrap();

        assert_eq!(StreamItem::Value(IonType::Struct), binary_user_reader.next().unwrap());
        binary_user_reader.step_in().unwrap();

        assert_eq!(StreamItem::Value(IonType::String), binary_user_reader.next().unwrap());
        assert_eq!("tenant_id", binary_user_reader.field_name().unwrap());
        assert_eq!(TENANT_ID,  binary_user_reader.read_string().unwrap().text());


        assert_eq!(StreamItem::Value(IonType::String), binary_user_reader.next().unwrap());
        assert_eq!("type", binary_user_reader.field_name().unwrap());
        assert_eq!(ENVELOPE_TYPE, binary_user_reader.read_string().unwrap().text());

        assert_eq!(StreamItem::Value(IonType::Blob), binary_user_reader.next().unwrap());
        assert_eq!("data", binary_user_reader.field_name().unwrap());
        assert_eq!(ENVELOPE_DATA, binary_user_reader.read_blob().unwrap().as_slice());
    }
    
    #[test]
    fn endec_envelope() {
        const TENANT_ID: &str = "TENANT_ID";
        const ENVELOPE_TYPE: &str = "ENVELOPE_TYPE";
        const ENVELOPE_DATA: &[u8] = "ENVELOPE_DATA".as_bytes();
        let envelope = Envelope::new(TENANT_ID, ENVELOPE_TYPE, ENVELOPE_DATA);
        assert_eq!(envelope, Envelope::decode(&envelope.encode()));
    }

    #[test]
    fn test_getting_data_types() {
        const TENANT_ID: &str = "TENANT_ID";
        const ENVELOPE_TYPE: &str = "ENVELOPE_TYPE";
        const ENVELOPE_DATA: &[u8] = "ENVELOPE_DATA".as_bytes();
        let envelope = Envelope::new(TENANT_ID, ENVELOPE_TYPE, ENVELOPE_DATA);
        
        assert_eq!(envelope.get_type(), Envelope::get_data_type());
        assert_eq!(envelope.get_type(), super::DATA_TYPE);
    }
}