Skip to content

Instantly share code, notes, and snippets.

@kitlith
Created September 9, 2018 05:44
Show Gist options
  • Save kitlith/feae830bfd48558e487a87becbd39ed1 to your computer and use it in GitHub Desktop.
Save kitlith/feae830bfd48558e487a87becbd39ed1 to your computer and use it in GitHub Desktop.
type-level abstractions for scroll
#![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, Length>(Data, std::marker::PhantomData<Length>);
impl <'a, Data, Length> TryFromCtx<'a> for LengthData<Data, Length>
where Data: TryFromCtx<'a, Size = usize> + 'a,
Length: TryInto<usize, Error = std::num::TryFromIntError>
+ TryFromCtx<'a, Size = usize> + 'a,
scroll::Error: std::convert::From<<Data as scroll::ctx::TryFromCtx<'a>>::Error>
+ std::convert::From<<Length as scroll::ctx::TryFromCtx<'a>>::Error>,
<Data as TryFromCtx<'a>>::Error: std::convert::From<scroll::Error>,
<Length as TryFromCtx<'a>>::Error: std::convert::From<scroll::Error> {
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::<Length>(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<Endian>(String, std::marker::PhantomData<Endian>);
impl<'a, Endian> TryFromCtx<'a> for UTF16<Endian> 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<Length, Endian> From<LengthData<UTF16<Endian>, Length>> for String {
fn from(src: LengthData<UTF16<Endian>, Length>) -> Self {
(src.0).0
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment