1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
use std::convert::TryInto;

#[cfg(feature = "bitvec")]
mod bitvec;
mod dynamic_struct_index_reader;
mod dynamic_struct_index_writer;
mod dynamic_struct_reader;
#[cfg(feature = "ndarray_0_15")]
mod ndarray;
mod pointer;
mod position;
mod static_struct_reader;
mod traits;
mod types;
mod variant_reader;
mod vec_reader;
mod writer;

pub use self::{
	dynamic_struct_index_reader::{
		DynamicStructIndexFieldCount, DynamicStructIndexFieldId, DynamicStructIndexFieldOffset,
		DynamicStructIndexPointer, DynamicStructIndexReader, DynamicStructIndexType,
	},
	dynamic_struct_index_writer::{DynamicStructIndexWriter, DynamicStructIndexWriterI},
	dynamic_struct_reader::DynamicStructReader,
	pointer::Pointer,
	position::Position,
	static_struct_reader::StaticStructReader,
	traits::{PointerType, Read, ReadType, StaticSize, Write, WriteType},
	variant_reader::VariantReader,
	vec_reader::VecReader,
	writer::Writer,
};
pub use buffalo_macro::{Read, Write};

pub fn read<'a, T>(bytes: &'a [u8]) -> T::Output
where
	T: Read<'a>,
{
	let position = bytes.len() - std::mem::size_of::<PointerType>();
	let position = position.try_into().unwrap();
	let position = Position::new(position);
	<Pointer<T>>::read(bytes, position)
}

#[cfg(test)]
#[allow(unused)]
mod test {
	use crate as buffalo;

	#[derive(buffalo::Read, buffalo::Write)]
	#[buffalo(size = "dynamic")]
	struct AddressBook {
		#[buffalo(id = 0, required)]
		pub contacts: Vec<Contact>,
	}

	#[derive(buffalo::Read, buffalo::Write)]
	#[buffalo(size = "dynamic")]
	struct Contact {
		#[buffalo(id = 0, required)]
		pub age: u16,
		#[buffalo(id = 1, required)]
		pub name: String,
		#[buffalo(id = 2, required)]
		pub phone_numbers: Option<Vec<PhoneNumber>>,
	}

	#[derive(buffalo::Read, buffalo::Write)]
	#[buffalo(size = "static", value_size = 8)]
	enum PhoneNumber {
		#[allow(unused)]
		#[buffalo(id = 0)]
		Home(String),
		#[allow(unused)]
		#[buffalo(id = 1)]
		Mobile(String),
	}

	#[test]
	fn test_address_book() {
		let mut writer = buffalo::Writer::new();
		let name = writer.write("John Doe");
		let home = writer.write("1231231234");
		let mobile = writer.write("4564564567");
		let phone_numbers = writer.write(&vec![
			PhoneNumberWriter::Home(home),
			PhoneNumberWriter::Mobile(mobile),
		]);
		let contact = writer.write(&ContactWriter {
			age: 28,
			name,
			phone_numbers: Some(phone_numbers),
		});
		let contacts = writer.write(&vec![contact]);
		let address_book = writer.write(&AddressBookWriter { contacts });
		writer.write(&address_book);
		let bytes = writer.into_bytes();
		let address_book = buffalo::read::<AddressBookReader>(&bytes);
		let contact = address_book.contacts().get(0).unwrap();
		assert_eq!(contact.name(), "John Doe");
		assert_eq!(contact.age(), 28);
		let phone_numbers = contact.phone_numbers();
		let home = phone_numbers.unwrap().get(0).unwrap();
		assert_eq!(home.as_home().unwrap(), "1231231234");
		let mobile = phone_numbers.unwrap().get(1).unwrap();
		assert_eq!(mobile.as_mobile().unwrap(), "4564564567");
	}
}