check size of items
This commit is contained in:
		@@ -12,11 +12,11 @@ pub const NODE_SIZE: usize = 0x4000;
 | 
				
			|||||||
#[derive(Debug,Clone,Copy,AllVariants,PartialEq,Eq,PartialOrd,Ord)]
 | 
					#[derive(Debug,Clone,Copy,AllVariants,PartialEq,Eq,PartialOrd,Ord)]
 | 
				
			||||||
#[repr(u8)]
 | 
					#[repr(u8)]
 | 
				
			||||||
pub enum ItemType {
 | 
					pub enum ItemType {
 | 
				
			||||||
	Invalid = 0x00,           // invalid
 | 
						Invalid = 0x00,           // invalid, but seems to exist?
 | 
				
			||||||
	Inode = 0x01,             // implemented
 | 
						Inode = 0x01,             // implemented
 | 
				
			||||||
	Ref = 0x0c,               // implemented
 | 
						Ref = 0x0c,               // implemented
 | 
				
			||||||
	ExtRef = 0x0d,
 | 
						ExtRef = 0x0d,
 | 
				
			||||||
	XAttr = 0x18,
 | 
						XAttr = 0x18,             // TODO
 | 
				
			||||||
	VerityDesc = 0x24,
 | 
						VerityDesc = 0x24,
 | 
				
			||||||
	VerityMerkle = 0x25,
 | 
						VerityMerkle = 0x25,
 | 
				
			||||||
	Orphan = 0x30,
 | 
						Orphan = 0x30,
 | 
				
