<commit_before>use serial::Serial;
use timer::Timer;
use keypad::Keypad;
use gpu::GPU;
use sound::Sound;

static WRAM_SIZE: uint = 0x8000;
static ZRAM_SIZE: uint = 0x7F;

#[deriving(Eq)]
enum DMAType {
	NoDMA,
	GDMA,
	HDMA,
}

pub struct MMU {
	priv wram: ~[u8, ..WRAM_SIZE],
	priv zram: ~[u8, ..ZRAM_SIZE],
	priv hdma: [u8, ..4],
	inte: u8,
	intf: u8,
	serial: Serial,
	timer: Timer,
	keypad: Keypad,
	gpu: GPU,
	sound: Sound,
	priv hdma_status: DMAType,
	priv hdma_src: u16,
	priv hdma_dst: u16,
	priv hdma_len: u8,
	priv wrambank: u8,
	priv mbc: ~::mbc::MBC,
	priv gbmode: ::gbmode::GbMode,
	priv gbspeed: ::gbmode::GbSpeed,
	priv speed_switch_req: bool,
}

impl MMU {
	pub fn new(romname: &str) -> MMU {
		let mut res = MMU {
			wram: ~([0, ..WRAM_SIZE]),
			zram: ~([0, ..ZRAM_SIZE]),
			hdma: [0, ..4],
			wrambank: 1,
			inte: 0,
			intf: 0,
			serial: Serial::new(),
			timer: Timer::new(),
			keypad: Keypad::new(),
			gpu: GPU::new(),
			sound: Sound::new(),
			mbc: ::mbc::get_mbc(&Path::new(romname)),
			gbmode: ::gbmode::Classic,
			gbspeed: ::gbmode::Single,
			speed_switch_req: false,
			hdma_src: 0,
			hdma_dst: 0,
			hdma_status: NoDMA,
			hdma_len: 0xFF,
		};
		if res.rb(0x0143) == 0xC0 {
			fail!("This game does not work in Classic mode");
		}
		res.set_initial();
		return res
	}

	pub fn new_cgb(romname: &str) -> MMU {
		let mut res = MMU {
			wram: ~([0,.. WRAM_SIZE]),
			zram: ~([0,.. ZRAM_SIZE]),
			wrambank: 1,
			hdma: [0,.. 4],
			inte: 0,
			intf: 0,
			serial: Serial::new(),
			timer: Timer::new(),
			keypad: Keypad::new(),
			gpu: GPU::new_cgb(),
			sound: Sound::new(),
			mbc: ::mbc::get_mbc(&Path::new(romname)),
			gbmode: ::gbmode::Color,
			gbspeed: ::gbmode::Single,
			speed_switch_req: false,
			hdma_src: 0,
			hdma_dst: 0,
			hdma_status: NoDMA,
			hdma_len: 0xFF,
		};
		res.determine_mode();
		res.set_initial();
		return res;
	}

	fn set_initial(&mut self) {
		self.wb(0xFF05, 0);
		self.wb(0xFF06, 0);
		self.wb(0xFF07, 0);
		self.wb(0xFF40, 0x91);
		self.wb(0xFF42, 0);
		self.wb(0xFF43, 0);
		self.wb(0xFF45, 0);
		self.wb(0xFF47, 0xFC);
		self.wb(0xFF48, 0xFF);
		self.wb(0xFF49, 0xFF);
		self.wb(0xFF4A, 0);
		self.wb(0xFF4B, 0);
	}

	fn determine_mode(&mut self) {
		let mode = match self.rb(0x0143) & 0x80 {
			0x80 => ::gbmode::Color,
			_ => ::gbmode::ColorAsClassic,
		};
		self.gbmode = mode;
		self.gpu.gbmode = mode;
	}

	pub fn get_mode(&self) -> ::gbmode::GbMode {
		self.gbmode
	}

	pub fn cycle(&mut self, cputicks: uint) -> uint {
		let ticks = cputicks + self.perform_vramdma();

		let gputicks = ticks /
			if self.gbspeed == ::gbmode::Single { 1 }
			else { 2 };

		self.timer.cycle(ticks);
		self.intf |= self.timer.interrupt;
		self.timer.interrupt = 0;

		self.intf |= self.keypad.interrupt;
		self.keypad.interrupt = 0;

		self.gpu.cycle(gputicks);
		self.intf |= self.gpu.interrupt;
		self.gpu.interrupt = 0;

		return gputicks;
	}

	pub fn rb(&self, address: u16) -> u8 {
		match address {
			0x0000 .. 0x7FFF => self.mbc.readrom(address),
			0x8000 .. 0x9FFF => self.gpu.rb(address),
			0xA000 .. 0xBFFF => self.mbc.readram(address),
			0xC000 .. 0xCFFF | 0xE000 .. 0xEFFF => self.wram[address & 0x0FFF],
			0xD000 .. 0xDFFF | 0xF000 .. 0xFDFF => self.wram[(self.wrambank as u16 * 0x1000) | address & 0x0FFF],
			0xFE00 .. 0xFE9F => self.gpu.rb(address),
			0xFF00 => self.keypad.rb(),
			0xFF01 .. 0xFF02 => self.serial.rb(address),
			0xFF04 .. 0xFF07 => self.timer.rb(address),
			0xFF0F => self.intf,
			0xFF10 .. 0xFF3F => self.sound.rb(address),
			0xFF4D => (if self.gbspeed == ::gbmode::Double { 0x80 } else { 0 }) | (if self.speed_switch_req { 1 } else { 0 }),
			0xFF40 .. 0xFF4F => self.gpu.rb(address),
			0xFF51 .. 0xFF55 => self.hdma_read(address),
			0xFF68 .. 0xFF6B => self.gpu.rb(address),
			0xFF70 => self.wrambank,
			0xFF80 .. 0xFFFE => self.zram[address & 0x007F],
			0xFFFF => self.inte,
			_ => { warn!("rb not implemented for {:X}", address); 0 },
		}
	}

	pub fn rw(&self, address: u16) -> u16 {
		(self.rb(address) as u16) | (self.rb(address + 1) as u16 << 8)
	}

	pub fn wb(&mut self, address: u16, value: u8) {
		match address {
			0x0000 .. 0x7FFF => self.mbc.writerom(address, value),
			0x8000 .. 0x9FFF => self.gpu.wb(address, value),
			0xA000 .. 0xBFFF => self.mbc.writeram(address, value),
			0xC000 .. 0xCFFF | 0xE000 .. 0xEFFF => self.wram[address & 0x0FFF] = value,
			0xD000 .. 0xDFFF | 0xF000 .. 0xFDFF => self.wram[(self.wrambank as u16 * 0x1000) | address & 0x0FFF] = value,
			0xFE00 .. 0xFE9F => self.gpu.wb(address, value),
			0xFF00 => self.keypad.wb(value),
			0xFF01 .. 0xFF02 => self.serial.wb(address, value),
			0xFF04 .. 0xFF07 => self.timer.wb(address, value),
			0xFF10 .. 0xFF3F => self.sound.wb(address, value),
			0xFF46 => self.oamdma(value),
			0xFF4D => if value & 0x1 == 0x1 { self.speed_switch_req = true; },
			0xFF40 .. 0xFF4F => self.gpu.wb(address, value),
			0xFF51 .. 0xFF55 => self.hdma_write(address, value),
			0xFF68 .. 0xFF6B => self.gpu.wb(address, value),
			0xFF0F => self.intf = value,
			0xFF70 => { self.wrambank = match value & 0x7 { 0 => 1, n => n }; },
			0xFF80 .. 0xFFFE => self.zram[address & 0x007F] = value,
			0xFFFF => self.inte = value,
			_ => warn!("wb not implemented for {:X}", address),
		};
	}

	pub fn ww(&mut self, address: u16, value: u16) {
		self.wb(address, (value & 0xFF) as u8);
		self.wb(address + 1, (value >> 8) as u8);
	}

	pub fn switch_speed(&mut self) {
		if self.speed_switch_req {
			info!("Switching speed");
			if self.gbspeed == ::gbmode::Double {
				self.gbspeed = ::gbmode::Single;
			} else {
				self.gbspeed = ::gbmode::Double;
			}
		}
		self.speed_switch_req = false;
	}

	fn oamdma(&mut self, value: u8) {
		let base = (value as u16) << 8;
		for i in range(0u16, 0xA0) {
			let b = self.rb(base + i);
			self.wb(0xFE00 + i, b);
		}
	}

	fn hdma_read(&self, a: u16) -> u8 {
		match a {
			0xFF51 .. 0xFF54 => { self.hdma[a - 0xFF51] },
			0xFF55 => self.hdma_len | if self.hdma_status == NoDMA { 0x80 } else { 0 },
			_ => fail!(),
		}
	}

	fn hdma_write(&mut self, a: u16, v: u8) {
		match a {
			0xFF51 => self.hdma[0] = v,
			0xFF52 => self.hdma[1] = v & 0xF0,
			0xFF53 => self.hdma[2] = v & 0x1F,
			0xFF54 => self.hdma[3] = v & 0xF0,
			0xFF55 => {
				if self.hdma_status == HDMA {
					if v & 0x80 == 0 { self.hdma_status = NoDMA; };
					return;
				}
				let src = (self.hdma[0] as u16 << 8) | (self.hdma[1] as u16);
				let dst = (self.hdma[2] as u16 << 8) | (self.hdma[3] as u16) | 0x8000;
				if !(src <= 0x7FF0 || (src >= 0xA000 && src <= 0xDFF0)) { fail!("HDMA transfer with illegal start address {:04X}", src); }

				self.hdma_src = src;
				self.hdma_dst = dst;
				self.hdma_len = v & 0x7F;

				self.hdma_status =
					if v & 0x80 == 0x80 { HDMA }
					else { GDMA };
			},
			_ => fail!(),
		};
	}

	fn perform_vramdma(&mut self) -> uint {
		match self.hdma_status {
			NoDMA => 0,
			GDMA => self.perform_gdma(),
			HDMA => self.perform_hdma(),
		}
	}

	fn perform_hdma(&mut self) -> uint {
		if self.gpu.may_hdma() == false || self.hdma_len == 0xFF {
			return 0;
		}

		self.perform_vramdma_row();

		return 0x10 * (if self.gbspeed == ::gbmode::Single { 4 } else { 2 });
	}

	fn perform_gdma(&mut self) -> uint {
		let len = self.hdma_len as uint + 1;
		for _i in range(0, len) {
			self.perform_vramdma_row();
		}

		self.hdma_status = NoDMA;
		return len * 0x10 * 2;
	}

	fn perform_vramdma_row(&mut self) {
		for j in range(0u16, 0x10) {
			let b: u8 = self.rb(self.hdma_src + j);
			self.gpu.wb(self.hdma_dst + j, b);
		}
		self.hdma_src += 0x10;
		self.hdma_dst += 0x10;
		self.hdma_len -= 1;
	}
}
<commit_msg>Another beautiful fix to the VRAM-DMA<commit_after>use serial::Serial;
use timer::Timer;
use keypad::Keypad;
use gpu::GPU;
use sound::Sound;

static WRAM_SIZE: uint = 0x8000;
static ZRAM_SIZE: uint = 0x7F;

#[deriving(Eq)]
enum DMAType {
	NoDMA,
	GDMA,
	HDMA,
}

pub struct MMU {
	priv wram: ~[u8, ..WRAM_SIZE],
	priv zram: ~[u8, ..ZRAM_SIZE],
	priv hdma: [u8, ..4],
	inte: u8,
	intf: u8,
	serial: Serial,
	timer: Timer,
	keypad: Keypad,
	gpu: GPU,
	sound: Sound,
	priv hdma_status: DMAType,
	priv hdma_src: u16,
	priv hdma_dst: u16,
	priv hdma_len: u8,
	priv wrambank: u8,
	priv mbc: ~::mbc::MBC,
	priv gbmode: ::gbmode::GbMode,
	priv gbspeed: ::gbmode::GbSpeed,
	priv speed_switch_req: bool,
}

