#![feature(try_from)] // for "anything that can be converted into usize" extern crate scroll; // if you're not using the edition 2018 preview use scroll::ctx::TryFromCtx; use std::convert::TryInto; use scroll::Pread; struct LengthData(Data, std::marker::PhantomData); impl <'a, Data, Length> TryFromCtx<'a> for LengthData where Data: TryFromCtx<'a, Size = usize> + 'a, Length: TryInto + TryFromCtx<'a, Size = usize> + 'a, scroll::Error: std::convert::From<>::Error> + std::convert::From<>::Error>, >::Error: std::convert::From, >::Error: std::convert::From { type Error = scroll::Error; type Size = usize; fn try_from_ctx(src: &'a [u8], _ctx: ()) -> Result<(Self, Self::Size), Self::Error> { let read = &mut 0usize; let length: usize = src.gread::(read)?.try_into().unwrap(); Ok((LengthData((&src[*read..*read+length]).pread(0)?, std::marker::PhantomData), *read)) } } // Reads an entire buffer as a UTF-16 string. maybe use StrCtx from scroll in the future? struct UTF16(String, std::marker::PhantomData); impl<'a, Endian> TryFromCtx<'a> for UTF16 where Endian: byteorder::ByteOrder + 'a { type Error = scroll::Error; type Size = usize; fn try_from_ctx(src: &'a [u8], _ctx: ()) -> Result<(Self, Self::Size), Self::Error> { if src.len() % 2 != 0 { return Err(scroll::Error::Custom("Length of utf-16 string is not a multiple of 2!".to_owned())); } let mut data = vec![0u16; src.len()/2]; Endian::read_u16_into(src, &mut data); Ok((UTF16(String::from_utf16_lossy(&data).into(), std::marker::PhantomData), src.len())) } } impl From, Length>> for String { fn from(src: LengthData, Length>) -> Self { (src.0).0 } }