			||||||
@@ -25,12 +25,12 @@ pub enum ItemType {
 | 
				
			|||||||
	Dir = 0x54,               // implemented (better with len feature; allow multiple?)
 | 
						Dir = 0x54,               // implemented (better with len feature; allow multiple?)
 | 
				
			||||||
	DirIndex = 0x60,          // implemented
 | 
						DirIndex = 0x60,          // implemented
 | 
				
			||||||
	ExtentData = 0x6c,        // implemented
 | 
						ExtentData = 0x6c,        // implemented
 | 
				
			||||||
	ExtentCsum = 0x80,
 | 
						ExtentCsum = 0x80,        // TODO
 | 
				
			||||||
	Root = 0x84,              // implemented
 | 
						Root = 0x84,              // implemented
 | 
				
			||||||
	RootBackRef = 0x90,
 | 
						RootBackRef = 0x90,       // implemented
 | 
				
			||||||
	RootRef = 0x9c,
 | 
						RootRef = 0x9c,           // implemented
 | 
				
			||||||
	Extent = 0xa8,            // implemented (with only one version of extra data)
 | 
						Extent = 0xa8,            // implemented (with only one version of extra data!!)
 | 
				
			||||||
	Metadata = 0xa9,          // implemented (with only one version of extra data)
 | 
						Metadata = 0xa9,          // implemented (with only one version of extra data!!)
 | 
				
			||||||
	TreeBlockRef = 0xb0,
 | 
						TreeBlockRef = 0xb0,
 | 
				
			||||||
	ExtentDataRef = 0xb2,
 | 
						ExtentDataRef = 0xb2,
 | 
				
			||||||
	ExtentRefV0 = 0xb4,
 | 
						ExtentRefV0 = 0xb4,
 | 
				
			||||||
@@ -53,7 +53,7 @@ pub enum ItemType {
 | 
				
			|||||||
	UUIDSubvol = 0xfb,        // implemented
 | 
						UUIDSubvol = 0xfb,        // implemented
 | 
				
			||||||
	UUIDReceivedSubvol = 0xfc,
 | 
						UUIDReceivedSubvol = 0xfc,
 | 
				
			||||||
	String = 0xfd,
 | 
						String = 0xfd,
 | 
				
			||||||
	InvalidMax = 0xff,
 | 
						InvalidMax = 0xff,        // invalid
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[allow(unused)]
 | 
					#[allow(unused)]
 | 
				
			||||||
@@ -309,6 +309,8 @@ pub struct RootItem {
 | 
				
			|||||||
	pub otime: Time,
 | 
						pub otime: Time,
 | 
				
			||||||
	pub stime: Time,
 | 
						pub stime: Time,
 | 
				
			||||||
	pub rtime: Time,
 | 
						pub rtime: Time,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data: Vec<u8>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[allow(unused)]
 | 
					#[allow(unused)]
 | 
				
			||||||
@@ -320,7 +322,7 @@ pub struct DirItem {
 | 
				
			|||||||
	pub name_len: u16,
 | 
						pub name_len: u16,
 | 
				
			||||||
	pub dir_type: u8,
 | 
						pub dir_type: u8,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//	#[len = "name_len"]
 | 
						#[len = "name_len"]
 | 
				
			||||||
	pub name: CString,
 | 
						pub name: CString,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -406,7 +408,7 @@ pub struct RefItem {
 | 
				
			|||||||
	pub index: u64,
 | 
						pub index: u64,
 | 
				
			||||||
	pub name_len: u16,
 | 
						pub name_len: u16,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//	#[len = "name_len"]
 | 
						#[len = "name_len"]
 | 
				
			||||||
	pub name: CString,
 | 
						pub name: CString,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -416,6 +418,8 @@ pub struct RootRefItem {
 | 
				
			|||||||
	pub directory: u64,
 | 
						pub directory: u64,
 | 
				
			||||||
	pub index: u64,
 | 
						pub index: u64,
 | 
				
			||||||
	pub name_len: u16,
 | 
						pub name_len: u16,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						#[len = "name_len"]
 | 
				
			||||||
	pub name: CString,
 | 
						pub name: CString,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -571,6 +575,14 @@ impl ParseBin for ItemType {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn parse_check_size<T: ParseBin>(bytes: &[u8]) -> Result<T, ParseError> {
 | 
				
			||||||
 | 
						let (result, real_len) = T::parse_len(bytes)?;
 | 
				
			||||||
 | 
						if real_len != bytes.len() {
 | 
				
			||||||
 | 
							eprintln!("{} parsing incomplete! Parsed {} of {} bytes", std::any::type_name::<T>(), real_len, bytes.len());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						Ok(result)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ParseBin for Node {
 | 
					impl ParseBin for Node {
 | 
				
			||||||
	fn parse_len(bytes: &[u8]) -> Result<(Node, usize), ParseError> {
 | 
						fn parse_len(bytes: &[u8]) -> Result<(Node, usize), ParseError> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -604,45 +616,45 @@ impl ParseBin for Node {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
				let value = match key.key_type {
 | 
									let value = match key.key_type {
 | 
				
			||||||
					ItemType::BlockGroup =>
 | 
										ItemType::BlockGroup =>
 | 
				
			||||||
						Value::BlockGroup(BlockGroupItem::parse(data_slice)?),
 | 
											Value::BlockGroup(parse_check_size(data_slice)?),
 | 
				
			||||||
					ItemType::Metadata => {
 | 
										ItemType::Metadata => {
 | 
				
			||||||
						let item = ExtentItem::parse(data_slice)?;
 | 
											let item: ExtentItem = parse_check_size(data_slice)?;
 | 
				
			||||||
						if item.flags != 2 || item.refs > 1 {
 | 
											if item.flags != 2 || item.refs > 1 {
 | 
				
			||||||
							println!("Metadata item with refs = {}, flags = {}, data = {:x?}", item.refs, item.flags, &data_slice[0x18..]);
 | 
												println!("Metadata item with refs = {}, flags = {}, data = {:x?}", item.refs, item.flags, &data_slice[0x18..]);
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
						Value::Extent(item)
 | 
											Value::Extent(item)
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
					ItemType::Extent =>
 | 
										ItemType::Extent =>
 | 
				
			||||||
						Value::Extent(ExtentItem::parse(data_slice)?),
 | 
											Value::Extent(parse_check_size(data_slice)?),
 | 
				
			||||||
					ItemType::Inode =>
 | 
										ItemType::Inode =>
 | 
				
			||||||
						Value::Inode(InodeItem::parse(data_slice)?),
 | 
											Value::Inode(parse_check_size(data_slice)?),
 | 
				
			||||||
					ItemType::Root =>
 | 
										ItemType::Root =>
 | 
				
			||||||
						Value::Root(RootItem::parse(data_slice)?),
 | 
											Value::Root(parse_check_size(data_slice)?),
 | 
				
			||||||
					ItemType::Dir =>
 | 
										ItemType::Dir =>
 | 
				
			||||||
						Value::Dir(DirItem::parse(data_slice)?),
 | 
											Value::Dir(parse_check_size(data_slice)?),
 | 
				
			||||||
					ItemType::DirIndex =>
 | 
										ItemType::DirIndex =>
 | 
				
			||||||
						Value::DirIndex(DirItem::parse(data_slice)?),
 | 
											Value::DirIndex(parse_check_size(data_slice)?),
 | 
				
			||||||
					ItemType::Chunk =>
 | 
										ItemType::Chunk =>
 | 
				
			||||||
						Value::Chunk(ChunkItem::parse(data_slice)?),
 | 
											Value::Chunk(parse_check_size(data_slice)?),
 | 
				
			||||||
					ItemType::FreeSpaceInfo =>
 | 
										ItemType::FreeSpaceInfo =>
 | 
				
			||||||
						Value::FreeSpaceInfo(FreeSpaceInfoItem::parse(data_slice)?),
 | 
											Value::FreeSpaceInfo(parse_check_size(data_slice)?),
 | 
				
			||||||
					ItemType::FreeSpaceExtent =>
 | 
										ItemType::FreeSpaceExtent =>
 | 
				
			||||||
						Value::FreeSpaceExtent,
 | 
											Value::FreeSpaceExtent,
 | 
				
			||||||
					ItemType::UUIDSubvol =>
 | 
										ItemType::UUIDSubvol =>
 | 
				
			||||||
						Value::UUIDSubvol(UUIDSubvolItem::parse(data_slice)?),
 | 
											Value::UUIDSubvol(parse_check_size(data_slice)?),
 | 
				
			||||||
					ItemType::Dev =>
 | 
										ItemType::Dev =>
 | 
				
			||||||
						Value::Dev(DevItem::parse(data_slice)?),
 | 
											Value::Dev(parse_check_size(data_slice)?),
 | 
				
			||||||
					ItemType::DevExtent =>
 | 
										ItemType::DevExtent =>
 | 
				
			||||||
						Value::DevExtent(DevExtentItem::parse(data_slice)?),
 | 
											Value::DevExtent(parse_check_size(data_slice)?),
 | 
				
			||||||
					ItemType::ExtentData =>
 | 
										ItemType::ExtentData =>
 | 
				
			||||||
						Value::ExtentData(ExtentDataItem::parse(data_slice)?),
 | 
											Value::ExtentData(parse_check_size(data_slice)?),
 | 
				
			||||||
					ItemType::Ref => {
 | 
										ItemType::Ref => {
 | 
				
			||||||
						Value::Ref(RefItem::parse(data_slice)?)
 | 
											Value::Ref(parse_check_size(data_slice)?)
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
					ItemType::RootRef =>
 | 
										ItemType::RootRef =>
 | 
				
			||||||
						Value::RootRef(RootRefItem::parse(data_slice)?),
 | 
											Value::RootRef(parse_check_size(data_slice)?),
 | 
				
			||||||
					ItemType::RootBackRef =>
 | 
										ItemType::RootBackRef =>
 | 
				
			||||||
						Value::RootRef(RootRefItem::parse(data_slice)?),
 | 
											Value::RootRef(parse_check_size(data_slice)?),
 | 
				
			||||||
					_ =>
 | 
										_ =>
 | 
				
			||||||
						Value::Unknown(Vec::from(data_slice)),
 | 
											Value::Unknown(Vec::from(data_slice)),
 | 
				
			||||||
				};
 | 
									};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
use crate::btrfs_structs::{Item, Key, ItemType, Value, ExtentDataBody};
 | 
					use crate::btrfs_structs::{Item, Key, ItemType, Value, ExtentDataBody};
 | 
				
			||||||
use crate::render_common::{DebugRender, Hex, size_name};
 | 
					use crate::render_common::{Hex, size_name};
 | 
				
			||||||
use maud::{Markup, html, DOCTYPE, PreEscaped};
 | 
					use maud::{Markup, html, DOCTYPE, PreEscaped};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
@@ -205,7 +205,7 @@ fn item_value_string(tree_id: u64, item: &Item) -> Markup {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn item_details_string(tree_id: u64, item: &Item) -> Markup {
 | 
					fn item_details_string(_tree_id: u64, item: &Item) -> Markup {
 | 
				
			||||||
	match &item.value {
 | 
						match &item.value {
 | 
				
			||||||
		Value::Inode(inode_item) => {
 | 
							Value::Inode(inode_item) => {
 | 
				
			||||||
			html! { table { tbody {
 | 
								html! { table { tbody {
 | 
				
			||||||
@@ -222,7 +222,7 @@ fn item_details_string(tree_id: u64, item: &Item) -> Markup {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		Value::ExtentData(extent_item) => {
 | 
							Value::ExtentData(extent_item) => {
 | 
				
			||||||
			match &extent_item.data {
 | 
								match &extent_item.data {
 | 
				
			||||||
				ExtentDataBody::Inline(data) => {
 | 
									ExtentDataBody::Inline(_data) => {
 | 
				
			||||||
					html! {} // we really want data as string / hex
 | 
										html! {} // we really want data as string / hex
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				ExtentDataBody::External(ext_extent) => {
 | 
									ExtentDataBody::External(ext_extent) => {
 | 
				
			||||||
@@ -255,7 +255,6 @@ fn item_details_string(tree_id: u64, item: &Item) -> Markup {
 | 
				
			|||||||
			}}}
 | 
								}}}
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		Value::Root(root_item) => {
 | 
							Value::Root(root_item) => {
 | 
				
			||||||
			let inode = &root_item.inode;
 | 
					 | 
				
			||||||
			html! { table { tbody {
 | 
								html! { table { tbody {
 | 
				
			||||||
				tr { td { "root dir id" } td { (format!("{:X}", root_item.root_dirid)) } }
 | 
									tr { td { "root dir id" } td { (format!("{:X}", root_item.root_dirid)) } }
 | 
				
			||||||
				tr { td { "logical address" } td { (format!("{:X}", root_item.bytenr)) } }
 | 
									tr { td { "logical address" } td { (format!("{:X}", root_item.bytenr)) } }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
use std::{
 | 
					use std::{
 | 
				
			||||||
	collections::HashMap, env, fs::{File, OpenOptions}, iter,
 | 
						collections::HashMap, env, fs::{File, OpenOptions}, iter,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use memmap2::{Mmap, MmapOptions};
 | 
					use memmap2::MmapOptions;
 | 
				
			||||||
use rouille::{Request, Response, router};
 | 
					use rouille::{Request, Response, router};
 | 
				
			||||||
use btrfs_explorer::{
 | 
					use btrfs_explorer::{
 | 
				
			||||||
	btrfs_structs::{TreeID, Value::Extent, Value::BlockGroup, NODE_SIZE, ItemType},
 | 
						btrfs_structs::{TreeID, Value::Extent, Value::BlockGroup, NODE_SIZE, ItemType},
 | 
				
			||||||
@@ -20,7 +20,6 @@ fn main() -> Result<(), MainError> {
 | 
				
			|||||||
	let image = unsafe { Mmap::map(&file)? };
 | 
						let image = unsafe { Mmap::map(&file)? };
 | 
				
			||||||
	*/
 | 
						*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const O_DIRECT: i32 = 0x4000;
 | 
					 | 
				
			||||||
	let file = OpenOptions::new().read(true).open(filename)?;
 | 
						let file = OpenOptions::new().read(true).open(filename)?;
 | 
				
			||||||
	let image = unsafe { MmapOptions::new().len(493921239040usize).map(&file)? };
 | 
						let image = unsafe { MmapOptions::new().len(493921239040usize).map(&file)? };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,4 @@
 | 
				
			|||||||
extern crate proc_macro;
 | 
					use quote::{quote, format_ident};
 | 
				
			||||||
extern crate syn;
 | 
					 | 
				
			||||||
#[macro_use]
 | 
					 | 
				
			||||||
extern crate quote;
 | 
					 | 
				
			||||||
extern crate proc_macro2;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use proc_macro2::Span;
 | 
					use proc_macro2::Span;
 | 
				
			||||||
use proc_macro::TokenStream;
 | 
					use proc_macro::TokenStream;
 | 
				
			||||||
use syn::{DeriveInput, Data::Enum, parse_macro_input};
 | 
					use syn::{DeriveInput, Data::Enum, parse_macro_input};
 | 
				
			||||||
@@ -40,7 +35,7 @@ pub fn derive_parse_bin(input: TokenStream) -> TokenStream {
 | 
				
			|||||||
		syn::Data::Struct(struct_item) => {
 | 
							syn::Data::Struct(struct_item) => {
 | 
				
			||||||
			match struct_item.fields {
 | 
								match struct_item.fields {
 | 
				
			||||||
				syn::Fields::Named(fields_named) => {
 | 
									syn::Fields::Named(fields_named) => {
 | 
				
			||||||
					return derive_parse_bin_struct(&name, &fields_named.named);
 | 
										derive_parse_bin_struct(&name, &fields_named.named)
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				syn::Fields::Unnamed(fields_unnamed) => {
 | 
									syn::Fields::Unnamed(fields_unnamed) => {
 | 
				
			||||||
					if fields_unnamed.unnamed.len() != 1 {
 | 
										if fields_unnamed.unnamed.len() != 1 {
 | 
				
			||||||
@@ -48,13 +43,13 @@ pub fn derive_parse_bin(input: TokenStream) -> TokenStream {
 | 
				
			|||||||
					}
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					let inner_type = fields_unnamed.unnamed.into_iter().next().unwrap().ty;
 | 
										let inner_type = fields_unnamed.unnamed.into_iter().next().unwrap().ty;
 | 
				
			||||||
					return derive_parse_bin_alias(name, inner_type);
 | 
										derive_parse_bin_alias(name, inner_type)
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
				_ => panic!("ParseBin on unit structs makes no sense!"),
 | 
									_ => panic!("ParseBin on unit structs makes no sense!"),
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		_ => panic!("ParseBin only works on structs so far!"),
 | 
							_ => panic!("ParseBin only works on structs so far!"),
 | 
				
			||||||
	};
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn derive_parse_bin_alias(name: syn::Ident, ty: syn::Type) -> TokenStream {
 | 
					fn derive_parse_bin_alias(name: syn::Ident, ty: syn::Type) -> TokenStream {
 | 
				
			||||||
@@ -113,39 +108,30 @@ fn derive_parse_bin_struct<'a, T>(name: &syn::Ident, fields: T) -> TokenStream
 | 
				
			|||||||
		if let Some(varname) = veclen {
 | 
							if let Some(varname) = veclen {
 | 
				
			||||||
			let field_name_item = format_ident!("{}_item", field_name);
 | 
								let field_name_item = format_ident!("{}_item", field_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			let field_type_item: &syn::Type = match &field_type {
 | 
								enum FieldType<'a> {
 | 
				
			||||||
				syn::Type::Path(tp) => {
 | 
									Vec(&'a syn::Type),
 | 
				
			||||||
					match tp.path.segments.iter().next() {
 | 
									CString,
 | 
				
			||||||
						Some(single) => {
 | 
					 | 
				
			||||||
							if &single.ident.to_string() == "Vec" {
 | 
					 | 
				
			||||||
								match &single.arguments {
 | 
					 | 
				
			||||||
									syn::PathArguments::AngleBracketed(args) => {
 | 
					 | 
				
			||||||
										match args.args.iter().next() {
 | 
					 | 
				
			||||||
											Some(firstarg) => {
 | 
					 | 
				
			||||||
												match firstarg {
 | 
					 | 
				
			||||||
													syn::GenericArgument::Type(ty) => {
 | 
					 | 
				
			||||||
														Some(ty)
 | 
					 | 
				
			||||||
													},
 | 
					 | 
				
			||||||
													_ => None,
 | 
					 | 
				
			||||||
												}
 | 
					 | 
				
			||||||
											},
 | 
					 | 
				
			||||||
											None => None,
 | 
					 | 
				
			||||||
										}
 | 
					 | 
				
			||||||
									},
 | 
					 | 
				
			||||||
									_ => None,
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								let syn::Type::Path(tp) = &field_type else { panic!() };
 | 
				
			||||||
 | 
								let single = tp.path.segments.iter().next().unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								let field_type = if &single.ident.to_string() ==  "Vec" {
 | 
				
			||||||
 | 
									let syn::PathArguments::AngleBracketed(args) = &single.arguments else { panic!() };
 | 
				
			||||||
 | 
									let firstarg = args.args.iter().next().unwrap();
 | 
				
			||||||
 | 
									let syn::GenericArgument::Type(ty) = firstarg else { panic!() };
 | 
				
			||||||
 | 
									FieldType::Vec(ty)
 | 
				
			||||||
 | 
								} else if &single.ident.to_string() == "CString" {
 | 
				
			||||||
 | 
									FieldType::CString
 | 
				
			||||||
			} else {
 | 
								} else {
 | 
				
			||||||
								None
 | 
									panic!("The len attribute is only allowed on Vec<_> or CString")
 | 
				
			||||||
							}
 | 
								};
 | 
				
			||||||
						},
 | 
					 | 
				
			||||||
						None => None,
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				},
 | 
					 | 
				
			||||||
				_ => None,
 | 
					 | 
				
			||||||
			}.expect("The len attribute is only allowed on type Vec<_>");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			let varname_ident = syn::Ident::new(&varname, Span::call_site());
 | 
								let varname_ident = syn::Ident::new(&varname, Span::call_site());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								match field_type {
 | 
				
			||||||
 | 
									FieldType::Vec(field_type_item) => {
 | 
				
			||||||
					parsing_statements.push(quote!{
 | 
										parsing_statements.push(quote!{
 | 
				
			||||||
						let mut #field_name = Vec::new();
 | 
											let mut #field_name = Vec::new();
 | 
				
			||||||
						for i in 0 .. #varname_ident.0 as usize {
 | 
											for i in 0 .. #varname_ident.0 as usize {
 | 
				
			||||||
@@ -154,8 +140,16 @@ fn derive_parse_bin_struct<'a, T>(name: &syn::Ident, fields: T) -> TokenStream
 | 
				
			|||||||
							#field_name.push(#field_name_item.0);
 | 
												#field_name.push(#field_name_item.0);
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					});
 | 
										});
 | 
				
			||||||
 | 
					 | 
				
			||||||
					combining_expressions.push(quote!(#field_name: #field_name));
 | 
										combining_expressions.push(quote!(#field_name: #field_name));
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									FieldType::CString => {
 | 
				
			||||||
 | 
										parsing_statements.push(quote!{
 | 
				
			||||||
 | 
											let #field_name = CString::parse_len(&bytes[__parse_bin_derive_size .. __parse_bin_derive_size + #varname_ident.0 as usize])?;
 | 
				
			||||||
 | 
											__parse_bin_derive_size += #varname_ident.0 as usize;
 | 
				
			||||||
 | 
										});
 | 
				
			||||||
 | 
										combining_expressions.push(quote!(#field_name: #field_name.0));
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			parsing_statements.push(quote!{
 | 
								parsing_statements.push(quote!{
 | 
				
			||||||
				let #field_name = <#field_type>::parse_len(&bytes[__parse_bin_derive_size..])?;
 | 
									let #field_name = <#field_type>::parse_len(&bytes[__parse_bin_derive_size..])?;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user