impl MMU {
	pub fn new(romname: &str) -> MMU {
		let mut res = MMU {
			wram: ~([0, ..WRAM_SIZE]),
			zram: ~([0, ..ZRAM_SIZE]),
			hdma: [0, ..4],
			wrambank: 1,
			inte: 0,
			intf: 0,
			serial: Serial::new(),
			timer: Timer::new(),
			keypad: Keypad::new(),
			gpu: GPU::new(),
			sound: Sound::new(),
			mbc: ::mbc::get_mbc(&Path::new(romname)),
			gbmode: ::gbmode::Classic,
			gbspeed: ::gbmode::Single,
			speed_switch_req: false,
			hdma_src: 0,
			hdma_dst: 0,
			hdma_status: NoDMA,
			hdma_len: 0xFF,
		};
		if res.rb(0x0143) == 0xC0 {
			fail!("This game does not work in Classic mode");
		}
		res.set_initial();
		return res
	}

	pub fn new_cgb(romname: &str) -> MMU {
		let mut res = MMU {
			wram: ~([0,.. WRAM_SIZE]),
			zram: ~([0,.. ZRAM_SIZE]),
			wrambank: 1,
			hdma: [0,.. 4],
			inte: 0,
			intf: 0,
			serial: Serial::new(),
			timer: Timer::new(),
			keypad: Keypad::new(),
			gpu: GPU::new_cgb(),
			sound: Sound::new(),
			mbc: ::mbc::get_mbc(&Path::new(romname)),
			gbmode: ::gbmode::Color,
			gbspeed: ::gbmode::Single,
			speed_switch_req: false,
			hdma_src: 0,
			hdma_dst: 0,
			hdma_status: NoDMA,
			hdma_len: 0xFF,
		};
		res.determine_mode();
		res.set_initial();
		return res;
	}

	fn set_initial(&mut self) {
		self.wb(0xFF05, 0);
		self.wb(0xFF06, 0);
		self.wb(0xFF07, 0);
		self.wb(0xFF40, 0x91);
		self.wb(0xFF42, 0);
		self.wb(0xFF43, 0);
		self.wb(0xFF45, 0);
		self.wb(0xFF47, 0xFC);
		self.wb(0xFF48, 0xFF);
		self.wb(0xFF49, 0xFF);
		self.wb(0xFF4A, 0);
		self.wb(0xFF4B, 0);
	}

	fn determine_mode(&mut self) {
		let mode = match self.rb(0x0143) & 0x80 {
			0x80 => ::gbmode::Color,
			_ => ::gbmode::ColorAsClassic,
		};
		self.gbmode = mode;
		self.gpu.gbmode = mode;
	}

	pub fn get_mode(&self) -> ::gbmode::GbMode {
		self.gbmode
	}

	pub fn cycle(&mut self, cputicks: uint) -> uint {
		let ticks = cputicks + self.perform_vramdma();

		let gputicks = ticks /
			if self.gbspeed == ::gbmode::Single { 1 }
			else { 2 };

		self.timer.cycle(ticks);
		self.intf |= self.timer.interrupt;
		self.timer.interrupt = 0;

		self.intf |= self.keypad.interrupt;
		self.keypad.interrupt = 0;

		self.gpu.cycle(gputicks);
		self.intf |= self.gpu.interrupt;
		self.gpu.interrupt = 0;

		return gputicks;
	}

	pub fn rb(&self, address: u16) -> u8 {
		match address {
			0x0000 .. 0x7FFF => self.mbc.readrom(address),
			0x8000 .. 0x9FFF => self.gpu.rb(address),
			0xA000 .. 0xBFFF => self.mbc.readram(address),
			0xC000 .. 0xCFFF | 0xE000 .. 0xEFFF => self.wram[address & 0x0FFF],
			0xD000 .. 0xDFFF | 0xF000 .. 0xFDFF => self.wram[(self.wrambank as u16 * 0x1000) | address & 0x0FFF],
			0xFE00 .. 0xFE9F => self.gpu.rb(address),
			0xFF00 => self.keypad.rb(),
			0xFF01 .. 0xFF02 => self.serial.rb(address),
			0xFF04 .. 0xFF07 => self.timer.rb(address),
			0xFF0F => self.intf,
			0xFF10 .. 0xFF3F => self.sound.rb(address),
			0xFF4D => (if self.gbspeed == ::gbmode::Double { 0x80 } else { 0 }) | (if self.speed_switch_req { 1 } else { 0 }),
			0xFF40 .. 0xFF4F => self.gpu.rb(address),
			0xFF51 .. 0xFF55 => self.hdma_read(address),
			0xFF68 .. 0xFF6B => self.gpu.rb(address),
			0xFF70 => self.wrambank,
			0xFF80 .. 0xFFFE => self.zram[address & 0x007F],
			0xFFFF => self.inte,
			_ => { warn!("rb not implemented for {:X}", address); 0 },
		}
	}

	pub fn rw(&self, address: u16) -> u16 {
		(self.rb(address) as u16) | (self.rb(address + 1) as u16 << 8)
	}

	pub fn wb(&mut self, address: u16, value: u8) {
		match address {
			0x0000 .. 0x7FFF => self.mbc.writerom(address, value),
			0x8000 .. 0x9FFF => self.gpu.wb(address, value),
			0xA000 .. 0xBFFF => self.mbc.writeram(address, value),
			0xC000 .. 0xCFFF | 0xE000 .. 0xEFFF => self.wram[address & 0x0FFF] = value,
			0xD000 .. 0xDFFF | 0xF000 .. 0xFDFF => self.wram[(self.wrambank as u16 * 0x1000) | address & 0x0FFF] = value,
			0xFE00 .. 0xFE9F => self.gpu.wb(address, value),
			0xFF00 => self.keypad.wb(value),
			0xFF01 .. 0xFF02 => self.serial.wb(address, value),
			0xFF04 .. 0xFF07 => self.timer.wb(address, value),
			0xFF10 .. 0xFF3F => self.sound.wb(address, value),
			0xFF46 => self.oamdma(value),
			0xFF4D => if value & 0x1 == 0x1 { self.speed_switch_req = true; },
			0xFF40 .. 0xFF4F => self.gpu.wb(address, value),
			0xFF51 .. 0xFF55 => self.hdma_write(address, value),
			0xFF68 .. 0xFF6B => self.gpu.wb(address, value),
			0xFF0F => self.intf = value,
			0xFF70 => { self.wrambank = match value & 0x7 { 0 => 1, n => n }; },
			0xFF80 .. 0xFFFE => self.zram[address & 0x007F] = value,
			0xFFFF => self.inte = value,
			_ => warn!("wb not implemented for {:X}", address),
		};
	}

	pub fn ww(&mut self, address: u16, value: u16) {
		self.wb(address, (value & 0xFF) as u8);
		self.wb(address + 1, (value >> 8) as u8);
	}

	pub fn switch_speed(&mut self) {
		if self.speed_switch_req {
			info!("Switching speed");
			if self.gbspeed == ::gbmode::Double {
				self.gbspeed = ::gbmode::Single;
			} else {
				self.gbspeed = ::gbmode::Double;
			}
		}
		self.speed_switch_req = false;
	}

	fn oamdma(&mut self, value: u8) {
		let base = (value as u16) << 8;
		for i in range(0u16, 0xA0) {
			let b = self.rb(base + i);
			self.wb(0xFE00 + i, b);
		}
	}

	fn hdma_read(&self, a: u16) -> u8 {
		match a {
			0xFF51 .. 0xFF54 => { self.hdma[a - 0xFF51] },
			0xFF55 => self.hdma_len | if self.hdma_status == NoDMA { 0x80 } else { 0 },
			_ => fail!(),
		}
	}

	fn hdma_write(&mut self, a: u16, v: u8) {
		match a {
			0xFF51 => self.hdma[0] = v,
			0xFF52 => self.hdma[1] = v & 0xF0,
			0xFF53 => self.hdma[2] = v & 0x1F,
			0xFF54 => self.hdma[3] = v & 0xF0,
			0xFF55 => {
				if self.hdma_status == HDMA {
					if v & 0x80 == 0 { self.hdma_status = NoDMA; };
					return;
				}
				let src = (self.hdma[0] as u16 << 8) | (self.hdma[1] as u16);
				let dst = (self.hdma[2] as u16 << 8) | (self.hdma[3] as u16) | 0x8000;
				if !(src <= 0x7FF0 || (src >= 0xA000 && src <= 0xDFF0)) { fail!("HDMA transfer with illegal start address {:04X}", src); }

				self.hdma_src = src;
				self.hdma_dst = dst;
				self.hdma_len = v & 0x7F;

				self.hdma_status =
					if v & 0x80 == 0x80 { HDMA }
					else { GDMA };
			},
			_ => fail!(),
		};
	}

	fn perform_vramdma(&mut self) -> uint {
		match self.hdma_status {
			NoDMA => 0,
			GDMA => self.perform_gdma(),
			HDMA => self.perform_hdma(),
		}
	}

	fn perform_hdma(&mut self) -> uint {
		if self.gpu.may_hdma() == false || self.hdma_len == 0xFF {
			return 0;
		}

		self.perform_vramdma_row();
		if self.hdma_len == 0xFF { self.hdma_status = NoDMA; }

		return 0x10 * (if self.gbspeed == ::gbmode::Single { 4 } else { 2 });
	}

	fn perform_gdma(&mut self) -> uint {
		let len = self.hdma_len as uint + 1;
		for _i in range(0, len) {
			self.perform_vramdma_row();
		}

		self.hdma_status = NoDMA;
		return len * 0x10 * 2;
	}

	fn perform_vramdma_row(&mut self) {
		for j in range(0u16, 0x10) {
			let b: u8 = self.rb(self.hdma_src + j);
			self.gpu.wb(self.hdma_dst + j, b);
		}
		self.hdma_src += 0x10;
		self.hdma_dst += 0x10;
		self.hdma_len -= 1;
	}
}
<|endoftext|>


<commit_before>//
// GLSL Mathematics for Rust.
//
// Copyright (c) 2015 The glm-rs authors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::cmp;
use std::num::{ Int, Float, SignedInt, NumCast, cast };
use std::ops::{ Add, Sub, Mul, Div, Rem, Neg };
use rand::Rand;

/// Marker trait for primitive types.
///
/// # Note
///
/// In `glm`, not all Rust primitive number types are used. Only those types
/// that used in GLSL, i.e., `f32`, `f64`, `i32`, `u32` and `bool`, implement
/// this trait.
pub trait Primitive
: Send + Copy + Sized + Clone + PartialOrd + PartialEq + Rand {}

// TODO: must have our own `NumCast` to convert between numbers and `bool`.

impl Primitive for bool {}

/// Additive group.
pub trait Zero: Add<Self, Output = Self> {

    /// Additive identity.
    ///
    /// # Example
    ///
    /// ```
    /// let ling = <glm::IVec3 as glm::Zero>::zero();
    /// let v3 = glm::ivec3(1, 2, 3);
    /// assert_eq!(v3 + ling, v3);
    /// ```
    fn zero() -> Self;

    /// Returns `true` if the receiver equals to `zero()`.
    ///
    /// # Example
    ///
    /// ```
    /// use glm::Zero;  // bring the method to the scope.
    /// assert!(<f32 as glm::Zero>::zero().is_zero());
    /// ```
    fn is_zero(&self) -> bool;
}

/// Multiplicative group.
pub trait One: Mul<Self, Output = Self> {

    /// The multiplication identity.
    ///
    /// # Example
    ///
    /// ```
    /// let yi = <glm::DVec3 as glm::One>::one();
    /// let dv = glm::dvec3(0., 3.14, 6.28);
    /// assert_eq!(dv * yi, dv);
    /// ```
    fn one() -> Self;
}

/// Trait for primitive number type.
pub trait BaseNum
: Primitive
+ Zero
+ One
+ Div<Self, Output = Self>
+ Rem<Self, Output = Self>
+ NumCast
{
    /// Returns the smaller one of two numbers.
    ///
    /// # Example
    ///
    /// ```
    /// use glm::BaseNum;
    /// assert_eq!(1i32.min(2i32), 1i32);
    /// ```
    fn min(self, other: Self) -> Self;

    /// Returns the larger one of two numbers.
    ///
    /// # Example
    ///
    /// ```
    /// use glm::BaseNum;
    /// assert_eq!(1i32.max(2i32), 2i32);
    /// ```
    fn max(self, other: Self) -> Self;
}

/// Trait for numerical types that have negative values.
pub trait Signed
: Neg<Output = Self>
+ Sub<Self, Output = Self>
{
    /// Returns the absolute value of the receiver.
    ///
    /// # Example
    ///
    /// ```
    /// use glm::Signed;
    /// assert_eq!((-1_i32).abs(), 1);
    /// ```
    fn abs(&self) -> Self;

    /// Returns the sign number of the receiver.
    ///
    /// # Example
    ///
    /// ```
    /// use glm::{ Signed, dvec3 };
    /// assert_eq!(dvec3(2.718, 0., -0.).sign(), dvec3(1., 0., 0.));
    /// ```
    fn sign(&self) -> Self;
}

/// Marker trait for primitive integer number type.
pub trait BaseInt: Int + BaseNum {}

/// Trait for comparing types that are derived from float numbers.
///
/// # Note
///
/// Comparing float numbers are tricky. This trait is mainly for convenience.
/// See [this article](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/)
/// for the details of comparing float numbers.
pub trait ApproxEq {

    type BaseType: Float;

    /// Returns `true` if the difference between `x` and `y` is less than
    /// `max_diff`.
    ///
    /// # Note
    ///
    /// The meanings of "difference" and "less than" are up to the
    /// implementations.
    ///
    /// # Example
    ///
    /// use glm::*;
    ///
    /// let v1 = vec2(1000., 2000.);
    /// let v2 = vec2(1010., 1080.);
    /// assert!(v1.is_close_to(&v2, 50.));
    /// assert!(!v1.is_close_to(&v2, 10.));
    fn is_close_to(&self, rhs: &Self, max_diff: Self::BaseType) -> bool;

    /// Returns `true` if the difference between `x` and `y` is less than
    /// [machine epsilon](http://en.wikipedia.org/wiki/Machine_epsilon).
    ///
    /// # Example
    ///
    /// ```
    /// use glm::*;
    ///
    /// let f = 0.1_f32;
    /// let mut sum = 0f32;
    /// for i in 0..10 {
    ///     sum += f;
    /// }
    /// assert_eq!(1.0_f32 == sum, false);
    /// assert_eq!(1f32.is_approx_eq(&sum), true);
    /// ```
    fn is_approx_eq(&self, rhs: &Self) -> bool {
        self.is_close_to(rhs, <Self::BaseType as Float>::epsilon())
    }
}

/// Returns the result of `x.is_close_to(y, max_diff)`.
#[inline(always)]
pub fn is_close_to<T: ApproxEq>(x: &T, y: &T, max_diff: <T as ApproxEq>::BaseType) -> bool {
    x.is_close_to(y, max_diff)
}

/// Returns the result of `x.is_approx_eq(y)`.
#[inline(always)]
pub fn is_approx_eq<T: ApproxEq>(x: &T, y: &T) -> bool {
    x.is_approx_eq(y)
}

#[macro_export]
macro_rules! assert_approx_eq(
    ($left: expr, $right: expr) => ({
        let lhs = &($left);
        let rhs = &($right);
        if !is_approx_eq(lhs, rhs) {
            panic!(
                "assertion failed: left ≈ right` (left: `{:?}`, right: `{:?}`)",
                *lhs, *rhs,
            )
        }
    })
);

#[macro_export]
macro_rules! assert_close_to(
    ($left: expr, $right: expr, $max_diff: expr) => ({
        let lhs = &($left);
        let rhs = &($right);
        let diff = $max_diff;
        if !is_close_to(lhs, rhs, diff) {
            panic!(
                "assertion failed: left ≈ right` (left: `{:?}`, right: `{:?}`, tolerance: `{:?}`)",
                *lhs, *rhs, diff
            )
        }
    })
);

/// Trait for primitive float number type.
pub trait BaseFloat: Float + BaseNum + Signed + ApproxEq<BaseType = Self> {}

macro_rules! impl_basenum(
    ($({ $t: ident, $y: expr, $l: expr }), +) => {
        $(
            impl Primitive for $t {}
            impl One for $t {
                #[inline(always)]
                fn one() -> $t { $y }
            }
            impl Zero for $t {
                #[inline(always)]
                fn zero() -> $t { $l }
                #[inline(always)]
                fn is_zero(&self) -> bool { *self == $l }
            }
        )+
    }
);

impl_basenum! {
    { i32, 1i32, 0i32 },
    { u32, 1u32, 0u32 },
    { f32, 1f32, 0f32 },
    { f64, 1f64, 0f64 }
}

impl Signed for i32 {
    #[inline(always)]
    fn abs(&self) -> i32 {
        SignedInt::abs(*self)
    }
    #[inline(always)]
    fn sign(&self) -> i32 {
        self.signum()
    }
}

macro_rules! impl_int(
    ($($t: ty), +) => {
        $(
            impl BaseNum for $t {
                #[inline(always)]
                fn min(self, other: $t) -> $t {
                    cmp::min(self, other)
                }
                #[inline(always)]
                fn max(self, other: $t) -> $t {
                    cmp::max(self, other)
                }
            }
            impl BaseInt for $t {}
        )+
    }
);
impl_int! { i32, u32 }

macro_rules! impl_flt(
    ($t: ident) => {
        impl Signed for $t {
            #[inline(always)]
            fn abs(&self) -> $t {
                Float::abs(*self)
            }
            #[inline(always)]
            fn sign(&self) -> $t {
                let l = <$t as Zero>::zero();
                if self.is_zero() {
                    l
                } else {
                    self.signum()
                }
            }
        }
        impl ApproxEq for $t {
            type BaseType = $t;
            #[inline(always)]
            fn is_close_to(&self, rhs: &$t, max_diff: $t) -> bool {
                (self - *rhs).abs() <= max_diff
            }
        }
        impl BaseNum for $t {
            #[inline(always)]
            fn min(self, other: $t) -> $t {
                Float::min(self, other)
            }
            #[inline(always)]
            fn max(self, other: $t) -> $t {
                Float::max(self, other)
            }
        }
        impl BaseFloat for $t {}
    }
);

impl_flt! { f32 }
impl_flt! { f64 }

macro_rules! impl_cast_fun {
    ($({$fun: ident, $t: ty}),+) => {
        $(
            pub fn $fun<T: BaseNum>(n: T) -> $t {
                let p: $t = cast(n).unwrap();
                p
            }
        )+
    }
}

impl_cast_fun! {
    { int, i32 }, { uint, u32 },
    { float, f32 }, { double, f64 }
}
<commit_msg>Do not use deprecated feature (Float::epsilon).<commit_after>//
// GLSL Mathematics for Rust.
//
// Copyright (c) 2015 The glm-rs authors.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

use std::cmp;
use std::num::{ Int, Float, SignedInt, NumCast, cast };
use std::{ f32, f64 };
use std::ops::{ Add, Sub, Mul, Div, Rem, Neg };
use rand::Rand;

/// Marker trait for primitive types.
///
/// # Note
///
/// In `glm`, not all Rust primitive number types are used. Only those types
/// that used in GLSL, i.e., `f32`, `f64`, `i32`, `u32` and `bool`, implement
/// this trait.
pub trait Primitive
: Send + Copy + Sized + Clone + PartialOrd + PartialEq + Rand {}

// TODO: must have our own `NumCast` to convert between numbers and `bool`.

impl Primitive for bool {}

/// Additive group.
pub trait Zero: Add<Self, Output = Self> {

    /// Additive identity.
    ///
    /// # Example
    ///
    /// ```
    /// let ling = <glm::IVec3 as glm::Zero>::zero();
    /// let v3 = glm::ivec3(1, 2, 3);
    /// assert_eq!(v3 + ling, v3);
    /// ```
    fn zero() -> Self;

    /// Returns `true` if the receiver equals to `zero()`.
    ///
    /// # Example
    ///
    /// ```
    /// use glm::Zero;  // bring the method to the scope.
    /// assert!(<f32 as glm::Zero>::zero().is_zero());
    /// ```
    fn is_zero(&self) -> bool;
}

/// Multiplicative group.
pub trait One: Mul<Self, Output = Self> {

    /// The multiplication identity.
    ///
    /// # Example
    ///
    /// ```
    /// let yi = <glm::DVec3 as glm::One>::one();
    /// let dv = glm::dvec3(0., 3.14, 6.28);
    /// assert_eq!(dv * yi, dv);
    /// ```
    fn one() -> Self;
}

/// Trait for primitive number type.
pub trait BaseNum
: Primitive
+ Zero
+ One
+ Div<Self, Output = Self>
+ Rem<Self, Output = Self>
+ NumCast
{
    /// Returns the smaller one of two numbers.
    ///
    /// # Example
    ///
    /// ```
    /// use glm::BaseNum;
    /// assert_eq!(1i32.min(2i32), 1i32);
    /// ```
    fn min(self, other: Self) -> Self;

    /// Returns the larger one of two numbers.
    ///
    /// # Example
    ///
    /// ```
    /// use glm::BaseNum;
    /// assert_eq!(1i32.max(2i32), 2i32);
    /// ```
    fn max(self, other: Self) -> Self;
}

/// Trait for numerical types that have negative values.
pub trait Signed
: Neg<Output = Self>
+ Sub<Self, Output = Self>
{
    /// Returns the absolute value of the receiver.
    ///
    /// # Example
    ///
    /// ```
    /// use glm::Signed;
    /// assert_eq!((-1_i32).abs(), 1);
    /// ```
    fn abs(&self) -> Self;

    /// Returns the sign number of the receiver.
    ///
    /// # Example
    ///
    /// ```
    /// use glm::{ Signed, dvec3 };
    /// assert_eq!(dvec3(2.718, 0., -0.).sign(), dvec3(1., 0., 0.));
    /// ```
    fn sign(&self) -> Self;
}

/// Marker trait for primitive integer number type.
pub trait BaseInt: Int + BaseNum {}

/// Trait for comparing types that are derived from float numbers.
///
/// # Note
///
/// Comparing float numbers is tricky. This trait is mainly for convenience.
/// See [this article](https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/)
/// for the details of comparing float numbers.
pub trait ApproxEq {

    type BaseType: BaseFloat;

    /// Returns `true` if the difference between `x` and `y` is less than
    /// `max_diff`.
    ///
    /// # Note
    ///
    /// The meanings of "difference" and "less than" are up to the
    /// implementations.
    ///
    /// # Example
    ///
    /// use glm::*;
    ///
    /// let v1 = vec2(1000., 2000.);
    /// let v2 = vec2(1010., 1080.);
    /// assert!(v1.is_close_to(&v2, 50.));
    /// assert!(!v1.is_close_to(&v2, 10.));
    fn is_close_to(&self, rhs: &Self, max_diff: Self::BaseType) -> bool;

    /// Returns `true` if the difference between `x` and `y` is less than
    /// [machine epsilon](http://en.wikipedia.org/wiki/Machine_epsilon).
    ///
    /// # Example
    ///
    /// ```
    /// use glm::*;
    ///
    /// let f = 0.1_f32;
    /// let mut sum = 0f32;
    /// for i in 0..10 {
    ///     sum += f;
    /// }
    /// assert_eq!(1.0_f32 == sum, false);
    /// assert_eq!(1f32.is_approx_eq(&sum), true);
    /// ```
    fn is_approx_eq(&self, rhs: &Self) -> bool {
        self.is_close_to(rhs, <Self::BaseType as BaseFloat>::epsilon())
    }
}

/// Returns the result of `x.is_close_to(y, max_diff)`.
#[inline(always)]
pub fn is_close_to<T: ApproxEq>(x: &T, y: &T, max_diff: <T as ApproxEq>::BaseType) -> bool {
    x.is_close_to(y, max_diff)
}

/// Returns the result of `x.is_approx_eq(y)`.
#[inline(always)]
pub fn is_approx_eq<T: ApproxEq>(x: &T, y: &T) -> bool {
    x.is_approx_eq(y)
}

#[macro_export]
macro_rules! assert_approx_eq(
    ($left: expr, $right: expr) => ({
        let lhs = &($left);
        let rhs = &($right);
        if !is_approx_eq(lhs, rhs) {
            panic!(
                "assertion failed: left ≈ right` (left: `{:?}`, right: `{:?}`)",
                *lhs, *rhs,
            )
        }
    })
);

#[macro_export]
macro_rules! assert_close_to(
    ($left: expr, $right: expr, $max_diff: expr) => ({
        let lhs = &($left);
        let rhs = &($right);
        let diff = $max_diff;
        if !is_close_to(lhs, rhs, diff) {
            panic!(
                "assertion failed: left ≈ right` (left: `{:?}`, right: `{:?}`, tolerance: `{:?}`)",
                *lhs, *rhs, diff
            )
        }
    })
);

/// Trait for primitive float number type.
pub trait BaseFloat: Float + BaseNum + Signed + ApproxEq<BaseType = Self> {
    fn epsilon() -> Self;
}

macro_rules! impl_basenum(
    ($({ $t: ident, $y: expr, $l: expr }), +) => {
        $(
            impl Primitive for $t {}
            impl One for $t {
                #[inline(always)]
                fn one() -> $t { $y }
            }
            impl Zero for $t {
                #[inline(always)]
                fn zero() -> $t { $l }
                #[inline(always)]
                fn is_zero(&self) -> bool { *self == $l }
            }
        )+
    }
);

impl_basenum! {
    { i32, 1i32, 0i32 },
    { u32, 1u32, 0u32 },
    { f32, 1f32, 0f32 },
    { f64, 1f64, 0f64 }
}

impl Signed for i32 {
    #[inline(always)]
    fn abs(&self) -> i32 {
        SignedInt::abs(*self)
    }
    #[inline(always)]
    fn sign(&self) -> i32 {
        self.signum()
    }
}

macro_rules! impl_int(
    ($($t: ty), +) => {
        $(
            impl BaseNum for $t {
                #[inline(always)]
                fn min(self, other: $t) -> $t {
                    cmp::min(self, other)
                }
                #[inline(always)]
                fn max(self, other: $t) -> $t {
                    cmp::max(self, other)
                }
            }
            impl BaseInt for $t {}
        )+
    }
);
impl_int! { i32, u32 }

macro_rules! impl_flt(
    ($t: ident) => {
        impl Signed for $t {
            #[inline(always)]
            fn abs(&self) -> $t {
                Float::abs(*self)
            }
            #[inline(always)]
            fn sign(&self) -> $t {
                let l = <$t as Zero>::zero();
                if self.is_zero() {
                    l
                } else {
                    self.signum()
                }
            }
        }
        impl ApproxEq for $t {
            type BaseType = $t;
            #[inline(always)]
            fn is_close_to(&self, rhs: &$t, max_diff: $t) -> bool {
                (self - *rhs).abs() <= max_diff
            }
        }
        impl BaseNum for $t {
            #[inline(always)]
            fn min(self, other: $t) -> $t {
                Float::min(self, other)
            }
            #[inline(always)]
            fn max(self, other: $t) -> $t {
                Float::max(self, other)
            }
        }
        impl BaseFloat for $t {
            fn epsilon() -> $t {
                $t::EPSILON
            }
        }
    }
);

impl_flt! { f32 }
impl_flt! { f64 }

macro_rules! impl_cast_fun {
    ($({$fun: ident, $t: ty}),+) => {
        $(
            pub fn $fun<T: BaseNum>(n: T) -> $t {
                let p: $t = cast(n).unwrap();
                p
            }
        )+
    }
}

impl_cast_fun! {
    { int, i32 }, { uint, u32 },
    { float, f32 }, { double, f64 }
}
<|endoftext|>


<commit_before>/// Utilities to write SDP offers and answers using Janus's SDP parsing machinery.

use super::ffi;
use super::glib;
use super::libc;
use super::serde::de::{self, Deserialize, Deserializer, Unexpected, Visitor};
use super::serde::ser::{Serialize, Serializer};
pub use ffi::sdp::janus_sdp_generate_answer as generate_answer;
pub use ffi::sdp::janus_sdp_generate_offer as generate_offer;
use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::ffi::{CStr, CString};
use std::ops::Deref;
use std::str;
use utils::GLibString;

pub type RawSdp = ffi::sdp::janus_sdp;
pub type RawMLine = ffi::sdp::janus_sdp_mline;
pub type RawAttribute = ffi::sdp::janus_sdp_attribute;
pub use ffi::sdp::janus_sdp_mtype as MediaType;
pub use ffi::sdp::janus_sdp_mdirection as MediaDirection;

// courtesy of c_string crate, which also has some other stuff we aren't interested in
// taking in as a dependency here.
macro_rules! c_str {
    ($lit:expr) => {
        unsafe {
            ::std::ffi::CStr::from_ptr(concat!($lit, "\0").as_ptr() as *const ::std::os::raw::c_char)
        }
    }
}

/// SDP attributes which may refer to a specific RTP payload type.
static MEDIA_PAYLOAD_ATTRIBUTES: [&'static str; 3] = ["rtpmap", "fmtp", "rtcp-fb"];

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
/// Available Janus audio codecs. See utils.c.
pub enum AudioCodec {
    Opus,
    Pcmu,
    Pcma,
    G722,
    Isac16,
    Isac32,
}

impl AudioCodec {
    pub fn to_str(&self) -> &'static str {
        self.to_cstr().to_str().unwrap()
    }
    pub fn to_cstr(&self) -> &'static CStr {
        match *self {
            AudioCodec::Opus => c_str!("opus"),
            AudioCodec::Pcmu => c_str!("pcmu"),
            AudioCodec::Pcma => c_str!("pcma"),
            AudioCodec::G722 => c_str!("g722"),
            AudioCodec::Isac16 => c_str!("isac16"),
            AudioCodec::Isac32 => c_str!("isac32"),
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
/// Available Janus video codecs. See utils.c.
pub enum VideoCodec {
    Vp8,
    Vp9,
    H264,
}

impl VideoCodec {
    pub fn to_str(&self) -> &'static str {
        self.to_cstr().to_str().unwrap()
    }
    pub fn to_cstr(&self) -> &'static CStr {
        match *self {
            VideoCodec::Vp8 => c_str!("vp8"),
            VideoCodec::Vp9 => c_str!("vp9"),
            VideoCodec::H264 => c_str!("h264"),
        }
    }
}

#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
/// Parameters controlling SDP offer answering behavior. Used as keys in the parameter list
/// for `janus_sdp_generate_answer`. See sdp-utils.h in the Janus source for more details.
pub enum OfferAnswerParameters {
    /// Used to signal the end of the offer-answer parameter list.
    Done = 0,
    /// Whether to accept or reject audio.
    Audio = 1,
    /// Whether to accept or reject video.
    Video = 2,
    /// Whether to accept or reject data.
    Data = 3,
    /// The MediaDirection for the audio stream.
    AudioDirection = 4,
    /// The MediaDirection for the video stream.
    VideoDirection = 5,
    /// The AudioCodec for the audio stream.
    AudioCodec = 6,
    /// The VideoCodec for the video stream.
    VideoCodec = 7,
    /// The payload type for the audio stream.
    AudioPayloadType = 8,
    /// The payload type for the video stream.
    VideoPayloadType = 9,
    /// Whether to negotiate telephone events.
    AudioDtmf = 10,
    /// Whether to add RTCP-FB attributes.
    VideoRtcpfbDefaults = 11,
    /// Whether to add attributes for H.264 video.
    VideoH264Fmtp = 12,
}

/// An SDP session description.
pub struct Sdp {
    pub ptr: *mut RawSdp, // annoyingly pub because of answer_sdp macro
}

/// An error indicating that we failed to parse an SDP for some reason.
#[derive(Debug, Clone)]
pub struct SdpParseError {
    buffer: Vec<u8>
}

impl Error for SdpParseError {
    fn description(&self) -> &str {
        str::from_utf8(&self.buffer).unwrap_or("SDP parsing failed, but the error was not valid UTF-8 :(")
    }
}

impl fmt::Display for SdpParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(self.description())
    }
}

impl Sdp {
    pub unsafe fn new(ptr: *mut RawSdp) -> Option<Self> {
        ptr.as_mut().map(|p| Self { ptr: p })
    }

    /// Parses an SDP offer string from a client into a structured SDP object.
    pub fn parse(offer: &CStr) -> Result<Self, SdpParseError> {
        let mut error_buffer = Vec::with_capacity(512);
        let error_ptr = error_buffer.as_mut_ptr() as *mut _;
        unsafe {
            let result = ffi::sdp::janus_sdp_parse(offer.as_ptr(), error_ptr, error_buffer.capacity());
            Sdp::new(result).ok_or_else(|| {
                error_buffer.set_len(libc::strlen(error_ptr));
                SdpParseError { buffer: error_buffer }
            })
        }
    }

    /// Gets the payload type number for a codec in this SDP, or None if the codec isn't present.
    pub fn get_payload_type(&self, codec_name: &CStr) -> Option<i32> {
        unsafe {
            match ffi::sdp::janus_sdp_get_codec_pt(self.ptr, codec_name.as_ptr()) {
                err if err < 0 => None,
                n => Some(n),
            }
        }
    }

    /// Rewrites any references from one dynamically assigned payload type in this SDP to another dynamically assigned
    /// payload type.
    pub fn rewrite_payload_type(&mut self, from: i32, to: i32) {
        let from_pt_string = from.to_string();
        let to_pt_string = to.to_string();
        for (_media, m_lines) in self.get_mlines() {
            unsafe {
                for m_line in m_lines {
                    // 1. replace the payload type ID in this media line's payload type list
                    if !glib::g_list_find(m_line.ptypes, from as *const _).is_null() {
                        // payload type data in the list is cast to pointers
                        m_line.ptypes = glib::g_list_remove(m_line.ptypes, from as *const _);
                        m_line.ptypes = glib::g_list_prepend(m_line.ptypes, to as *mut _);
                    }
                    // 2. rewrite the values of attribute lines with the old payload type to have the new payload type
                    let mut attr_node = m_line.attributes;
                    while let Some(node) = attr_node.as_ref() {
                        let next = node.next; // we might delete this link, so grab next now!
                        let data = node.data as *mut RawAttribute;
                        let attr = data.as_ref().expect("Null data in SDP attribute node :(");
                        let name = CStr::from_ptr(attr.name).to_str().expect("Invalid attribute name in SDP :(");
                        if MEDIA_PAYLOAD_ATTRIBUTES.contains(&name) {
                            // each of the attributes with payload types in the values look like "$pt $stuff"
                            // where $stuff is specifying payload-type-specfic options; just rewrite $pt
                            let value = CStr::from_ptr(attr.value).to_str().expect("Invalid attribute value in SDP :(");
                            if value.starts_with(&from_pt_string) {
                                // value string is copied into the attribute
                                let new_val = CString::new(value.replacen(&from_pt_string, &to_pt_string, 1)).unwrap();
                                let new_attr = ffi::sdp::janus_sdp_attribute_create(attr.name, new_val.as_ptr());
                                m_line.attributes = glib::g_list_prepend(m_line.attributes, new_attr as *mut _);
                                m_line.attributes = glib::g_list_delete_link(m_line.attributes, attr_node);
                                ffi::sdp::janus_sdp_attribute_destroy(data);
                            }
                        }
                        attr_node = next;
                    }
                }
            }
        }
    }

    /// Returns a map of all the SDP media lines per SDP media type.
    pub fn get_mlines(&self) -> HashMap<MediaType, Vec<&mut RawMLine>> {
        let mut result = HashMap::new();
        unsafe {
            let mut ml_node = (*self.ptr).m_lines;
            while let Some(node) = ml_node.as_ref() {
                let ml = (node.data as *mut RawMLine).as_mut().expect("Null data in SDP media node :(");
                result.entry(ml.type_).or_insert_with(Vec::new).push(ml);
                ml_node = node.next;
            }
            result
	}
    }

    /// Writes this SDP into an owned C-style string.
    pub fn to_glibstring(&self) -> GLibString {
        unsafe {
            let sdp = ffi::sdp::janus_sdp_write(self.ptr);
            GLibString::from_chars(sdp).expect("Mysterious error writing SDP to string :(")
        }
    }
}

impl Deref for Sdp {
    type Target = RawSdp;

    fn deref(&self) -> &RawSdp {
        unsafe { &*self.ptr }
    }
}

impl Drop for Sdp {
    fn drop(&mut self) {
        unsafe {
            #[cfg(not(feature="refcount"))]
            ffi::sdp::janus_sdp_free(self.ptr);
            #[cfg(feature="refcount")]
            ffi::sdp::janus_sdp_destroy(self.ptr);
        }
    }
}

impl fmt::Debug for Sdp {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Sdp {{ {} }}", self.to_glibstring().to_string_lossy())
    }
}

impl Serialize for Sdp {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
        self.to_glibstring().serialize(serializer)
    }
}

impl<'de> Deserialize<'de> for Sdp {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
        struct SdpVisitor;
        impl<'de> Visitor<'de> for SdpVisitor {
            type Value = Sdp;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("an SDP string")
            }

            fn visit_str<E>(self, value: &str) -> Result<Sdp, E> where E: de::Error {
                if let Ok(cs_value) = CString::new(value) {
                    if let Ok(sdp) = Sdp::parse(&cs_value) {
                        return Ok(sdp)
                    }
                }
                Err(E::invalid_value(Unexpected::Str(value), &self))
            }
        }
        deserializer.deserialize_str(SdpVisitor)
    }
}

unsafe impl Send for Sdp {}

#[macro_export]
/// Given an SDP offer from a client, generates an SDP answer.
/// (This has to be a macro because `generate_answer` is variadic.)
macro_rules! answer_sdp {
    ($sdp:expr $(, $param:expr, $value:expr)* $(,)*) => {{
        unsafe {
            let result = $crate::sdp::generate_answer(
                $sdp.ptr,
                $($param, $value,)*
                $crate::sdp::OfferAnswerParameters::Done
            );
            $crate::sdp::Sdp::new(result).expect("Mysterious error generating SDP answer :(")
        }
    }}
}

#[macro_export]
/// Generates an SDP offer given some parameters.
/// (This has to be a macro because `generate_offer` is variadic.)
macro_rules! offer_sdp {
    ($name:expr, $address:expr $(, $param:expr, $value:expr)* $(,)*) => {{
        unsafe {
            let result = $crate::sdp::generate_offer(
                $name,
                $address,
                $($param, $value,)*
                $crate::sdp::OfferAnswerParameters::Done
            );
            $crate::sdp::Sdp::new(result).expect("Mysterious error generating SDP offer :(")
        }
    }}
}
<commit_msg>Formatting<commit_after>/// Utilities to write SDP offers and answers using Janus's SDP parsing machinery.

use super::ffi;
use super::glib;
use super::libc;
use super::serde::de::{self, Deserialize, Deserializer, Unexpected, Visitor};
use super::serde::ser::{Serialize, Serializer};
pub use ffi::sdp::janus_sdp_generate_answer as generate_answer;
pub use ffi::sdp::janus_sdp_generate_offer as generate_offer;
use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::ffi::{CStr, CString};
use std::ops::Deref;
use std::str;
use utils::GLibString;

pub type RawSdp = ffi::sdp::janus_sdp;
pub type RawMLine = ffi::sdp::janus_sdp_mline;
pub type RawAttribute = ffi::sdp::janus_sdp_attribute;
pub use ffi::sdp::janus_sdp_mtype as MediaType;
pub use ffi::sdp::janus_sdp_mdirection as MediaDirection;

// courtesy of c_string crate, which also has some other stuff we aren't interested in
// taking in as a dependency here.
macro_rules! c_str {
    ($lit:expr) => {
        unsafe {
            ::std::ffi::CStr::from_ptr(concat!($lit, "\0").as_ptr() as *const ::std::os::raw::c_char)
        }
    }
}

/// SDP attributes which may refer to a specific RTP payload type.
static MEDIA_PAYLOAD_ATTRIBUTES: [&'static str; 3] = ["rtpmap", "fmtp", "rtcp-fb"];

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
/// Available Janus audio codecs. See utils.c.
pub enum AudioCodec {
    Opus,
    Pcmu,
    Pcma,
    G722,
    Isac16,
    Isac32,
}

impl AudioCodec {
    pub fn to_str(&self) -> &'static str {
        self.to_cstr().to_str().unwrap()
    }
    pub fn to_cstr(&self) -> &'static CStr {
        match *self {
            AudioCodec::Opus => c_str!("opus"),
            AudioCodec::Pcmu => c_str!("pcmu"),
            AudioCodec::Pcma => c_str!("pcma"),
            AudioCodec::G722 => c_str!("g722"),
            AudioCodec::Isac16 => c_str!("isac16"),
            AudioCodec::Isac32 => c_str!("isac32"),
        }
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
/// Available Janus video codecs. See utils.c.
pub enum VideoCodec {
    Vp8,
    Vp9,
    H264,
}

impl VideoCodec {
    pub fn to_str(&self) -> &'static str {
        self.to_cstr().to_str().unwrap()
    }
    pub fn to_cstr(&self) -> &'static CStr {
        match *self {
            VideoCodec::Vp8 => c_str!("vp8"),
            VideoCodec::Vp9 => c_str!("vp9"),
            VideoCodec::H264 => c_str!("h264"),
        }
    }
}

#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
/// Parameters controlling SDP offer answering behavior. Used as keys in the parameter list
/// for `janus_sdp_generate_answer`. See sdp-utils.h in the Janus source for more details.
pub enum OfferAnswerParameters {
    /// Used to signal the end of the offer-answer parameter list.
    Done = 0,
    /// Whether to accept or reject audio.
    Audio = 1,
    /// Whether to accept or reject video.
    Video = 2,
    /// Whether to accept or reject data.
    Data = 3,
    /// The MediaDirection for the audio stream.
    AudioDirection = 4,
    /// The MediaDirection for the video stream.
    VideoDirection = 5,
    /// The AudioCodec for the audio stream.
    AudioCodec = 6,
    /// The VideoCodec for the video stream.
    VideoCodec = 7,
    /// The payload type for the audio stream.
    AudioPayloadType = 8,
    /// The payload type for the video stream.
    VideoPayloadType = 9,
    /// Whether to negotiate telephone events.
    AudioDtmf = 10,
    /// Whether to add RTCP-FB attributes.
    VideoRtcpfbDefaults = 11,
    /// Whether to add attributes for H.264 video.
    VideoH264Fmtp = 12,
}

/// An SDP session description.
pub struct Sdp {
    pub ptr: *mut RawSdp, // annoyingly pub because of answer_sdp macro
}

/// An error indicating that we failed to parse an SDP for some reason.
#[derive(Debug, Clone)]
pub struct SdpParseError {
    buffer: Vec<u8>
}

impl Error for SdpParseError {
    fn description(&self) -> &str {
        str::from_utf8(&self.buffer).unwrap_or("SDP parsing failed, but the error was not valid UTF-8 :(")
    }
}

impl fmt::Display for SdpParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str(self.description())
    }
}

impl Sdp {
    pub unsafe fn new(ptr: *mut RawSdp) -> Option<Self> {
        ptr.as_mut().map(|p| Self { ptr: p })
    }

    /// Parses an SDP offer string from a client into a structured SDP object.
    pub fn parse(offer: &CStr) -> Result<Self, SdpParseError> {
        let mut error_buffer = Vec::with_capacity(512);
        let error_ptr = error_buffer.as_mut_ptr() as *mut _;
        unsafe {
            let result = ffi::sdp::janus_sdp_parse(offer.as_ptr(), error_ptr, error_buffer.capacity());
            Sdp::new(result).ok_or_else(|| {
                error_buffer.set_len(libc::strlen(error_ptr));
                SdpParseError { buffer: error_buffer }
            })
        }
    }

    /// Gets the payload type number for a codec in this SDP, or None if the codec isn't present.
    pub fn get_payload_type(&self, codec_name: &CStr) -> Option<i32> {
        unsafe {
            match ffi::sdp::janus_sdp_get_codec_pt(self.ptr, codec_name.as_ptr()) {
                err if err < 0 => None,
                n => Some(n),
            }
        }
    }

    /// Rewrites any references from one dynamically assigned payload type in this SDP to another dynamically assigned
    /// payload type.
    pub fn rewrite_payload_type(&mut self, from: i32, to: i32) {
        let from_pt_string = from.to_string();
        let to_pt_string = to.to_string();
        for (_media, m_lines) in self.get_mlines() {
            unsafe {
                for m_line in m_lines {
                    // 1. replace the payload type ID in this media line's payload type list
                    if !glib::g_list_find(m_line.ptypes, from as *const _).is_null() {
                        // payload type data in the list is cast to pointers
                        m_line.ptypes = glib::g_list_remove(m_line.ptypes, from as *const _);
                        m_line.ptypes = glib::g_list_prepend(m_line.ptypes, to as *mut _);
                    }
                    // 2. rewrite the values of attribute lines with the old payload type to have the new payload type
                    let mut attr_node = m_line.attributes;
                    while let Some(node) = attr_node.as_ref() {
                        let next = node.next; // we might delete this link, so grab next now!
                        let data = node.data as *mut RawAttribute;
                        let attr = data.as_ref().expect("Null data in SDP attribute node :(");
                        let name = CStr::from_ptr(attr.name).to_str().expect("Invalid attribute name in SDP :(");
                        if MEDIA_PAYLOAD_ATTRIBUTES.contains(&name) {
                            // each of the attributes with payload types in the values look like "$pt $stuff"
                            // where $stuff is specifying payload-type-specfic options; just rewrite $pt
                            let value = CStr::from_ptr(attr.value).to_str().expect("Invalid attribute value in SDP :(");
                            if value.starts_with(&from_pt_string) {
                                // value string is copied into the attribute
                                let new_val = CString::new(value.replacen(&from_pt_string, &to_pt_string, 1)).unwrap();
                                let new_attr = ffi::sdp::janus_sdp_attribute_create(attr.name, new_val.as_ptr());
                                m_line.attributes = glib::g_list_prepend(m_line.attributes, new_attr as *mut _);
                                m_line.attributes = glib::g_list_delete_link(m_line.attributes, attr_node);
                                ffi::sdp::janus_sdp_attribute_destroy(data);
                            }
                        }
                        attr_node = next;
                    }
                }
            }
        }
    }

    /// Returns a map of all the SDP media lines per SDP media type.
    pub fn get_mlines(&self) -> HashMap<MediaType, Vec<&mut RawMLine>> {
        let mut result = HashMap::new();
        unsafe {
            let mut ml_node = (*self.ptr).m_lines;
            while let Some(node) = ml_node.as_ref() {
                let ml = (node.data as *mut RawMLine).as_mut().expect("Null data in SDP media node :(");
                result.entry(ml.type_).or_insert_with(Vec::new).push(ml);
                ml_node = node.next;
            }
            result
        }
    }

    /// Writes this SDP into an owned C-style string.
    pub fn to_glibstring(&self) -> GLibString {
        unsafe {
            let sdp = ffi::sdp::janus_sdp_write(self.ptr);
            GLibString::from_chars(sdp).expect("Mysterious error writing SDP to string :(")
        }
    }
}

impl Deref for Sdp {
    type Target = RawSdp;

    fn deref(&self) -> &RawSdp {
        unsafe { &*self.ptr }
    }
}

impl Drop for Sdp {
    fn drop(&mut self) {
        unsafe {
            #[cfg(not(feature="refcount"))]
            ffi::sdp::janus_sdp_free(self.ptr);
            #[cfg(feature="refcount")]
            ffi::sdp::janus_sdp_destroy(self.ptr);
        }
    }
}

impl fmt::Debug for Sdp {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Sdp {{ {} }}", self.to_glibstring().to_string_lossy())
    }
}

impl Serialize for Sdp {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
        self.to_glibstring().serialize(serializer)
    }
}

impl<'de> Deserialize<'de> for Sdp {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
        struct SdpVisitor;
        impl<'de> Visitor<'de> for SdpVisitor {
            type Value = Sdp;

            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
                formatter.write_str("an SDP string")
            }

            fn visit_str<E>(self, value: &str) -> Result<Sdp, E> where E: de::Error {
                if let Ok(cs_value) = CString::new(value) {
                    if let Ok(sdp) = Sdp::parse(&cs_value) {
                        return Ok(sdp)
                    }
                }
                Err(E::invalid_value(Unexpected::Str(value), &self))
            }
        }
        deserializer.deserialize_str(SdpVisitor)
    }
}

