#![allow(non_snake_case)]
extern crate byteorder;
#[cfg(doctest)]
extern crate doc_comment;
#[cfg(doctest)]
doc_comment::doctest!("../README.md");
use std::borrow::Borrow;
use std::cell::RefCell;
use std::fmt;
use std::io::Cursor;
use std::io::Seek;
use std::io::SeekFrom;
use std::io::Write;
use std::ops::{Add, Deref, Sub};
use std::rc::Rc;
use byteorder::{BigEndian, LittleEndian, WriteBytesExt};
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Endian {
Big,
Little,
}
#[cfg(target_endian = "little")]
pub const DEFAULT_ENDIAN: Endian = Endian::Little;
#[cfg(target_endian = "big")]
pub const DEFAULT_ENDIAN: Endian = Endian::Big;
enum BindingValue {
Constant(u64),
From(Rc<Binding>, i64),
Unconstrained,
}
impl fmt::Debug for BindingValue {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
BindingValue::Constant(v) => write!(f, "Constant({})", v),
BindingValue::From(ref b, v) => write!(f, "From({:?}, {})", b, v),
BindingValue::Unconstrained => write!(f, "Unconstrained"),
}
}
}
struct Binding {
value: RefCell<BindingValue>,
}
impl fmt::Debug for Binding {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Binding {{ {:?} }}", self.value.borrow())
}
}
trait BindingOffset {
fn get_base_and_offset(&self) -> (Rc<Binding>, i64);
fn offset(&self, other: &Rc<Binding>) -> Option<i64>;
}
impl BindingOffset for Rc<Binding> {
fn get_base_and_offset(&self) -> (Rc<Binding>, i64) {
match *self.value.borrow().deref() {
BindingValue::From(ref b, offset) => {
let (base, base_offset) = b.get_base_and_offset();
(base, base_offset + offset)
}
_ => (self.clone(), 0),
}
}
fn offset(&self, other: &Rc<Binding>) -> Option<i64> {
let (base, offset) = self.get_base_and_offset();
let (other_base, other_offset) = other.get_base_and_offset();
let base_ptr = base.deref() as *const Binding;
let other_base_ptr = other_base.deref() as *const Binding;
if base_ptr == other_base_ptr {
Some(offset - other_offset)
} else {
None
}
}
}
impl Binding {
pub fn unconstrained() -> Binding {
Binding {
value: RefCell::new(BindingValue::Unconstrained),
}
}
pub fn from(other: Rc<Binding>, offset: i64) -> Binding {
Binding {
value: RefCell::new(BindingValue::From(other, offset)),
}
}
pub fn constant(val: u64) -> Binding {
Binding {
value: RefCell::new(BindingValue::Constant(val)),
}
}
pub fn set_const(&self, val: u64) {
let mut v = self.value.borrow_mut();
*v = BindingValue::Constant(val);
}
pub fn set(&self, other: Rc<Binding>) {
let mut v = self.value.borrow_mut();
let (base, offset) = other.get_base_and_offset();
*v = BindingValue::From(base, offset);
}
pub fn value(&self) -> Option<u64> {
match *self.value.borrow() {
BindingValue::Constant(c) => Some(c),
BindingValue::From(ref base, addend) => base.value().map(|v| v + addend as u64),
_ => None,
}
}
}
#[doc(hidden)]
pub struct RealLabel {
binding: Rc<Binding>,
}
impl fmt::Debug for RealLabel {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self.binding)
}
}
pub trait LabelMaker {
fn new() -> Self;
fn from_const(val: u64) -> Self;
fn from_label(other: &Self) -> Self;
fn from_label_offset(other: &Self, offset: i64) -> Self;
}
impl RealLabel {
pub fn value(&self) -> Option<u64> {
self.binding.value()
}
pub fn offset(&self, other: &RealLabel) -> Option<i64> {
self.binding.offset(&other.binding)
}
pub fn set_const(&self, val: u64) {
self.binding.set_const(val);
}
pub fn set(&self, other: &RealLabel) {
self.binding.set(other.binding.clone())
}
}
impl LabelMaker for RealLabel {
fn new() -> RealLabel {
RealLabel {
binding: Rc::new(Binding::unconstrained()),
}
}
fn from_const(val: u64) -> RealLabel {
RealLabel {
binding: Rc::new(Binding::constant(val)),
}
}
fn from_label(other: &RealLabel) -> RealLabel {
RealLabel {
binding: other.binding.clone(),
}
}
fn from_label_offset(other: &RealLabel, offset: i64) -> RealLabel {
RealLabel {
binding: Rc::new(Binding::from(other.binding.clone(), offset)),
}
}
}
#[derive(Clone)]
pub struct Label(pub Rc<RealLabel>);
impl fmt::Debug for Label {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Label {{ {:?} }}", self.0)
}
}
impl Deref for Label {
type Target = RealLabel;
fn deref(&self) -> &RealLabel {
let &Label(ref inner) = self;
inner.deref()
}
}
impl LabelMaker for Label {
fn new() -> Label {
Label(Rc::new(RealLabel::new()))
}
fn from_const(val: u64) -> Label {
Label(Rc::new(RealLabel::from_const(val)))
}
fn from_label(other: &Label) -> Label {
let &Label(ref inner) = other;
Label(Rc::new(RealLabel::from_label(inner.borrow())))
}
fn from_label_offset(other: &Label, offset: i64) -> Label {
let &Label(ref inner) = other;
Label(Rc::new(RealLabel::from_label_offset(
inner.borrow(),
offset,
)))
}
}
impl<'a> Add<i64> for &'a Label {
type Output = Label;
fn add(self, rhs: i64) -> Label {
Label::from_label_offset(self, rhs)
}
}
impl<'a> Sub<i64> for &'a Label {
type Output = Label;
fn sub(self, rhs: i64) -> Label {
Label::from_label_offset(self, -rhs)
}
}
impl<'a> Sub<&'a Label> for &'a Label {
type Output = i64;
fn sub(self, rhs: &'a Label) -> i64 {
self.offset(rhs).unwrap()
}
}
pub trait Num {}
impl Num for u8 {}
impl Num for u16 {}
impl Num for u32 {}
impl Num for u64 {}
pub enum LabelOrNum<T: Num> {
Label(Label),
Num(T),
}
pub trait ToLabelOrNum<'a, T: Num> {
fn to_labelornum(self) -> LabelOrNum<T>;
}
impl<'a, T: Num> ToLabelOrNum<'a, T> for Label {
fn to_labelornum(self) -> LabelOrNum<T> {
LabelOrNum::Label(self)
}
}
impl<'a, T: Num> ToLabelOrNum<'a, T> for &'a Label {
fn to_labelornum(self) -> LabelOrNum<T> {
LabelOrNum::Label(self.clone())
}
}
impl<'a, T: Num> ToLabelOrNum<'a, T> for T {
fn to_labelornum(self) -> LabelOrNum<T> {
LabelOrNum::Num(self)
}
}
#[derive(Clone)]
struct Reference {
label: Label,
offset: u64,
endian: Endian,
size: usize,
}
pub struct Section {
pub endian: Endian,
contents: Cursor<Vec<u8>>,
references: Vec<Reference>,
start: Label,
final_size: Label,
}
impl Section {
pub fn new() -> Section {
Section::with_endian(DEFAULT_ENDIAN)
}
pub fn with_endian(endian: Endian) -> Section {
Section {
endian,
contents: Cursor::new(vec![]),
references: vec![],
start: Label::new(),
final_size: Label::new(),
}
}
pub fn size(&self) -> u64 {
self.contents.get_ref().len() as u64
}
pub fn final_size(&self) -> Label {
self.final_size.clone()
}
pub fn get_contents(self) -> Option<Vec<u8>> {
let mut section = self;
section.final_size.set_const(section.size());
let references: Vec<Reference> = section.references.to_vec();
let mut ok = true;
section = references.iter().cloned().fold(section, |s, r| {
if let Some(val) = r.label.value() {
s.store_label_value(val, r.offset, r.endian, r.size)
} else {
ok = false;
s
}
});
if ok {
Some(section.contents.into_inner())
} else {
None
}
}
pub fn start(&self) -> Label {
self.start.clone()
}
pub fn here(&self) -> Label {
&self.start + self.size() as i64
}
pub fn set_start_const(self, value: u64) -> Section {
self.start.set_const(value);
self
}
pub fn mark(self, label: &Label) -> Section {
label.set(&self.here());
self
}
pub fn append_bytes(mut self, data: &[u8]) -> Section {
self.contents.write_all(data).unwrap();
self
}
pub fn append_section<S: Into<Section>>(mut self, section: S) -> Section {
let Section {
contents,
references,
final_size,
..
} = section.into();
final_size.set_const(contents.get_ref().len() as u64);
let current = self.size();
self.contents.write_all(&contents.into_inner()).unwrap();
self.references.extend(references.into_iter().map(|mut r| {
r.offset += current;
r
}));
self
}
pub fn append_repeated(mut self, byte: u8, count: usize) -> Section {
for _ in 0..count {
self.contents.write_u8(byte).unwrap();
}
self
}
pub fn align(self, alignment: u64) -> Section {
assert!(((alignment - 1) & alignment) == 0);
let new_size = (self.size() + alignment - 1) & !(alignment - 1);
let add = new_size - self.size();
self.append_repeated(0, add as usize)
}
fn store_label_value(mut self, val: u64, offset: u64, endian: Endian, size: usize) -> Section {
let current = self.size();
if offset != current {
self.contents.seek(SeekFrom::Start(offset)).unwrap();
}
match endian {
Endian::Little => match size {
1 => self.L8(val as u8),
2 => self.L16(val as u16),
4 => self.L32(val as u32),
8 => self.L64(val),
_ => unreachable!("Unhandled label size!"),
},
Endian::Big => match size {
1 => self.B8(val as u8),
2 => self.B16(val as u16),
4 => self.B32(val as u32),
8 => self.B64(val),
_ => unreachable!("Unhandled label size!"),
},
}
}
fn append_label(mut self, label: &Label, endian: Endian, size: usize) -> Section {
let current = self.size();
if let Some(val) = label.value() {
self.store_label_value(val, current, endian, size)
} else {
self.references.push(Reference {
label: label.clone(),
offset: current,
endian,
size,
});
self.append_repeated(0, size)
}
}
pub fn D8<'a, T: ToLabelOrNum<'a, u8>>(mut self, byte: T) -> Section {
let endian = self.endian;
match byte.to_labelornum() {
LabelOrNum::Num(n) => {
self.contents.write_u8(n).unwrap();
self
}
LabelOrNum::Label(l) => self.append_label(&l, endian, 1),
}
}
pub fn L8<'a, T: ToLabelOrNum<'a, u8>>(self, byte: T) -> Section {
self.D8(byte)
}
pub fn B8<'a, T: ToLabelOrNum<'a, u8>>(self, byte: T) -> Section {
self.D8(byte)
}
pub fn D16<'a, T: ToLabelOrNum<'a, u16>>(self, word: T) -> Section {
match self.endian {
Endian::Little => self.L16(word),
Endian::Big => self.B16(word),
}
}
pub fn L16<'a, T: ToLabelOrNum<'a, u16>>(mut self, word: T) -> Section {
match word.to_labelornum() {
LabelOrNum::Num(n) => {
self.contents.write_u16::<LittleEndian>(n).unwrap();
self
}
LabelOrNum::Label(l) => self.append_label(&l, Endian::Little, 2),
}
}
pub fn B16<'a, T: ToLabelOrNum<'a, u16>>(mut self, word: T) -> Section {
match word.to_labelornum() {
LabelOrNum::Num(n) => {
self.contents.write_u16::<BigEndian>(n).unwrap();
self
}
LabelOrNum::Label(l) => self.append_label(&l, Endian::Big, 2),
}
}
pub fn D32<'a, T: ToLabelOrNum<'a, u32>>(self, dword: T) -> Section {
match self.endian {
Endian::Little => self.L32(dword),
Endian::Big => self.B32(dword),
}
}
pub fn L32<'a, T: ToLabelOrNum<'a, u32>>(mut self, dword: T) -> Section {
match dword.to_labelornum() {
LabelOrNum::Num(n) => {
self.contents.write_u32::<LittleEndian>(n).unwrap();
self
}
LabelOrNum::Label(l) => self.append_label(&l, Endian::Little, 4),
}
}
pub fn B32<'a, T: ToLabelOrNum<'a, u32>>(mut self, dword: T) -> Section {
match dword.to_labelornum() {
LabelOrNum::Num(n) => {
self.contents.write_u32::<BigEndian>(n).unwrap();
self
}
LabelOrNum::Label(l) => self.append_label(&l, Endian::Big, 4),
}
}
pub fn D64<'a, T: ToLabelOrNum<'a, u64>>(self, qword: T) -> Section {
match self.endian {
Endian::Little => self.L64(qword),
Endian::Big => self.B64(qword),
}
}
pub fn L64<'a, T: ToLabelOrNum<'a, u64>>(mut self, qword: T) -> Section {
match qword.to_labelornum() {
LabelOrNum::Num(n) => {
self.contents.write_u64::<LittleEndian>(n).unwrap();
self
}
LabelOrNum::Label(l) => self.append_label(&l, Endian::Little, 8),
}
}
pub fn B64<'a, T: ToLabelOrNum<'a, u64>>(mut self, qword: T) -> Section {
match qword.to_labelornum() {
LabelOrNum::Num(n) => {
self.contents.write_u64::<BigEndian>(n).unwrap();
self
}
LabelOrNum::Label(l) => self.append_label(&l, Endian::Big, 8),
}
}
}
impl Default for Section {
fn default() -> Self {
Section::new()
}
}
#[test]
fn binding_offset() {
let b_u = Rc::new(Binding::unconstrained());
let b_c = Rc::new(Binding::constant(1));
let b_f1 = Rc::new(Binding::from(b_u.clone(), 0));
assert_eq!(b_f1.offset(&b_u).unwrap(), 0);
assert!(b_f1.offset(&b_c).is_none());
assert!(b_u.offset(&b_c).is_none());
assert!(b_c.offset(&b_u).is_none());
let b_f2 = Rc::new(Binding::from(b_c.clone(), 10));
assert_eq!(b_f2.offset(&b_c).unwrap(), 10);
let b_f3 = Rc::new(Binding::from(b_f1.clone(), 10));
assert_eq!(b_f3.offset(&b_u).unwrap(), 10);
let b_f4 = Rc::new(Binding::from(b_f3.clone(), 10));
assert_eq!(b_f4.offset(&b_u).unwrap(), 20);
let b_f5 = Rc::new(Binding::from(b_u.clone(), 10));
let b_f6 = Rc::new(Binding::from(b_f5.clone(), 10));
assert_eq!(b_f6.offset(&b_f5).unwrap(), 10);
assert_eq!(b_f6.offset(&b_u).unwrap(), 20);
assert_eq!(b_f6.offset(&b_f4).unwrap(), 0);
assert_eq!(b_f6.offset(&b_f3).unwrap(), 10);
assert_eq!(b_f3.offset(&b_f6).unwrap(), -10);
}
#[test]
fn binding_value() {
let b_u = Rc::new(Binding::unconstrained());
let b_c = Rc::new(Binding::constant(1));
let b_f1 = Rc::new(Binding::from(b_u.clone(), 0));
assert!(b_u.value().is_none());
assert_eq!(b_c.value().unwrap(), 1);
assert!(b_f1.value().is_none());
let b_f2 = Rc::new(Binding::from(b_c.clone(), 10));
assert_eq!(b_f2.value().unwrap(), 11);
let b_f3 = Rc::new(Binding::from(b_f1.clone(), 10));
assert!(b_f3.value().is_none());
let b_f4 = Rc::new(Binding::from(b_f3.clone(), 10));
assert!(b_f4.value().is_none());
let b_f5 = Rc::new(Binding::from(b_f2.clone(), 10));
assert_eq!(b_f5.value().unwrap(), 21);
}
#[test]
fn label_unconstrained() {
let l = Label::new();
assert!(l.value().is_none());
}
#[test]
fn label_const() {
let l = Label::from_const(10);
assert_eq!(l.value().unwrap(), 10);
}
#[test]
fn label_label() {
let l1 = Label::new();
let l2 = Label::from_label(&l1);
assert!(l2.value().is_none());
assert_eq!(l2.offset(&l1).unwrap(), 0);
assert_eq!(l1.offset(&l2).unwrap(), 0);
}
#[test]
fn label_label_offset() {
let l1 = Label::new();
let l2 = Label::from_label_offset(&l1, 10);
assert!(l2.value().is_none());
assert_eq!(l2.offset(&l1).unwrap(), 10);
assert_eq!(l1.offset(&l2).unwrap(), -10);
let l3 = Label::from_label_offset(&l2, 10);
assert_eq!(l3.offset(&l2).unwrap(), 10);
assert_eq!(l2.offset(&l3).unwrap(), -10);
assert_eq!(l3.offset(&l1).unwrap(), 20);
assert_eq!(l1.offset(&l3).unwrap(), -20);
let l4 = Label::from_label_offset(&l3, 10);
assert_eq!(l4.offset(&l1).unwrap(), 30);
let l5 = Label::from_label_offset(&l1, 10);
assert_eq!(l5.offset(&l2).unwrap(), 0);
assert_eq!(l5.offset(&l3).unwrap(), -10);
assert_eq!(l3.offset(&l5).unwrap(), 10);
}
#[test]
fn label_offset_unrelated() {
let l1 = Label::new();
let l2 = Label::new();
assert!(l2.offset(&l1).is_none());
assert!(l1.offset(&l2).is_none());
}
#[test]
fn label_add() {
let l1 = Label::new();
let l2 = &l1 + 10;
assert_eq!(l2.offset(&l1).unwrap(), 10);
}
#[test]
fn label_sub() {
let l1 = Label::new();
let l2 = &l1 - 10;
assert_eq!(l2.offset(&l1).unwrap(), -10);
}
#[test]
fn label_sub_label() {
let l1 = Label::new();
let l2 = &l1 + 10;
assert_eq!(&l2 - &l1, 10);
}
#[test]
fn label_set_const() {
let l = Label::new();
let val = 0x12345678;
l.set_const(val);
assert_eq!(l.value().unwrap(), val);
}
#[test]
fn label_set() {
let val = 0x12345678;
let l1 = Label::from_const(val);
let l2 = Label::new();
l2.set(&l1);
assert_eq!(l2.value().unwrap(), val);
let l3 = Label::new();
let l4 = Label::new();
l4.set(&l3);
l3.set_const(val);
assert_eq!(l4.value().unwrap(), val);
}
#[test]
fn section_construction() {
let s = Section::new();
assert_eq!(s.endian, DEFAULT_ENDIAN);
let s2 = Section::with_endian(Endian::Little);
assert_eq!(s2.endian, Endian::Little);
}
#[test]
fn section_append_bytes() {
let s = Section::new();
let b1 = [0, 1, 2, 3, 4];
let b2 = [0xf, 0xe, 0xd, 0xc, 0xb];
assert_eq!(
s.append_bytes(&b1)
.append_bytes(&b2)
.get_contents()
.unwrap(),
&[0, 1, 2, 3, 4, 0xf, 0xe, 0xd, 0xc, 0xb]
);
}
#[test]
fn section_final_size() {
let s = Section::new();
let size = s.final_size();
s.append_repeated(0, 20).get_contents().unwrap();
assert_eq!(size.value().unwrap(), 20);
}
#[test]
fn section_append_section_simple() {
assert_eq!(
Section::new()
.D8(0xab)
.append_section(Section::new().D8(0xcd))
.D8(0xef)
.get_contents()
.unwrap(),
&[0xab, 0xcd, 0xef]
);
}
#[test]
fn section_append_section_labels() {
let mut s = Section::new();
let l1 = Label::from_const(0x12);
let l2 = Label::new();
s = s.D8(0xab);
{
s = s.append_section(Section::new().D8(0xcd).D8(&l1).D8(&l2));
}
s = s.D8(0xef);
l2.set_const(0x34);
assert_eq!(s.get_contents().unwrap(), &[0xab, 0xcd, 0x12, 0x34, 0xef]);
}
#[test]
fn section_append_section_final_size() {
let s = Section::new().D8(0xcd);
assert_eq!(
Section::new()
.D8(0xab)
.D8(s.final_size())
.append_section(s)
.D8(0xef)
.get_contents()
.unwrap(),
&[0xab, 1, 0xcd, 0xef]
);
}
#[test]
fn section_append_repeated() {
let s = Section::new();
assert_eq!(
s.append_repeated(0xff, 5).get_contents().unwrap(),
&[0xff, 0xff, 0xff, 0xff, 0xff]
);
}
#[test]
fn section_align() {
let s = Section::new();
assert_eq!(
s.D8(1).align(8).D8(1).get_contents().unwrap(),
&[1, 0, 0, 0, 0, 0, 0, 0, 1]
);
}
#[test]
fn section_test_8() {
let s = Section::new();
assert_eq!(
s.D8(0x12).L8(0x12).B8(0x12).get_contents().unwrap(),
&[0x12, 0x12, 0x12]
);
}
#[test]
fn section_test_16() {
let s = Section::with_endian(Endian::Little);
assert_eq!(
s.D16(0xABCD)
.L16(0xABCD)
.B16(0xABCD)
.get_contents()
.unwrap(),
&[0xCD, 0xAB, 0xCD, 0xAB, 0xAB, 0xCD]
);
}
#[test]
fn section_test_32() {
let s = Section::with_endian(Endian::Little);
assert_eq!(
s.D32(0xABCD1234)
.L32(0xABCD1234)
.B32(0xABCD1234)
.get_contents()
.unwrap(),
&[0x34, 0x12, 0xCD, 0xAB, 0x34, 0x12, 0xCD, 0xAB, 0xAB, 0xCD, 0x12, 0x34]
);
}
#[test]
fn section_test_64() {
let s = Section::with_endian(Endian::Little);
assert_eq!(
s.D64(0x12345678ABCDEFFF)
.L64(0x12345678ABCDEFFF)
.B64(0x12345678ABCDEFFF)
.get_contents()
.unwrap(),
&[
0xFF, 0xEF, 0xCD, 0xAB, 0x78, 0x56, 0x34, 0x12, 0xFF, 0xEF, 0xCD, 0xAB, 0x78, 0x56,
0x34, 0x12, 0x12, 0x34, 0x56, 0x78, 0xAB, 0xCD, 0xEF, 0xFF
]
);
}
#[test]
fn section_d8l_const_label() {
let l = Label::from_const(10);
let s = Section::with_endian(Endian::Little);
assert_eq!(
s.D8(&l).L8(&l).B8(&l).get_contents().unwrap(),
&[10, 10, 10]
);
}
#[test]
fn section_d16l_const_label() {
let l = Label::from_const(0xABCD);
let s = Section::with_endian(Endian::Little);
assert_eq!(
s.D16(&l).L16(&l).B16(&l).get_contents().unwrap(),
&[0xCD, 0xAB, 0xCD, 0xAB, 0xAB, 0xCD]
);
}
#[test]
fn section_d32l_const_label() {
let l = Label::from_const(0xABCD1234);
let s = Section::with_endian(Endian::Little);
assert_eq!(
s.D32(&l).L32(&l).B32(&l).get_contents().unwrap(),
&[0x34, 0x12, 0xCD, 0xAB, 0x34, 0x12, 0xCD, 0xAB, 0xAB, 0xCD, 0x12, 0x34]
);
}
#[test]
fn section_d64l_const_label() {
let l = Label::from_const(0xABCD12345678F00D);
let s = Section::with_endian(Endian::Little);
assert_eq!(
s.D64(&l).L64(&l).B64(&l).get_contents().unwrap(),
&[
0x0D, 0xF0, 0x78, 0x56, 0x34, 0x12, 0xCD, 0xAB, 0x0D, 0xF0, 0x78, 0x56, 0x34, 0x12,
0xCD, 0xAB, 0xAB, 0xCD, 0x12, 0x34, 0x56, 0x78, 0xF0, 0x0D
]
);
}
#[test]
fn section_get_contents_label_no_value() {
let l = Label::new();
let s = Section::with_endian(Endian::Little);
assert!(s.D8(&l).get_contents().is_none());
}
#[test]
fn section_label_assign_late() {
let l = Label::new();
let mut s = Section::with_endian(Endian::Little);
s = s.D8(&l).L8(&l).B8(&l);
l.set_const(10);
assert_eq!(s.get_contents().unwrap(), &[10, 10, 10]);
}
#[test]
fn section_start_here() {
let mut s = Section::with_endian(Endian::Little);
s = s.append_repeated(0, 10);
let start = s.start();
let mut here = s.here();
assert_eq!(here.offset(&start).unwrap(), 10);
s = s.append_repeated(0, 10);
here = s.here();
assert_eq!(here.offset(&start).unwrap(), 20);
}
#[test]
fn section_start_mark() {
let s = Section::with_endian(Endian::Little);
let start = s.start();
let marked = Label::new();
s.append_repeated(0, 10)
.mark(&marked)
.append_repeated(0, 10);
assert_eq!(marked.offset(&start).unwrap(), 10);
}
#[test]
fn section_additional_methods_trait() {
trait ExtraSection {
fn add_a_thing(self) -> Section;
}
impl ExtraSection for Section {
fn add_a_thing(self) -> Section {
self.B8(0x12).B16(0x3456).B32(0x7890abcd)
}
}
assert_eq!(
Section::new()
.D8(0)
.add_a_thing()
.D8(1)
.get_contents()
.unwrap(),
&[0, 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 1]
);
}
#[test]
fn test_simple_labels() {
let start = Label::new();
let end = Label::new();
let _section = Section::new().mark(&start).mark(&end);
assert_eq!(start.offset(&end), Some(0));
}
#[test]
fn test_set_start_const() {
let l = Label::new();
Section::new()
.set_start_const(0)
.append_repeated(0, 10)
.mark(&l)
.get_contents()
.unwrap();
assert_eq!(l.value().unwrap(), 10);
}
#[test]
fn section_bigendian_defaults() {
let s = Section::with_endian(Endian::Big);
assert_eq!(
s.D8(0x12)
.D16(0x1234)
.D32(0x12345678)
.D64(0x12345678ABCDEFFF)
.get_contents()
.unwrap(),
&[
0x12, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x12, 0x34, 0x56, 0x78, 0xAB, 0xCD, 0xEF,
0xFF
]
);
}