use std::{
fs::{self, File},
io::Write,
path::Path,
};
use crate::tests::*;
use proc_macro2::TokenStream;
use proptest::prelude::*;
use quote::{format_ident, quote};
use uuid::Uuid;
#[derive(Debug)]
pub(crate) struct TCrate {
pub packets: Vec<Packet>,
folder: Uuid,
}
impl Arbitrary for TCrate {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_: ()) -> Self::Strategy {
prop::collection::vec(Packet::arbitrary_with(()), 50..100)
.prop_map(move |packets| TCrate {
packets,
folder: Uuid::new_v4(),
})
.boxed()
}
}
impl TCrate {
pub fn write_all<P: AsRef<Path>>(&self, dest: P) -> std::io::Result<()> {
let crate_path = dest.as_ref().join(self.folder.to_string());
let src_path = crate_path.join("src");
fs::create_dir_all(&src_path)?;
let mut file = File::create(crate_path.join("Cargo.toml"))?;
file.write_all(include_str!("./cargo.toml.test").as_bytes())?;
let mut file = File::create(src_path.join("main.rs"))?;
file.write_all(self.generate().to_string().as_bytes())?;
Ok(())
}
fn generate(&self) -> TokenStream {
let declarations = self
.packets
.iter()
.map(|pkg| pkg.declaration(()))
.collect::<Vec<TokenStream>>();
let mut packets_refs = Vec::new();
let insts = self
.packets
.iter()
.map(|pkg| {
let name = format_ident!("{}", pkg.name);
packets_refs.push(name.clone());
let instance = pkg.instance(());
quote! { let #name = #instance; }
})
.collect::<Vec<TokenStream>>();
quote! {
use brec::*;
#(#declarations)*
brec::generate!();
fn main() {
#(#insts)*
let mut packets = vec![
#(#packets_refs,)*
];
let mut buffer: Vec<u8> = Vec::new();
let mut ctx = ();
for packet in packets.iter_mut() {
packet.write_all(&mut buffer, &mut ctx).expect("Data is written");
}
let mut restored: Vec<Packet> = Vec::new();
let mut inner = std::io::Cursor::new(buffer);
let mut reader: PacketBufReader<std::io::Cursor<Vec<u8>>> = PacketBufReader::new(&mut inner);
loop {
match reader.read(&mut ctx) {
Ok(next) => match next {
NextPacket::Found(packet) => restored.push(packet),
NextPacket::NotFound => {
}
NextPacket::NotEnoughData(_needed) => {
}
NextPacket::NoData => {
break;
}
NextPacket::Skipped => {
}
},
Err(err) => {
panic!("{err}");
}
};
}
println!("Has been read: {} from {}", restored.len(), packets.len());
}
}
}
}