unsafe impl Send for Sdp {}

#[macro_export]
/// Given an SDP offer from a client, generates an SDP answer.
/// (This has to be a macro because `generate_answer` is variadic.)
macro_rules! answer_sdp {
    ($sdp:expr $(, $param:expr, $value:expr)* $(,)*) => {
        unsafe {
            let result = $crate::sdp::generate_answer(
                $sdp.ptr,
                $($param, $value,)*
                $crate::sdp::OfferAnswerParameters::Done
            );
            $crate::sdp::Sdp::new(result).expect("Mysterious error generating SDP answer :(")
        }
    }
}

#[macro_export]
/// Generates an SDP offer given some parameters.
/// (This has to be a macro because `generate_offer` is variadic.)
macro_rules! offer_sdp {
    ($name:expr, $address:expr $(, $param:expr, $value:expr)* $(,)*) => {
        unsafe {
            let result = $crate::sdp::generate_offer(
                $name,
                $address,
                $($param, $value,)*
                $crate::sdp::OfferAnswerParameters::Done
            );
            $crate::sdp::Sdp::new(result).expect("Mysterious error generating SDP offer :(")
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use getrandom::getrandom;

use poly::{eval, generate, y_intercept};

/// Split a secret into N shares, of which K are required to re-combine. Returns
/// a map of share IDs to share values.
pub fn split(n: u8, k: u8, secret: &[u8]) -> HashMap<u8, Vec<u8>> {
    // Generate a random K-degree polynomial for each byte of the secret.
    let polys = secret
        .iter()
        .map(|b| generate(k - 1, *b, &mut getrandom))
        .collect::<Vec<Vec<u8>>>();

    // Collect the evaluation of each polynomial with the share ID as the input.
    (1..=n)
        .map(|id| (id, polys.iter().map(|p| eval(p, id)).collect()))
        .collect()
}

/// Combine a map of share IDs into the original secret.
///
/// N.B.: There is no way to know if this is successful or not.
pub fn combine<S: ::std::hash::BuildHasher>(shares: &HashMap<u8, Vec<u8>, S>) -> Vec<u8> {
    let len = shares.values().next().unwrap().len();
    if shares.values().any(|v| v.len() != len) {
        panic!("mismatched share lengths")
    }

    (0..len)
        .map(|i| y_intercept(shares.iter().map(|(id, v)| (*id, v[i])).collect()))
        .collect()
}

#[cfg(test)]
mod test {
    extern crate itertools;

    use super::*;

    use self::itertools::Itertools;

    #[test]
    fn test_split() {
        let secret = vec![1, 2, 3, 4, 5];
        let splits = split(5, 3, &secret);

        for i in 5..3 {
            for keys in splits.keys().combinations(i) {
                let mut subset: HashMap<u8, Vec<u8>> = HashMap::new();
                for key in keys {
                    subset.insert(*key, splits.get(key).unwrap().to_vec());
                }
                assert_eq!(combine(&subset), secret);
            }
        }

        for i in 2..1 {
            for keys in splits.keys().combinations(i) {
                let mut subset: HashMap<u8, Vec<u8>> = HashMap::new();
                for key in keys {
                    subset.insert(*key, splits.get(key).unwrap().to_vec());
                }
                assert_ne!(combine(&subset), secret);
            }
        }
    }

    #[test]
    fn test_combine() {
        let mut shares: HashMap<u8, Vec<u8>> = HashMap::new();
        shares.insert(1, vec![64, 163, 216, 189, 193]);
        shares.insert(3, vec![194, 250, 117, 212, 82]);
        shares.insert(5, vec![95, 17, 153, 111, 252]);

        assert_eq!(combine(&shares), vec![1, 2, 3, 4, 5])
    }
}
<commit_msg>Fix ranges in tests.<commit_after>use std::collections::HashMap;

use getrandom::getrandom;

use poly::{eval, generate, y_intercept};

/// Split a secret into N shares, of which K are required to re-combine. Returns
/// a map of share IDs to share values.
pub fn split(n: u8, k: u8, secret: &[u8]) -> HashMap<u8, Vec<u8>> {
    // Generate a random K-degree polynomial for each byte of the secret.
    let polys = secret
        .iter()
        .map(|b| generate(k - 1, *b, &mut getrandom))
        .collect::<Vec<Vec<u8>>>();

    // Collect the evaluation of each polynomial with the share ID as the input.
    (1..=n)
        .map(|id| (id, polys.iter().map(|p| eval(p, id)).collect()))
        .collect()
}

/// Combine a map of share IDs into the original secret.
///
/// N.B.: There is no way to know if this is successful or not.
pub fn combine<S: ::std::hash::BuildHasher>(shares: &HashMap<u8, Vec<u8>, S>) -> Vec<u8> {
    let len = shares.values().next().unwrap().len();
    if shares.values().any(|v| v.len() != len) {
        panic!("mismatched share lengths")
    }

    (0..len)
        .map(|i| y_intercept(shares.iter().map(|(id, v)| (*id, v[i])).collect()))
        .collect()
}

#[cfg(test)]
mod test {
    extern crate itertools;

    use super::*;

    use self::itertools::Itertools;

    #[test]
    fn test_split() {
        let secret = vec![1, 2, 3, 4, 5];
        let splits = split(5, 3, &secret);

        for i in 5..=3 {
            for keys in splits.keys().combinations(i) {
                let mut subset: HashMap<u8, Vec<u8>> = HashMap::new();
                for key in keys {
                    subset.insert(*key, splits.get(key).unwrap().to_vec());
                }
                assert_eq!(combine(&subset), secret);
            }
        }

        for i in 2..=1 {
            for keys in splits.keys().combinations(i) {
                let mut subset: HashMap<u8, Vec<u8>> = HashMap::new();
                for key in keys {
                    subset.insert(*key, splits.get(key).unwrap().to_vec());
                }
                assert_ne!(combine(&subset), secret);
            }
        }
    }

    #[test]
    fn test_combine() {
        let mut shares: HashMap<u8, Vec<u8>> = HashMap::new();
        shares.insert(1, vec![64, 163, 216, 189, 193]);
        shares.insert(3, vec![194, 250, 117, 212, 82]);
        shares.insert(5, vec![95, 17, 153, 111, 252]);

        assert_eq!(combine(&shares), vec![1, 2, 3, 4, 5])
    }
}
<|endoftext|>


<commit_before>use rustc_serialize::{Encodable, Encoder};

use super::UpdateRequestId;

#[derive(RustcDecodable, RustcEncodable, Clone, Debug, PartialEq, Eq)]
pub struct UpdateReport {
    pub update_id:         UpdateRequestId,
    pub operation_results: Vec<OperationResult>
}

impl UpdateReport {
    pub fn new(update_id: String, results: Vec<OperationResult>) -> UpdateReport {
        UpdateReport { update_id: update_id, operation_results: results }
    }

    pub fn single(update_id: UpdateRequestId, result_code: UpdateResultCode, result_text: String) -> UpdateReport {
        let result = OperationResult {
            id: update_id.clone(),
            result_code: result_code,
            result_text: result_text
        };
        UpdateReport { update_id: update_id, operation_results: vec![result] }
    }
}

#[derive(RustcEncodable, Clone, Debug)]
pub struct DeviceReport<'d, 'r> {
    pub device: &'d str,
    pub report: &'r UpdateReport
}

impl<'d, 'r> DeviceReport<'d, 'r> {
    pub fn new(device: &'d str, report: &'r UpdateReport) -> DeviceReport<'d, 'r> {
        DeviceReport { device: &device, report: &report }
    }
}

#[allow(non_camel_case_types)]
#[derive(RustcDecodable, Clone, Debug, PartialEq, Eq)]
pub enum UpdateResultCode {
    OK = 0,                  // Operation executed successfully
    ALREADY_PROCESSED,       // Operation has already been processed
    DEPENDENCY_FAILURE,      // Dependency failure during package install, upgrade, or removal
    VALIDATION_FAILED,       // Update image integrity has been compromised
    INSTALL_FAILED,          // Package installation failed
    UPGRADE_FAILED,          // Package upgrade failed
    REMOVAL_FAILED,          // Package removal failed
    FLASH_FAILED,            // The module loader could not flash its managed module
    CREATE_PARTITION_FAILED, // Partition creation failed
    DELETE_PARTITION_FAILED, // Partition deletion failed
    RESIZE_PARTITION_FAILED, // Partition resize failed
    WRITE_PARTITION_FAILED,  // Partition write failed
    PATCH_PARTITION_FAILED,  // Partition patching failed
    USER_DECLINED,           // User declined the update
    SOFTWARE_BLACKLISTED,    // Software was blacklisted
    DISK_FULL,               // Ran out of disk space
    NOT_FOUND,               // Software package not found
    OLD_VERSION,             // Tried to downgrade to older version
    INTERNAL_ERROR,          // SWM Internal integrity error
    GENERAL_ERROR,           // Other error
}

impl Encodable for UpdateResultCode {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_u64(self.clone() as u64)
    }
}

#[derive(RustcDecodable, RustcEncodable, Clone, Debug, PartialEq, Eq)]
pub struct OperationResult {
    pub id:          String,
    pub result_code: UpdateResultCode,
    pub result_text: String,
}

#[derive(RustcDecodable, RustcEncodable, Clone, Debug, PartialEq, Eq)]
pub struct InstalledFirmware {
    pub module:        String,
    pub firmware_id:   String,
    pub last_modified: u64
}

#[derive(RustcDecodable, RustcEncodable, Clone, Debug, PartialEq, Eq)]
pub struct InstalledPackage {
    pub package_id:    String,
    pub name:          String,
    pub description:   String,
    pub last_modified: u64
}

#[derive(RustcDecodable, RustcEncodable, Clone, Debug, PartialEq, Eq)]
pub struct InstalledSoftware {
    pub packages:  Vec<InstalledPackage>,
    pub firmwares: Vec<InstalledFirmware>
}

impl InstalledSoftware {
    pub fn new(packages: Vec<InstalledPackage>, firmwares: Vec<InstalledFirmware>) -> InstalledSoftware {
        InstalledSoftware { packages: packages, firmwares: firmwares }
    }
}
<commit_msg>Yet another fix to the report name<commit_after>use rustc_serialize::{Encodable, Encoder};

use super::UpdateRequestId;

#[derive(RustcDecodable, RustcEncodable, Clone, Debug, PartialEq, Eq)]
pub struct UpdateReport {
    pub update_id:         UpdateRequestId,
    pub operation_results: Vec<OperationResult>
}

impl UpdateReport {
    pub fn new(update_id: String, results: Vec<OperationResult>) -> UpdateReport {
        UpdateReport { update_id: update_id, operation_results: results }
    }

    pub fn single(update_id: UpdateRequestId, result_code: UpdateResultCode, result_text: String) -> UpdateReport {
        let result = OperationResult {
            id: update_id.clone(),
            result_code: result_code,
            result_text: result_text
        };
        UpdateReport { update_id: update_id, operation_results: vec![result] }
    }
}

#[derive(RustcEncodable, Clone, Debug)]
pub struct DeviceReport<'d, 'r> {
    pub device:        &'d str,
    pub update_report: &'r UpdateReport
}

impl<'d, 'r> DeviceReport<'d, 'r> {
    pub fn new(device: &'d str, update_report: &'r UpdateReport) -> DeviceReport<'d, 'r> {
        DeviceReport { device: &device, update_report: &update_report }
    }
}

#[allow(non_camel_case_types)]
#[derive(RustcDecodable, Clone, Debug, PartialEq, Eq)]
pub enum UpdateResultCode {
    OK = 0,                  // Operation executed successfully
    ALREADY_PROCESSED,       // Operation has already been processed
    DEPENDENCY_FAILURE,      // Dependency failure during package install, upgrade, or removal
    VALIDATION_FAILED,       // Update image integrity has been compromised
    INSTALL_FAILED,          // Package installation failed
    UPGRADE_FAILED,          // Package upgrade failed
    REMOVAL_FAILED,          // Package removal failed
    FLASH_FAILED,            // The module loader could not flash its managed module
    CREATE_PARTITION_FAILED, // Partition creation failed
    DELETE_PARTITION_FAILED, // Partition deletion failed
    RESIZE_PARTITION_FAILED, // Partition resize failed
    WRITE_PARTITION_FAILED,  // Partition write failed
    PATCH_PARTITION_FAILED,  // Partition patching failed
    USER_DECLINED,           // User declined the update
    SOFTWARE_BLACKLISTED,    // Software was blacklisted
    DISK_FULL,               // Ran out of disk space
    NOT_FOUND,               // Software package not found
    OLD_VERSION,             // Tried to downgrade to older version
    INTERNAL_ERROR,          // SWM Internal integrity error
    GENERAL_ERROR,           // Other error
}

impl Encodable for UpdateResultCode {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_u64(self.clone() as u64)
    }
}

#[derive(RustcDecodable, RustcEncodable, Clone, Debug, PartialEq, Eq)]
pub struct OperationResult {
    pub id:          String,
    pub result_code: UpdateResultCode,
    pub result_text: String,
}

#[derive(RustcDecodable, RustcEncodable, Clone, Debug, PartialEq, Eq)]
pub struct InstalledFirmware {
    pub module:        String,
    pub firmware_id:   String,
    pub last_modified: u64
}

#[derive(RustcDecodable, RustcEncodable, Clone, Debug, PartialEq, Eq)]
pub struct InstalledPackage {
    pub package_id:    String,
    pub name:          String,
    pub description:   String,
    pub last_modified: u64
}

#[derive(RustcDecodable, RustcEncodable, Clone, Debug, PartialEq, Eq)]
pub struct InstalledSoftware {
    pub packages:  Vec<InstalledPackage>,
    pub firmwares: Vec<InstalledFirmware>
}

impl InstalledSoftware {
    pub fn new(packages: Vec<InstalledPackage>, firmwares: Vec<InstalledFirmware>) -> InstalledSoftware {
        InstalledSoftware { packages: packages, firmwares: firmwares }
    }
}
<|endoftext|>


<commit_before>use std::io;
use byteorder::{LittleEndian, ByteOrder};

use super::{Deserialize, Serialize, Error, Uint32};
use super::section::{
    Section, CodeSection, TypeSection, ImportSection, ExportSection, FunctionSection,
    GlobalSection, TableSection, ElementSection, DataSection, MemorySection
};

const WASM_MAGIC_NUMBER: [u8; 4] = [0x00, 0x61, 0x73, 0x6d];

/// WebAssembly module
#[derive(Clone)]
pub struct Module {
    magic: u32,
    version: u32,
    sections: Vec<Section>,
}

impl Default for Module {
    fn default() -> Self {
        Module {
            magic: 0x6d736100,
            version: 1,
            sections: Vec::with_capacity(16),
        }
    }
}

impl Module {
    /// New module with sections
    pub fn new(sections: Vec<Section>) -> Self {
        Module {
            sections: sections, ..Default::default()
        }
    }

    /// Destructure the module, yielding sections
    pub fn into_sections(self) -> Vec<Section> {
        self.sections
    }

    /// Version of module.
    pub fn version(&self) -> u32 { self.version }

    /// Sections list.
    /// Each known section is optional and may appear at most once.
    pub fn sections(&self) -> &[Section] {
        &self.sections
    }

    /// Sections list (mutable)
    /// Each known section is optional and may appear at most once.
    pub fn sections_mut(&mut self) -> &mut Vec<Section> {
        &mut self.sections
    }

    /// Code section, if any.
    pub fn code_section(&self) -> Option<&CodeSection> {
        for section in self.sections() {
            if let &Section::Code(ref code_section) = section { return Some(code_section); }
        }
        None
    }

    /// Types section, if any.
    pub fn type_section(&self) -> Option<&TypeSection> {
        for section in self.sections() {
            if let &Section::Type(ref type_section) = section { return Some(type_section); }
        }
        None
    }

    /// Imports section, if any.
    pub fn import_section(&self) -> Option<&ImportSection> {
        for section in self.sections() {
            if let &Section::Import(ref import_section) = section { return Some(import_section); }
        }
        None
    }

    /// Globals section, if any.
    pub fn global_section(&self) -> Option<&GlobalSection> {
        for section in self.sections() {
            if let &Section::Global(ref section) = section { return Some(section); }
        }
        None
    }

    /// Exports section, if any.
    pub fn export_section(&self) -> Option<&ExportSection> {
        for section in self.sections() {
            if let &Section::Export(ref export_section) = section { return Some(export_section); }
        }
        None
    }

    /// Table section, if any.
    pub fn table_section(&self) -> Option<&TableSection> {
        for section in self.sections() {
            if let &Section::Table(ref section) = section { return Some(section); }
        }
        None
    }

    /// Data section, if any.
    pub fn data_section(&self) -> Option<&DataSection> {
        for section in self.sections() {
            if let &Section::Data(ref section) = section { return Some(section); }
        }
        None
    }

    /// Element section, if any.
    pub fn elements_section(&self) -> Option<&ElementSection> {
        for section in self.sections() {
            if let &Section::Element(ref section) = section { return Some(section); }
        }
        None
    }

    /// Memory section, if any.
    pub fn memory_section(&self) -> Option<&MemorySection> {
        for section in self.sections() {
            if let &Section::Memory(ref section) = section { return Some(section); }
        }
        None
    }

    /// Functions signatures section, if any.
    pub fn function_section(&self) -> Option<&FunctionSection> {
        for section in self.sections() {
            if let &Section::Function(ref sect) = section { return Some(sect); }
        }
        None
    }

    /// Start section, if any.
    pub fn start_section(&self) -> Option<u32> {
        for section in self.sections() {
            if let &Section::Start(sect) = section { return Some(sect); }
        }
        None
    }
}

impl Deserialize for Module {
    type Error = super::Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let mut sections = Vec::new();

        let mut magic = [0u8; 4];
        reader.read(&mut magic)?;
        if magic != WASM_MAGIC_NUMBER {
            return Err(Error::InvalidMagic);
        }

        let version: u32 = Uint32::deserialize(reader)?.into();

        if version != 1 {
            return Err(Error::UnsupportedVersion(version));
        }

        loop {
            match Section::deserialize(reader) {
                Err(Error::UnexpectedEof) => { break; },
                Err(e) => { return Err(e) },
                Ok(section) => { sections.push(section); }
            }
        }

        Ok(Module {
            magic: LittleEndian::read_u32(&magic),
            version: version,
            sections: sections,
        })
    }
}

impl Serialize for Module {
    type Error = Error;

    fn serialize<W: io::Write>(self, w: &mut W) -> Result<(), Self::Error> {
        Uint32::from(self.magic).serialize(w)?;
        Uint32::from(self.version).serialize(w)?;
        for section in self.sections.into_iter() {
            section.serialize(w)?;
        }
        Ok(())
    }
}

struct PeekSection<'a> {
    cursor: usize,
    region: &'a [u8],
}

impl<'a> io::Read for PeekSection<'a> {
    fn read(&mut self, buf: &mut [u8]) -> ::std::io::Result<usize> {
        let available = ::std::cmp::min(buf.len(), self.region.len() - self.cursor);
        if available < buf.len() {
            return Err(::std::io::Error::from(::std::io::ErrorKind::UnexpectedEof));
        }

        let range = self.cursor..self.cursor + buf.len();
        buf.copy_from_slice(&self.region[range]);

        self.cursor += available;
        Ok(available)
    }
}

/// Returns size of the module in the provided stream
pub fn peek_size(source: &[u8]) -> usize {
    if source.len() < 9 {
        return 0;
    }

    let mut cursor = 8;
    loop {
        let (new_cursor, section_id, section_len) = {
            let mut peek_section = PeekSection { cursor: 0, region: &source[cursor..] };
            let section_id: u8 = match super::VarUint7::deserialize(&mut peek_section) {
                Ok(res) => res.into(),
                Err(_) => { break; },
            };
            let section_len: u32 = match super::VarUint32::deserialize(&mut peek_section) {
                Ok(res) => res.into(),
                Err(_) => { break; },
            };

            (peek_section.cursor, section_id, section_len)
        };

        if section_id <= 11 && section_len > 0 {
            let next_cursor = cursor + new_cursor + section_len as usize;
            if next_cursor >= source.len() {
                break;
            }
            cursor = next_cursor;
        } else {
            break;
        }
    }

    cursor
}

#[cfg(test)]
mod integration_tests {

    use super::super::{deserialize_file, serialize, deserialize_buffer, Section};
    use super::Module;

    #[test]
    fn hello() {
        let module = deserialize_file("./res/cases/v1/hello.wasm").expect("Should be deserialized");

        assert_eq!(module.version(), 1);
        assert_eq!(module.sections().len(), 8);
    }

    #[test]
    fn serde() {
        let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        let buf = serialize(module).expect("serialization to succeed");

        let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
        let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");

        assert_eq!(module_old.sections().len(), module_new.sections().len());
    }

    #[test]
    fn serde_type() {
        let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        module.sections_mut().retain(|x| {
            if let &Section::Type(_) = x { true } else { false }
        });

        let buf = serialize(module).expect("serialization to succeed");

        let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
        let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        assert_eq!(
            module_old.type_section().expect("type section exists").types().len(),
            module_new.type_section().expect("type section exists").types().len(),
            "There should be equal amount of types before and after serialization"
        );
    }

    #[test]
    fn serde_import() {
        let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        module.sections_mut().retain(|x| {
            if let &Section::Import(_) = x { true } else { false }
        });

        let buf = serialize(module).expect("serialization to succeed");

        let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
        let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        assert_eq!(
            module_old.import_section().expect("import section exists").entries().len(),
            module_new.import_section().expect("import section exists").entries().len(),
            "There should be equal amount of import entries before and after serialization"
        );
    }

    #[test]
    fn serde_code() {
        let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        module.sections_mut().retain(|x| {
            if let &Section::Code(_) = x { true } else { false }
        });

        let buf = serialize(module).expect("serialization to succeed");

        let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
        let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        assert_eq!(
            module_old.code_section().expect("code section exists").bodies().len(),
            module_new.code_section().expect("code section exists").bodies().len(),
            "There should be equal amount of function bodies before and after serialization"
        );
    }

    #[test]
    fn const_() {
        use super::super::Opcode::*;

        let module = deserialize_file("./res/cases/v1/const.wasm").expect("Should be deserialized");
        let func = &module.code_section().expect("Code section to exist").bodies()[0];
        assert_eq!(func.code().elements().len(), 20);

        assert_eq!(I64Const(9223372036854775807), func.code().elements()[0]);
        assert_eq!(I64Const(-9223372036854775808), func.code().elements()[1]);
        assert_eq!(I64Const(-1152894205662152753), func.code().elements()[2]);
        assert_eq!(I64Const(-8192), func.code().elements()[3]);
        assert_eq!(I32Const(1024), func.code().elements()[4]);
        assert_eq!(I32Const(2048), func.code().elements()[5]);
        assert_eq!(I32Const(4096), func.code().elements()[6]);
        assert_eq!(I32Const(8192), func.code().elements()[7]);
        assert_eq!(I32Const(16384), func.code().elements()[8]);
        assert_eq!(I32Const(32767), func.code().elements()[9]);
        assert_eq!(I32Const(-1024), func.code().elements()[10]);
        assert_eq!(I32Const(-2048), func.code().elements()[11]);
        assert_eq!(I32Const(-4096), func.code().elements()[12]);
        assert_eq!(I32Const(-8192), func.code().elements()[13]);
        assert_eq!(I32Const(-16384), func.code().elements()[14]);
        assert_eq!(I32Const(-32768), func.code().elements()[15]);
        assert_eq!(I32Const(-2147483648), func.code().elements()[16]);
        assert_eq!(I32Const(2147483647), func.code().elements()[17]);
    }

    #[test]
    fn store() {
        use super::super::Opcode::*;

        let module = deserialize_file("./res/cases/v1/offset.wasm").expect("Should be deserialized");
        let func = &module.code_section().expect("Code section to exist").bodies()[0];

        assert_eq!(func.code().elements().len(), 5);
        assert_eq!(I64Store(0, 32), func.code().elements()[2]);
    }

    #[test]
    fn peek() {
        use super::peek_size;

        let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        let mut buf = serialize(module).expect("serialization to succeed");

        buf.extend_from_slice(&[1, 5, 12, 17]);

        assert_eq!(peek_size(&buf), buf.len() - 4);
    }

    #[test]
    fn peek_2() {
        use super::peek_size;

        let module = deserialize_file("./res/cases/v1/offset.wasm").expect("Should be deserialized");
        let mut buf = serialize(module).expect("serialization to succeed");

        buf.extend_from_slice(&[0, 0, 0, 0, 0, 1, 5, 12, 17]);

        assert_eq!(peek_size(&buf), buf.len() - 9);
    }
}
<commit_msg>Made default module magic number endian-independent.<commit_after>use std::io;
use byteorder::{LittleEndian, ByteOrder};

use super::{Deserialize, Serialize, Error, Uint32};
use super::section::{
    Section, CodeSection, TypeSection, ImportSection, ExportSection, FunctionSection,
    GlobalSection, TableSection, ElementSection, DataSection, MemorySection
};

const WASM_MAGIC_NUMBER: [u8; 4] = [0x00, 0x61, 0x73, 0x6d];

/// WebAssembly module
#[derive(Clone)]
pub struct Module {
    magic: u32,
    version: u32,
    sections: Vec<Section>,
}

impl Default for Module {
    fn default() -> Self {
        Module {
            magic: LittleEndian::read_u32(&WASM_MAGIC_NUMBER),
            version: 1,
            sections: Vec::with_capacity(16),
        }
    }
}

impl Module {
    /// New module with sections
    pub fn new(sections: Vec<Section>) -> Self {
        Module {
            sections: sections, ..Default::default()
        }
    }

    /// Destructure the module, yielding sections
    pub fn into_sections(self) -> Vec<Section> {
        self.sections
    }

    /// Version of module.
    pub fn version(&self) -> u32 { self.version }

    /// Sections list.
    /// Each known section is optional and may appear at most once.
    pub fn sections(&self) -> &[Section] {
        &self.sections
    }

    /// Sections list (mutable)
    /// Each known section is optional and may appear at most once.
    pub fn sections_mut(&mut self) -> &mut Vec<Section> {
        &mut self.sections
    }

    /// Code section, if any.
    pub fn code_section(&self) -> Option<&CodeSection> {
        for section in self.sections() {
            if let &Section::Code(ref code_section) = section { return Some(code_section); }
        }
        None
    }

    /// Types section, if any.
    pub fn type_section(&self) -> Option<&TypeSection> {
        for section in self.sections() {
            if let &Section::Type(ref type_section) = section { return Some(type_section); }
        }
        None
    }

    /// Imports section, if any.
    pub fn import_section(&self) -> Option<&ImportSection> {
        for section in self.sections() {
            if let &Section::Import(ref import_section) = section { return Some(import_section); }
        }
        None
    }

    /// Globals section, if any.
    pub fn global_section(&self) -> Option<&GlobalSection> {
        for section in self.sections() {
            if let &Section::Global(ref section) = section { return Some(section); }
        }
        None
    }

    /// Exports section, if any.
    pub fn export_section(&self) -> Option<&ExportSection> {
        for section in self.sections() {
            if let &Section::Export(ref export_section) = section { return Some(export_section); }
        }
        None
    }

    /// Table section, if any.
    pub fn table_section(&self) -> Option<&TableSection> {
        for section in self.sections() {
            if let &Section::Table(ref section) = section { return Some(section); }
        }
        None
    }

    /// Data section, if any.
    pub fn data_section(&self) -> Option<&DataSection> {
        for section in self.sections() {
            if let &Section::Data(ref section) = section { return Some(section); }
        }
        None
    }

    /// Element section, if any.
    pub fn elements_section(&self) -> Option<&ElementSection> {
        for section in self.sections() {
            if let &Section::Element(ref section) = section { return Some(section); }
        }
        None
    }

    /// Memory section, if any.
    pub fn memory_section(&self) -> Option<&MemorySection> {
        for section in self.sections() {
            if let &Section::Memory(ref section) = section { return Some(section); }
        }
        None
    }

    /// Functions signatures section, if any.
    pub fn function_section(&self) -> Option<&FunctionSection> {
        for section in self.sections() {
            if let &Section::Function(ref sect) = section { return Some(sect); }
        }
        None
    }

    /// Start section, if any.
    pub fn start_section(&self) -> Option<u32> {
        for section in self.sections() {
            if let &Section::Start(sect) = section { return Some(sect); }
        }
        None
    }
}

impl Deserialize for Module {
    type Error = super::Error;

    fn deserialize<R: io::Read>(reader: &mut R) -> Result<Self, Self::Error> {
        let mut sections = Vec::new();

        let mut magic = [0u8; 4];
        reader.read(&mut magic)?;
        if magic != WASM_MAGIC_NUMBER {
            return Err(Error::InvalidMagic);
        }

        let version: u32 = Uint32::deserialize(reader)?.into();

        if version != 1 {
            return Err(Error::UnsupportedVersion(version));
        }

        loop {
            match Section::deserialize(reader) {
                Err(Error::UnexpectedEof) => { break; },
                Err(e) => { return Err(e) },
                Ok(section) => { sections.push(section); }
            }
        }

        Ok(Module {
            magic: LittleEndian::read_u32(&magic),
            version: version,
            sections: sections,
        })
    }
}

impl Serialize for Module {
    type Error = Error;

    fn serialize<W: io::Write>(self, w: &mut W) -> Result<(), Self::Error> {
        Uint32::from(self.magic).serialize(w)?;
        Uint32::from(self.version).serialize(w)?;
        for section in self.sections.into_iter() {
            section.serialize(w)?;
        }
        Ok(())
    }
}

struct PeekSection<'a> {
    cursor: usize,
    region: &'a [u8],
}

impl<'a> io::Read for PeekSection<'a> {
    fn read(&mut self, buf: &mut [u8]) -> ::std::io::Result<usize> {
        let available = ::std::cmp::min(buf.len(), self.region.len() - self.cursor);
        if available < buf.len() {
            return Err(::std::io::Error::from(::std::io::ErrorKind::UnexpectedEof));
        }

        let range = self.cursor..self.cursor + buf.len();
        buf.copy_from_slice(&self.region[range]);

        self.cursor += available;
        Ok(available)
    }
}

/// Returns size of the module in the provided stream
pub fn peek_size(source: &[u8]) -> usize {
    if source.len() < 9 {
        return 0;
    }

    let mut cursor = 8;
    loop {
        let (new_cursor, section_id, section_len) = {
            let mut peek_section = PeekSection { cursor: 0, region: &source[cursor..] };
            let section_id: u8 = match super::VarUint7::deserialize(&mut peek_section) {
                Ok(res) => res.into(),
                Err(_) => { break; },
            };
            let section_len: u32 = match super::VarUint32::deserialize(&mut peek_section) {
                Ok(res) => res.into(),
                Err(_) => { break; },
            };

            (peek_section.cursor, section_id, section_len)
        };

        if section_id <= 11 && section_len > 0 {
            let next_cursor = cursor + new_cursor + section_len as usize;
            if next_cursor >= source.len() {
                break;
            }
            cursor = next_cursor;
        } else {
            break;
        }
    }

    cursor
}

#[cfg(test)]
mod integration_tests {

    use super::super::{deserialize_file, serialize, deserialize_buffer, Section};
    use super::Module;

    #[test]
    fn hello() {
        let module = deserialize_file("./res/cases/v1/hello.wasm").expect("Should be deserialized");

        assert_eq!(module.version(), 1);
        assert_eq!(module.sections().len(), 8);
    }

    #[test]
    fn serde() {
        let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        let buf = serialize(module).expect("serialization to succeed");

        let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
        let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");

        assert_eq!(module_old.sections().len(), module_new.sections().len());
    }

    #[test]
    fn serde_type() {
        let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        module.sections_mut().retain(|x| {
            if let &Section::Type(_) = x { true } else { false }
        });

        let buf = serialize(module).expect("serialization to succeed");

        let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
        let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        assert_eq!(
            module_old.type_section().expect("type section exists").types().len(),
            module_new.type_section().expect("type section exists").types().len(),
            "There should be equal amount of types before and after serialization"
        );
    }

    #[test]
    fn serde_import() {
        let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        module.sections_mut().retain(|x| {
            if let &Section::Import(_) = x { true } else { false }
        });

        let buf = serialize(module).expect("serialization to succeed");

        let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
        let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        assert_eq!(
            module_old.import_section().expect("import section exists").entries().len(),
            module_new.import_section().expect("import section exists").entries().len(),
            "There should be equal amount of import entries before and after serialization"
        );
    }

    #[test]
    fn serde_code() {
        let mut module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        module.sections_mut().retain(|x| {
            if let &Section::Code(_) = x { true } else { false }
        });

        let buf = serialize(module).expect("serialization to succeed");

        let module_new: Module = deserialize_buffer(&buf).expect("deserialization to succeed");
        let module_old = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        assert_eq!(
            module_old.code_section().expect("code section exists").bodies().len(),
            module_new.code_section().expect("code section exists").bodies().len(),
            "There should be equal amount of function bodies before and after serialization"
        );
    }

    #[test]
    fn const_() {
        use super::super::Opcode::*;

        let module = deserialize_file("./res/cases/v1/const.wasm").expect("Should be deserialized");
        let func = &module.code_section().expect("Code section to exist").bodies()[0];
        assert_eq!(func.code().elements().len(), 20);

        assert_eq!(I64Const(9223372036854775807), func.code().elements()[0]);
        assert_eq!(I64Const(-9223372036854775808), func.code().elements()[1]);
        assert_eq!(I64Const(-1152894205662152753), func.code().elements()[2]);
        assert_eq!(I64Const(-8192), func.code().elements()[3]);
        assert_eq!(I32Const(1024), func.code().elements()[4]);
        assert_eq!(I32Const(2048), func.code().elements()[5]);
        assert_eq!(I32Const(4096), func.code().elements()[6]);
        assert_eq!(I32Const(8192), func.code().elements()[7]);
        assert_eq!(I32Const(16384), func.code().elements()[8]);
        assert_eq!(I32Const(32767), func.code().elements()[9]);
        assert_eq!(I32Const(-1024), func.code().elements()[10]);
        assert_eq!(I32Const(-2048), func.code().elements()[11]);
        assert_eq!(I32Const(-4096), func.code().elements()[12]);
        assert_eq!(I32Const(-8192), func.code().elements()[13]);
        assert_eq!(I32Const(-16384), func.code().elements()[14]);
        assert_eq!(I32Const(-32768), func.code().elements()[15]);
        assert_eq!(I32Const(-2147483648), func.code().elements()[16]);
        assert_eq!(I32Const(2147483647), func.code().elements()[17]);
    }

    #[test]
    fn store() {
        use super::super::Opcode::*;

        let module = deserialize_file("./res/cases/v1/offset.wasm").expect("Should be deserialized");
        let func = &module.code_section().expect("Code section to exist").bodies()[0];

        assert_eq!(func.code().elements().len(), 5);
        assert_eq!(I64Store(0, 32), func.code().elements()[2]);
    }

    #[test]
    fn peek() {
        use super::peek_size;

        let module = deserialize_file("./res/cases/v1/test5.wasm").expect("Should be deserialized");
        let mut buf = serialize(module).expect("serialization to succeed");

        buf.extend_from_slice(&[1, 5, 12, 17]);

        assert_eq!(peek_size(&buf), buf.len() - 4);
    }

    #[test]
    fn peek_2() {
        use super::peek_size;

        let module = deserialize_file("./res/cases/v1/offset.wasm").expect("Should be deserialized");
        let mut buf = serialize(module).expect("serialization to succeed");

        buf.extend_from_slice(&[0, 0, 0, 0, 0, 1, 5, 12, 17]);

        assert_eq!(peek_size(&buf), buf.len() - 9);
    }

    #[test]
    fn module_default_round_trip() {
        let module1 = Module::default();
        let buf = serialize(module1).expect("Serialization should succeed");

        let module2: Module = deserialize_buffer(&buf).expect("Deserialization should succeed");
        assert_eq!(Module::default().magic, module2.magic);
    }
}
<|endoftext|>