<commit_before>//   Copyright 2014 Colin Sherratt
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

#![feature(old_impl_check)]

extern crate "snowmew-core" as core;

use std::sync::Arc;
use std::collections::{VecMap, BTreeMap};
use std::ops::{Deref, DerefMut};
use core::game::Game;

#[derive(Clone)]
pub struct Debugger<Game> {
    game: Game
}

impl<Game> Debugger<Game> {
    pub fn new(game: Game) -> Debugger<Game> {
        Debugger { game: game }
    }
}

#[derive(Clone)]
pub struct DebuggerGameData<GameData, Event> {
    index: uint,
    limit: uint,
    events: Arc<VecMap<Event>>,
    history: Arc<BTreeMap<uint, GameData>>,
    pub inner: GameData
}

impl<GameData: Send+Sync+Clone, Event: Send+Sync+Clone> DebuggerGameData<GameData, Event> {
    pub fn new(inner: GameData, limit: uint) -> DebuggerGameData<GameData, Event> {
        DebuggerGameData {
            index: 0,
            limit: limit,
            events: Arc::new(VecMap::new()),
            history: Arc::new(BTreeMap::new()),
            inner: inner
        }
    }

    fn compact(&mut self) {
        while self.history.len() > self.limit {
            let mut vec = Vec::new();
            {
                let last = self.history.iter();
                let mut this = self.history.iter();
                this.next();

                for ((&last, _), (&this, _)) in last.zip(this) {
                    vec.push((this - last, this));
                }
            }

            vec.as_mut_slice().sort_by(|&(b, _), &(a, _)| a.partial_cmp(&b).unwrap());

            let (_, remove) = vec.pop().unwrap();
            self.history.make_unique().remove(&remove).is_some();
        }
    }
}

impl<E, T> Deref for DebuggerGameData<T, E> {
    type Target = T;

    fn deref<'a>(&'a self) -> &'a <Self as Deref>::Target {
        &self.inner
    }
}

impl<E, T> DerefMut for DebuggerGameData<T, E> {
    fn deref_mut <'a>(&'a mut self) -> &'a mut <Self as Deref>::Target {
        &mut self.inner
    }
}

#[old_impl_check]
impl<GameData: Clone+Send+Sync,
     Event: Clone+Send+Sync,
     InputGame: Game<GameData, Event>> Debugger<InputGame> {

    /// seek a checkpoint ahead of the current point
    pub fn skip_forward(&mut self, mut gd: DebuggerGameData<GameData, Event>)
        -> DebuggerGameData<GameData, Event> {
        let mut out = None;
        for (&idx, f) in gd.history.iter() {
            if idx > gd.index {
                out = Some((idx, f.clone()));
                break;
            }
        }
        if let Some((idx, f)) = out {
            gd.index = idx;
            gd.inner = f;
        }
        gd
    }

    /// seek a checkout before the current time
    pub fn skip_backward(&mut self, mut gd: DebuggerGameData<GameData, Event>)
        -> DebuggerGameData<GameData, Event> {
        let mut out = None;
        for (&idx, f) in gd.history.iter().rev() {
            if idx < gd.index {
                out = Some((idx, f.clone()));
                break;
            }
        }
        if let Some((idx, f)) = out {
            println!("{}", idx);
            gd.index = idx;
            gd.inner = f;
        }
        gd
    }

    /// set limit of checkpoints
    pub fn limit(&mut self, limit: uint, mut gd: DebuggerGameData<GameData, Event>)
        -> DebuggerGameData<GameData, Event> {
        gd.limit = limit;
        gd.compact();
        gd
    }
}

impl<GameData: Clone+Send+Sync,
     Event: Clone+Send+Sync,
     InputGame: Game<GameData, Event>>
     Game<DebuggerGameData<GameData, Event>, Event> for Debugger<InputGame> {
    fn step(&mut self, event: Event, gd: DebuggerGameData<GameData, Event>)
        -> DebuggerGameData<GameData, Event> {

        let mut next = gd.clone();
        next.history.make_unique().insert(next.index, gd.inner.clone());
        next.index += 1;
        next.compact();
        next.inner = self.game.step(event, gd.inner);
        next
    }
}
<commit_msg>expand debugger to add replay_one and revert_one<commit_after>//   Copyright 2014 Colin Sherratt
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

#![feature(old_impl_check)]

extern crate "snowmew-core" as core;

use std::sync::Arc;
use std::collections::{VecMap, BTreeMap};
use std::ops::{Deref, DerefMut};
use core::game::Game;

#[derive(Clone)]
pub struct Debugger<Game> {
    game: Game
}

impl<Game> Debugger<Game> {
    pub fn new(game: Game) -> Debugger<Game> {
        Debugger { game: game }
    }
}

#[derive(Clone)]
pub struct DebuggerGameData<GameData, Event> {
    index: uint,
    limit: uint,
    events: Arc<VecMap<Event>>,
    history: Arc<BTreeMap<uint, GameData>>,
    pub inner: GameData
}

impl<GameData: Send+Sync+Clone, Event: Send+Sync+Clone> DebuggerGameData<GameData, Event> {
    pub fn new(inner: GameData, limit: uint) -> DebuggerGameData<GameData, Event> {
        DebuggerGameData {
            index: 0,
            limit: limit,
            events: Arc::new(VecMap::new()),
            history: Arc::new(BTreeMap::new()),
            inner: inner
        }
    }

    fn compact(&mut self) {
        while self.history.len() > self.limit {
            let mut vec = Vec::new();
            {
                let last = self.history.iter();
                let mut this = self.history.iter();
                this.next();

                for ((&last, _), (&this, _)) in last.zip(this) {
                    vec.push((this - last, this));
                }
            }

            vec.as_mut_slice().sort_by(|&(b, _), &(a, _)| a.partial_cmp(&b).unwrap());

            let (_, remove) = vec.pop().unwrap();
            self.history.make_unique().remove(&remove).is_some();
        }
    }
}

impl<E, T> Deref for DebuggerGameData<T, E> {
    type Target = T;

    fn deref<'a>(&'a self) -> &'a <Self as Deref>::Target {
        &self.inner
    }
}

impl<E, T> DerefMut for DebuggerGameData<T, E> {
    fn deref_mut <'a>(&'a mut self) -> &'a mut <Self as Deref>::Target {
        &mut self.inner
    }
}

#[old_impl_check]
impl<GameData: Clone+Send+Sync,
     Event: Clone+Send+Sync,
     InputGame: Game<GameData, Event>> Debugger<InputGame> {

    /// seek a checkpoint ahead of the current point
    pub fn skip_forward(&mut self, mut gd: DebuggerGameData<GameData, Event>)
        -> DebuggerGameData<GameData, Event> {
        let mut out = None;
        for (&idx, f) in gd.history.iter() {
            if idx > gd.index {
                out = Some((idx, f.clone()));
                break;
            }
        }
        if let Some((idx, f)) = out {
            gd.index = idx;
            gd.inner = f;
        }
        gd
    }

    /// seek a checkout before the current time
    pub fn skip_backward(&mut self, mut gd: DebuggerGameData<GameData, Event>)
        -> DebuggerGameData<GameData, Event> {
        let mut out = None;
        for (&idx, f) in gd.history.iter().rev() {
            if idx < gd.index {
                out = Some((idx, f.clone()));
                break;
            }
        }
        if let Some((idx, f)) = out {
            println!("{}", idx);
            gd.index = idx;
            gd.inner = f;
        }
        gd
    }

    pub fn replay_one(&mut self, mut gd: DebuggerGameData<GameData, Event>)
        -> DebuggerGameData<GameData, Event> {
        if let Some(event) = gd.events.get(&gd.index).map(|x| x.clone()) {
            gd.inner = self.game.step(event, gd.inner);
            gd.index += 1;
        }
        gd
    }

    pub fn revert_one(&mut self, mut gd: DebuggerGameData<GameData, Event>)
        -> DebuggerGameData<GameData, Event> {
        let idx = gd.index - 1;
        if idx == 0 {
            gd
        } else {
            gd = self.skip_backward(gd);
            while gd.index != idx {
                gd = self.replay_one(gd);
            }
            gd
        }
    }

    /// set limit of checkpoints
    pub fn limit(&mut self, limit: uint, mut gd: DebuggerGameData<GameData, Event>)
        -> DebuggerGameData<GameData, Event> {
        gd.limit = limit;
        gd.compact();
        gd
    }
}

impl<GameData: Clone+Send+Sync,
     Event: Clone+Send+Sync,
     InputGame: Game<GameData, Event>>
     Game<DebuggerGameData<GameData, Event>, Event> for Debugger<InputGame> {
    fn step(&mut self, event: Event, gd: DebuggerGameData<GameData, Event>)
        -> DebuggerGameData<GameData, Event> {

        let mut next = gd.clone();
        next.history.make_unique().insert(next.index, gd.inner.clone());
        next.events.make_unique().insert(next.index, event.clone());
        next.index += 1;
        next.compact();
        next.inner = self.game.step(event, gd.inner);
        next
    }
}
<|endoftext|>


<commit_before>use std::fmt::{self, Write, Debug, Formatter};
use std::mem;

use gtk::signal::Inhibit;
use gdk::EventKey;

use logic::Token;

#[derive(Clone)]
pub struct Line {
	/// The line number of the proof, starting at 0. It is only visually where everything is incremented
	pub no: usize,
	/// A step of the proof. e.g. (P^Q)->P. This is a vector of tokens that can be invalid.
	pub step: Vec<Token>,
	/// A token string representing the method of the proof.
	pub method: Vec<Token>,
	/// Line numbers that this depends on. Line numbers start at 0.
	pub deps: Vec<usize>,
}
impl Line {
	/// Constructs an empty line
	pub fn new(no: usize) -> Line {
		Line {
			no: no,
			step: Vec::new(),
			method: Vec::new(),
			deps: Vec::new(),
		}
	}
	/// Constructs a line with the specified tokens in the `step` field.
	pub fn with_step(no: usize, step: Vec<Token>) -> Line {
		Line {
			no: no,
			step: step,
			method: Vec::new(),
			deps: Vec::new(),
		}
	}
	pub fn full(no: usize, step: Vec<Token>, method: Vec<Token>, deps: Vec<usize>) -> Line {
		Line {
			no: no,
			step: step,
			method: method,
			deps: deps,
		}
	}

	pub fn fmt_cursor(&self, f: &mut Formatter, c: &Cursor) -> Result<(), fmt::Error> {
		let mut step_str = String::with_capacity(self.step.len() + 16);
		if !f.alternate() {
			for (i, t) in self.step.iter().enumerate() {
				if c.no == self.no && c.col == Col::Step && c.i == i {
					step_str.push('|');
				}
				try!(write!(step_str, "{}", t));
			}
		} else {
			for (i, t) in self.step.iter().enumerate() {
				if c.no == self.no && c.col == Col::Step && c.i == i {
					step_str.push('|');
				}
				try!(write!(step_str, "{:#}", t));
			}
		}
		if c.no == self.no && c.col == Col::Step && c.i == self.step.len() {
			step_str.push('|');
		}

		let mut dep_str = String::with_capacity(self.deps.len() * 2);
		for (i, dep) in self.deps.iter().enumerate() {
			try!(write!(dep_str, "{}", dep + 1));
			if i < self.deps.len() - 1 {
				dep_str.push_str(", ")
			}
		}

		let mut method_str = String::with_capacity(self.method.len() + 8);
		if c.no == self.no && c.col == Col::Method && (c.i <= self.method.len() || self.method.len() == 0) {
			let (a, b) = self.method.split_at(c.i);
			if !f.alternate() {
				for t in a {
					try!(write!(method_str, "{}", t));
				}
				method_str.push('|');
				for t in b {
					try!(write!(method_str, "{}", t));
				}
			} else {
				for t in a {
					try!(write!(method_str, "{:#}", t));
				}
				method_str.push('|');
				for t in b {
					try!(write!(method_str, "{:#}", t));
				}
			}
		} else {
			if !f.alternate() {
				for t in self.method.iter() {
					try!(write!(method_str, "{}", t));
				}
			} else {
				for t in self.method.iter() {
					try!(write!(method_str, "{:#}", t));
				}
			}
		}
		f.pad(&format!("{: >3}. {: <20} {: <10} {{{}}}", self.no + 1, step_str, method_str, dep_str))
	}
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Col {
	Step,
	Method,
}
#[derive(Debug, PartialEq, Eq)]
pub struct Cursor {
	/// Line number
	no: usize,
	/// Column
	col: Col,
	/// Index of token/string
	i: usize,
}
impl Cursor {
	pub fn new() -> Cursor {
		Cursor {
			no: 0,
			col: Col::Step,
			i: 0,
		}
	}
	/// Move the cursor to the right. Wrap at end of line. Error at end of text.
	pub fn right(&mut self, lines: &[Line]) -> Result<(), ()> {
		let l = match lines.get(self.no) {
			Some(l) => l,
			None    => { *self = Cursor::new(); return Err(()); },
		};
		self.i += 1;
		match self.col {
			Col::Step => {
				if self.i > l.step.len() {
					self.col = Col::Method;
					self.i = 0;
				}
				Ok(())
			}
			Col::Method => {
				if self.i > l.method.len() {
					if self.no < lines.len() - 1 {
						self.no += 1;
						self.col = Col::Step;
						self.i = 0;
						Ok(())
					} else {
						self.i -= 1;
						Err(())
					}
				} else {
					Ok(())
				}
			}
		}
	}
	/// Move the cursor to the left. Wrap at start of line. Error at start of text.
	pub fn left(&mut self, lines: &[Line]) -> Result<(), ()> {
		let l = match lines.get(self.no) {
			Some(l) => l,
			None    => { *self = Cursor::new(); return Err(()); },
		};

		if self.i == 0 {
			match self.col {
				Col::Step => {
					if self.no > 0 {
						self.no -= 1;
						self.col = Col::Method;
						self.i = match lines.get(self.no) {
							Some(l) => l.method.len(),
							None    => { *self = Cursor::new(); return Err(()); },
						};
					}
				}
				Col::Method => {
					self.col = Col::Step;
					self.i = l.step.len();
				}
			}
		} else {
			self.i -= 1;
		}
		Ok(())
	}

	/// Add a newline to `lines` if the cursor is at the end of the line.
	pub fn newline(&mut self, lines: &mut Vec<Line>) -> Result<(), ()> {
		if !(  (self.col == Col::Step && self.i == lines[self.no].step.len())
			|| (self.col == Col::Method && self.i == lines[self.no].method.len())) {
			// Don't place a newline if the cursor isn't at the end of the line.
			return Err(());
		}

		let no = self.no + 1;
		for l in lines.iter_mut() {
			if l.no >= no {
				l.no += 1;
			}
		}
		lines.insert(no, Line::new(no));

		self.no += 1;
		self.i = 0;

		Ok(())
	}
}

pub struct Editor {
	lines: Vec<Line>,
	cursor: Cursor,
}

impl<'a> Editor {
	/// Constructs a new editor
	pub fn new() -> Editor {
		Editor {
			lines: vec![Line::full(0, vec![Token::Char('P')], Token::from_str("Premise"), vec![0]),
						Line::full(1, vec![Token::Not, Token::Not, Token::Char('P')], Token::from_str("¬I 1"), vec![0])],
			cursor: Cursor::new(),
		}
	}
	/// Gets a ref to the line numbered `v` in the proof.
	pub fn line(&'a self, v: usize) -> Option<&'a Line> {
		self.lines.get(v - 1)
	}
	/// Gets the number of lines in the proof.
	pub fn lines(&self) -> usize {
		self.lines.len()
	}
	/// Handles the input given to it, and whether to pass the input on or not.
	pub fn handle_input(&mut self, e: &EventKey) -> Inhibit {
		use gdk::enums::key;
		use gdk::{keyval_to_unicode, keyval_name};

		let c = keyval_to_unicode(e.keyval).unwrap_or(' ');
		let name = keyval_name(e.keyval).unwrap_or(" ".to_string());
		println!("keypress: {0:#08x} : {1} : {2}", e.keyval, c, name);

		match unsafe { mem::transmute(e.keyval) } {
			key::Right => {
				let _ = self.cursor.right(&self.lines);
			},
			key::Left => {
				let _ = self.cursor.left(&self.lines);
			},
			key::Return => {
				let _ = self.cursor.newline(&mut self.lines);
			},
			_ => {
				return Inhibit(false);
			},
		}
		println!(" *** Editor *** - Cursor: {:?} \n{:?}", self.cursor, self);
		Inhibit(true)
	}
}
impl Debug for Editor {
	fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
		for l in self.lines.iter() {
			try!(l.fmt_cursor(f, &self.cursor));
			try!(writeln!(f, ""));
		}
		Ok(())
	}
}
<commit_msg>Add delete key handling<commit_after>use std::fmt::{self, Write, Debug, Formatter};
use std::mem;
use std::ops::{Deref, DerefMut};

use gtk::signal::Inhibit;
use gdk::EventKey;

use logic::Token;

#[derive(Clone)]
pub struct Lines {
	inner: Vec<Line>
}
impl Lines {
	/// Creates a lines object with one line.
	pub fn new() -> Lines {
		Lines {
			inner: vec![Line::new(0)]
		}
	}
	/// Creates a lines object from a vector.
	pub fn from_vec(v: Vec<Line>) -> Lines {
		Lines {
			inner: v
		}
	}

	/// Inserts `nl` at `nl.no` in `lines`, and updates all line numbers in `lines`
	pub fn insert_line(&mut self, nl: Line) {
		let no = nl.no;
		for l in self.iter_mut() {
			if l.no >= no {
				l.no += 1;
			}
		}
		self.insert(no, nl);
	}
	/// Deletes the line at `no` in `lines`, and updates all line numbers in `lines`
	pub fn delete_line(&mut self, no: usize) {
		self.inner.remove(no);
		for l in self.iter_mut() {
			if l.no >= no {
				l.no -= 1;
			}
		}
	}
}
impl Deref for Lines {
	type Target = Vec<Line>;
	fn deref(&self) -> &Vec<Line> {
		&self.inner
	}
}
impl DerefMut for Lines {
	fn deref_mut(&mut self) -> &mut Vec<Line> {
		&mut self.inner
	}
}

#[derive(Clone)]
pub struct Line {
	/// The line number of the proof, starting at 0. It is only visually where everything is incremented
	pub no: usize,
	/// A step of the proof. e.g. (P^Q)->P. This is a vector of tokens that can be invalid.
	pub step: Vec<Token>,
	/// A token string representing the method of the proof.
	pub method: Vec<Token>,
	/// Line numbers that this depends on. Line numbers start at 0.
	pub deps: Vec<usize>,
}
impl Line {
	/// Constructs an empty line
	pub fn new(no: usize) -> Line {
		Line {
			no: no,
			step: Vec::new(),
			method: Vec::new(),
			deps: Vec::new(),
		}
	}
	/// Constructs a line with the specified tokens in the `step` field.
	pub fn with_step(no: usize, step: Vec<Token>) -> Line {
		Line {
			no: no,
			step: step,
			method: Vec::new(),
			deps: Vec::new(),
		}
	}
	pub fn full(no: usize, step: Vec<Token>, method: Vec<Token>, deps: Vec<usize>) -> Line {
		Line {
			no: no,
			step: step,
			method: method,
			deps: deps,
		}
	}

	pub fn fmt_cursor(&self, f: &mut Formatter, c: &Cursor) -> Result<(), fmt::Error> {
		let mut step_str = String::with_capacity(self.step.len() + 16);
		if !f.alternate() {
			for (i, t) in self.step.iter().enumerate() {
				if c.no == self.no && c.col == Col::Step && c.i == i {
					step_str.push('|');
				}
				try!(write!(step_str, "{}", t));
			}
		} else {
			for (i, t) in self.step.iter().enumerate() {
				if c.no == self.no && c.col == Col::Step && c.i == i {
					step_str.push('|');
				}
				try!(write!(step_str, "{:#}", t));
			}
		}
		if c.no == self.no && c.col == Col::Step && c.i == self.step.len() {
			step_str.push('|');
		}

		let mut dep_str = String::with_capacity(self.deps.len() * 2);
		for (i, dep) in self.deps.iter().enumerate() {
			try!(write!(dep_str, "{}", dep + 1));
			if i < self.deps.len() - 1 {
				dep_str.push_str(", ")
			}
		}

		let mut method_str = String::with_capacity(self.method.len() + 8);
		if c.no == self.no && c.col == Col::Method && (c.i <= self.method.len() || self.method.len() == 0) {
			let (a, b) = self.method.split_at(c.i);
			if !f.alternate() {
				for t in a {
					try!(write!(method_str, "{}", t));
				}
				method_str.push('|');
				for t in b {
					try!(write!(method_str, "{}", t));
				}
			} else {
				for t in a {
					try!(write!(method_str, "{:#}", t));
				}
				method_str.push('|');
				for t in b {
					try!(write!(method_str, "{:#}", t));
				}
			}
		} else {
			if !f.alternate() {
				for t in self.method.iter() {
					try!(write!(method_str, "{}", t));
				}
			} else {
				for t in self.method.iter() {
					try!(write!(method_str, "{:#}", t));
				}
			}
		}
		f.pad(&format!("{: >3}. {: <20} {: <10} {{{}}}", self.no + 1, step_str, method_str, dep_str))
	}

	/// True if `self.step` and `self.method` are empty
	pub fn is_empty(&self) -> bool {
		self.step.is_empty() && self.method.is_empty()
	}
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Col {
	Step,
	Method,
}
#[derive(Debug, PartialEq, Eq)]
pub struct Cursor {
	/// Line number
	no: usize,
	/// Column
	col: Col,
	/// Index of token/string
	i: usize,
}
impl Cursor {
	pub fn new() -> Cursor {
		Cursor {
			no: 0,
			col: Col::Step,
			i: 0,
		}
	}
	/// Move the cursor to the right. Wrap at end of line. Error at end of text.
	pub fn right(&mut self, lines: &[Line]) -> Result<(), ()> {
		let l = match lines.get(self.no) {
			Some(l) => l,
			None    => { *self = Cursor::new(); return Err(()); },
		};
		self.i += 1;
		match self.col {
			Col::Step => {
				if self.i > l.step.len() {
					self.col = Col::Method;
					self.i = 0;
				}
				Ok(())
			}
			Col::Method => {
				if self.i > l.method.len() {
					if self.no < lines.len() - 1 {
						self.no += 1;
						self.col = Col::Step;
						self.i = 0;
						Ok(())
					} else {
						self.i -= 1;
						Err(())
					}
				} else {
					Ok(())
				}
			}
		}
	}
	/// Move the cursor to the left. Wrap at start of line. Error at start of text.
	pub fn left(&mut self, lines: &[Line]) -> Result<(), ()> {
		let l = match lines.get(self.no) {
			Some(l) => l,
			None    => { *self = Cursor::new(); return Err(()); },
		};

		if self.i == 0 {
			match self.col {
				Col::Step => {
					if self.no > 0 {
						self.no -= 1;
						self.col = Col::Method;
						self.i = match lines.get(self.no) {
							Some(l) => l.method.len(),
							None    => { *self = Cursor::new(); return Err(()); },
						};
					}
				}
				Col::Method => {
					self.col = Col::Step;
					self.i = l.step.len();
				}
			}
		} else {
			self.i -= 1;
		}
		Ok(())
	}

	/// Returns true if at the end of `Col::Step` or `Col::Method`
	fn is_eol(&self, lines: &Lines) -> bool {
		self.i == match self.col {
			Col::Step   => lines[self.no].step.len(),
			Col::Method => lines[self.no].method.len(),
		}
	}

	/// Delete the character in front of the cursor. If on an empty line && at the en, delete line. If no chars in front, error.
	pub fn delete(&mut self, lines: &mut Lines) -> Result<(), ()> {
		if lines[self.no].is_empty() && self.col == Col::Method {
			if lines.len() == 1 {
				return Err(());
			}
			// Delete the line
			lines.delete_line(self.no);

			if self.no != 0 { self.no -= 1; };
			self.i = 0;

			Ok(())
		} else if self.is_eol(lines) {
			Err(())
		} else {
			// Delete char in front
			match self.col {
				Col::Step   => { let _ = lines[self.no].step.remove(self.i); },
				Col::Method => { let _ = lines[self.no].method.remove(self.i); },
			}
			Ok(())
		}
	}
	/// Add a newline to `lines` if the cursor is at the end of the line.
	pub fn newline(&mut self, lines: &mut Lines) -> Result<(), ()> {
		if !self.is_eol(lines) {
			// Don't place a newline if the cursor isn't at the end of the line.
			return Err(());
		}

		lines.insert_line(Line::new(self.no + 1));

		self.no += 1;
		self.i = 0;

		Ok(())
	}
}

pub struct Editor {
	lines: Lines,
	cursor: Cursor,
}

impl<'a> Editor {
	/// Constructs a new editor
	pub fn new() -> Editor {
		Editor {
			lines: Lines::from_vec(vec![Line::full(0, vec![Token::Char('P')], Token::from_str("Premise"), vec![0]),
						Line::full(1, vec![Token::Not, Token::Not, Token::Char('P')], Token::from_str("¬I 1"), vec![0])]),
			cursor: Cursor::new(),
		}
	}
	/// Gets a ref to the line numbered `v` in the proof.
	pub fn line(&'a self, v: usize) -> Option<&'a Line> {
		self.lines.get(v - 1)
	}
	/// Gets the number of lines in the proof.
	pub fn lines(&self) -> usize {
		self.lines.len()
	}
	/// Handles the input given to it, and whether to pass the input on or not.
	pub fn handle_input(&mut self, e: &EventKey) -> Inhibit {
		use gdk::enums::key;
		use gdk::{keyval_to_unicode, keyval_name};

		let c = keyval_to_unicode(e.keyval).unwrap_or(' ');
		let name = keyval_name(e.keyval).unwrap_or(" ".to_string());
		println!("keypress: {0:#08x} : {1} : {2}", e.keyval, c, name);

		match unsafe { mem::transmute(e.keyval) } {
			key::Right => {
				let _ = self.cursor.right(&self.lines);
			},
			key::Left => {
				let _ = self.cursor.left(&self.lines);
			},
			key::Delete => {
				let _ = self.cursor.delete(&mut self.lines);
			},
			key::Return => {
				let _ = self.cursor.newline(&mut self.lines);
			},
			_ => {
				return Inhibit(false);
			},
		}
		println!(" *** Editor *** - Cursor: {:?} \n{:?}", self.cursor, self);
		Inhibit(true)
	}
}
impl Debug for Editor {
	fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
		for l in self.lines.iter() {
			try!(l.fmt_cursor(f, &self.cursor));
			try!(writeln!(f, ""));
		}
		Ok(())
	}
}
<|endoftext|>


<commit_before>// boolean_expression: a Rust crate for Boolean expressions and BDDs.
//
// Copyright (c) 2016 Chris Fallin <cfallin@c1f.net>. Released under the MIT
// License.
//

use std::cmp::Ord;
use std::collections::HashMap;
use std::fmt::Debug;
use std::hash::Hash;
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, Not};

use simplify;

/// An `Expr` is a simple Boolean logic expression. It may contain terminals
/// (i.e., free variables), constants, and the following fundamental operations:
/// AND, OR, NOT.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Expr<T>
where
    T: Clone + Debug + Eq + Hash,
{
    /// A terminal (free variable). This expression node represents a value that
    /// is not known until evaluation time.
    Terminal(T),
    /// A boolean constant: true or false.
    Const(bool),

    /// The logical complement of the contained expression argument.
    Not(Box<Expr<T>>),

    /// The logical AND of the two expression arguments.
    And(Box<Expr<T>>, Box<Expr<T>>),

    /// The logical OR of the two expression arguments.
    Or(Box<Expr<T>>, Box<Expr<T>>),
}

impl<T> Expr<T>
where
    T: Clone + Debug + Eq + Hash,
{
    /// Returns `true` if this `Expr` is a terminal.
    pub fn is_terminal(&self) -> bool {
        match self {
            &Expr::Terminal(_) => true,
            _ => false,
        }
    }

    /// Returns `true` if this `Expr` is a constant.
    pub fn is_const(&self) -> bool {
        match self {
            &Expr::Const(_) => true,
            _ => false,
        }
    }

    /// Returns `true` if this `Expr` is a NOT node.
    pub fn is_not(&self) -> bool {
        match self {
            &Expr::Not(_) => true,
            _ => false,
        }
    }

    /// Returns `true` if this `Expr` is an AND node.
    pub fn is_and(&self) -> bool {
        match self {
            &Expr::And(_, _) => true,
            _ => false,
        }
    }

    /// Returns `true` if this `Expr` is an OR node.
    pub fn is_or(&self) -> bool {
        match self {
            &Expr::Or(_, _) => true,
            _ => false,
        }
    }

    /// Builds a NOT node around an argument, consuming the argument
    /// expression.
    pub fn not(e: Expr<T>) -> Expr<T> {
        Expr::Not(Box::new(e))
    }

    /// Builds an AND node around two arguments, consuming the argument
    /// expressions.
    pub fn and(e1: Expr<T>, e2: Expr<T>) -> Expr<T> {
        Expr::And(Box::new(e1), Box::new(e2))
    }

    /// Builds an OR node around two arguments, consuming the argument
    /// expressions.
    pub fn or(e1: Expr<T>, e2: Expr<T>) -> Expr<T> {
        Expr::Or(Box::new(e1), Box::new(e2))
    }

    /// Evaluates the expression with a particular set of terminal assignments.
    /// If any terminals are not assigned, they default to `false`.
    pub fn evaluate(&self, vals: &HashMap<T, bool>) -> bool {
        match self {
            &Expr::Terminal(ref t) => *vals.get(t).unwrap_or(&false),
            &Expr::Const(val) => val,
            &Expr::And(ref a, ref b) => a.evaluate(vals) && b.evaluate(vals),
            &Expr::Or(ref a, ref b) => a.evaluate(vals) || b.evaluate(vals),
            &Expr::Not(ref x) => !x.evaluate(vals),
        }
    }

    /// Simplify an expression in a relatively cheap way using well-known logic
    /// identities.
    ///
    /// This function performs certain reductions using DeMorgan's Law,
    /// distribution of ANDs over ORs, and certain identities involving
    /// constants, to simplify an expression. The result will always be in
    /// sum-of-products form: nodes will always appear in order (from
    /// expression tree root to leaves) `OR -> AND -> NOT`. In other words,
    /// `AND` nodes may only have `NOT` nodes (or terminals or constants) as
    /// children, and `NOT` nodes may only have terminals or constants as
    /// children.
    ///
    /// This function explicitly does *not* perform any sort of minterm reduction.
    /// The terms may thus be redundant (i.e., `And(a, b)` may appear twice), and
    /// combinable terms may exist (i.e., `And(a, b)` and `And(a, Not(b))` may
    /// appear in the `OR`'d list of terms, where these could be combined to
    /// simply `a` but are not). For example:
    ///
    /// ```
    /// use boolean_expression::Expr;
    ///
    /// // This simplifies using DeMorgan's Law:
    /// let expr = Expr::not(Expr::or(Expr::Terminal(0), Expr::Terminal(1)));
    /// let simplified = expr.simplify_via_laws();
    /// assert_eq!(simplified,
    ///     Expr::and(Expr::not(Expr::Terminal(0)),
    ///               Expr::not(Expr::Terminal(1))));
    ///
    /// // This doesn't simplify, though:
    /// let expr = Expr::or(
    ///             Expr::and(Expr::Terminal(0), Expr::Terminal(1)),
    ///             Expr::and(Expr::Terminal(0), Expr::not(Expr::Terminal(1))));
    /// let simplified = expr.clone().simplify_via_laws();
    /// assert_eq!(simplified, expr);
    /// ```
    ///
    /// For better (but more expensive) simplification, see `simplify_via_bdd()`.
    pub fn simplify_via_laws(self) -> Expr<T> {
        simplify::simplify_via_laws(self)
    }

    /// Simplify an expression via a roundtrip through a `BDD`. This procedure
    /// is more effective than `Expr::simplify_via_laws()`, but more expensive.
    /// This roundtrip will implicitly simplify an arbitrarily complicated
    /// function (by construction, as the BDD is built), and then find a
    /// quasi-minimal set of terms using cubelist-based reduction. For example:
    ///
    /// ```
    /// use boolean_expression::Expr;
    ///
    /// // `simplify_via_laws()` cannot combine these terms, but
    /// // `simplify_via_bdd()` will:
    /// let expr = Expr::or(
    ///             Expr::and(Expr::Terminal(0), Expr::Terminal(1)),
    ///             Expr::and(Expr::Terminal(0), Expr::not(Expr::Terminal(1))));
    /// let simplified = expr.simplify_via_bdd();
    /// assert_eq!(simplified, Expr::Terminal(0));
    /// ```
    pub fn simplify_via_bdd(self) -> Expr<T> {
        simplify::simplify_via_bdd(self)
    }

    /// Map terminal values using the specified mapping function.
    pub fn map<F, R>(&self, f: F) -> Expr<R>
    where
        F: Fn(&T) -> R,
        R: Clone + Debug + Eq + Hash,
    {
        self.map1(&f)
    }

    fn map1<F, R>(&self, f: &F) -> Expr<R>
    where
        F: Fn(&T) -> R,
        R: Clone + Debug + Eq + Hash,
    {
        match self {
            &Expr::Terminal(ref t) => Expr::Terminal(f(t)),
            &Expr::Const(val) => Expr::Const(val),
            &Expr::Not(ref n) => Expr::not(n.map1(f)),
            &Expr::And(ref a, ref b) => Expr::and(a.map1(f), b.map1(f)),
            &Expr::Or(ref a, ref b) => Expr::or(a.map1(f), b.map1(f)),
        }
    }
}

impl<T> Not for Expr<T>
where
    T: Clone + Debug + Eq + Hash,
{
    type Output = Self;

    fn not(self) -> Self::Output {
        Self::not(self)
    }
}

impl<T> BitAnd<Expr<T>> for Expr<T>
where
    T: Clone + Debug + Eq + Hash,
{
    type Output = Self;

    fn bitand(self, rhs: Expr<T>) -> Self::Output {
        Self::and(self, rhs)
    }
}

impl<T> BitAndAssign<Expr<T>> for Expr<T>
where
    T: Clone + Debug + Eq + Hash,
{
    fn bitand_assign(&mut self, rhs: Expr<T>) {
        *self = Self::and(self.clone(), rhs);
    }
}

impl<T> BitOr<Expr<T>> for Expr<T>
where
    T: Clone + Debug + Eq + Hash,
{
    type Output = Self;

    fn bitor(self, rhs: Expr<T>) -> Self::Output {
        Self::or(self, rhs)
    }
}

impl<T> BitOrAssign<Expr<T>> for Expr<T>
where
    T: Clone + Debug + Eq + Hash,
{
    fn bitor_assign(&mut self, rhs: Expr<T>) {
        *self = Self::or(self.clone(), rhs);
    }
}
<commit_msg>Implement xor gate<commit_after>// boolean_expression: a Rust crate for Boolean expressions and BDDs.
//
// Copyright (c) 2016 Chris Fallin <cfallin@c1f.net>. Released under the MIT
// License.
//

use std::cmp::Ord;
use std::collections::HashMap;
use std::fmt::Debug;
use std::hash::Hash;
use std::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};

use simplify;

/// An `Expr` is a simple Boolean logic expression. It may contain terminals
/// (i.e., free variables), constants, and the following fundamental operations:
/// AND, OR, NOT.
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Expr<T>
where
    T: Clone + Debug + Eq + Hash,
{
    /// A terminal (free variable). This expression node represents a value that
    /// is not known until evaluation time.
    Terminal(T),
    /// A boolean constant: true or false.
    Const(bool),

    /// The logical complement of the contained expression argument.
    Not(Box<Expr<T>>),

    /// The logical AND of the two expression arguments.
    And(Box<Expr<T>>, Box<Expr<T>>),

    /// The logical OR of the two expression arguments.
    Or(Box<Expr<T>>, Box<Expr<T>>),
}

impl<T> Expr<T>
where
    T: Clone + Debug + Eq + Hash,
{
    /// Returns `true` if this `Expr` is a terminal.
    pub fn is_terminal(&self) -> bool {
        match self {
            &Expr::Terminal(_) => true,
            _ => false,
        }
    }

    /// Returns `true` if this `Expr` is a constant.
    pub fn is_const(&self) -> bool {
        match self {
            &Expr::Const(_) => true,
            _ => false,
        }
    }

    /// Returns `true` if this `Expr` is a NOT node.
    pub fn is_not(&self) -> bool {
        match self {
            &Expr::Not(_) => true,
            _ => false,
        }
    }

    /// Returns `true` if this `Expr` is an AND node.
    pub fn is_and(&self) -> bool {
        match self {
            &Expr::And(_, _) => true,
            _ => false,
        }
    }

    /// Returns `true` if this `Expr` is an OR node.
    pub fn is_or(&self) -> bool {
        match self {
            &Expr::Or(_, _) => true,
            _ => false,
        }
    }

    /// Builds a NOT node around an argument, consuming the argument
    /// expression.
    pub fn not(e: Expr<T>) -> Expr<T> {
        Expr::Not(Box::new(e))
    }

    /// Builds an AND node around two arguments, consuming the argument
    /// expressions.
    pub fn and(e1: Expr<T>, e2: Expr<T>) -> Expr<T> {
        Expr::And(Box::new(e1), Box::new(e2))
    }

    /// Builds an OR node around two arguments, consuming the argument
    /// expressions.
    pub fn or(e1: Expr<T>, e2: Expr<T>) -> Expr<T> {
        Expr::Or(Box::new(e1), Box::new(e2))
    }

    pub fn xor(e1: Expr<T>, e2: Expr<T>) -> Expr<T> {
        let nand = !(e1.clone() & e2.clone());
        let or = e1 | e2;
        nand & or
    }

    /// Evaluates the expression with a particular set of terminal assignments.
    /// If any terminals are not assigned, they default to `false`.
    pub fn evaluate(&self, vals: &HashMap<T, bool>) -> bool {
        match self {
            &Expr::Terminal(ref t) => *vals.get(t).unwrap_or(&false),
            &Expr::Const(val) => val,
            &Expr::And(ref a, ref b) => a.evaluate(vals) && b.evaluate(vals),
            &Expr::Or(ref a, ref b) => a.evaluate(vals) || b.evaluate(vals),
            &Expr::Not(ref x) => !x.evaluate(vals),
        }
    }

    /// Simplify an expression in a relatively cheap way using well-known logic
    /// identities.
    ///
    /// This function performs certain reductions using DeMorgan's Law,
    /// distribution of ANDs over ORs, and certain identities involving
    /// constants, to simplify an expression. The result will always be in
    /// sum-of-products form: nodes will always appear in order (from
    /// expression tree root to leaves) `OR -> AND -> NOT`. In other words,
    /// `AND` nodes may only have `NOT` nodes (or terminals or constants) as
    /// children, and `NOT` nodes may only have terminals or constants as
    /// children.
    ///
    /// This function explicitly does *not* perform any sort of minterm reduction.
    /// The terms may thus be redundant (i.e., `And(a, b)` may appear twice), and
    /// combinable terms may exist (i.e., `And(a, b)` and `And(a, Not(b))` may
    /// appear in the `OR`'d list of terms, where these could be combined to
    /// simply `a` but are not). For example:
    ///
    /// ```
    /// use boolean_expression::Expr;
    ///
    /// // This simplifies using DeMorgan's Law:
    /// let expr = Expr::not(Expr::or(Expr::Terminal(0), Expr::Terminal(1)));
    /// let simplified = expr.simplify_via_laws();
    /// assert_eq!(simplified,
    ///     Expr::and(Expr::not(Expr::Terminal(0)),
    ///               Expr::not(Expr::Terminal(1))));
    ///
    /// // This doesn't simplify, though:
    /// let expr = Expr::or(
    ///             Expr::and(Expr::Terminal(0), Expr::Terminal(1)),
    ///             Expr::and(Expr::Terminal(0), Expr::not(Expr::Terminal(1))));
    /// let simplified = expr.clone().simplify_via_laws();
    /// assert_eq!(simplified, expr);
    /// ```
    ///
    /// For better (but more expensive) simplification, see `simplify_via_bdd()`.
    pub fn simplify_via_laws(self) -> Expr<T> {
        simplify::simplify_via_laws(self)
    }

    /// Simplify an expression via a roundtrip through a `BDD`. This procedure
    /// is more effective than `Expr::simplify_via_laws()`, but more expensive.
    /// This roundtrip will implicitly simplify an arbitrarily complicated
    /// function (by construction, as the BDD is built), and then find a
    /// quasi-minimal set of terms using cubelist-based reduction. For example:
    ///
    /// ```
    /// use boolean_expression::Expr;
    ///
    /// // `simplify_via_laws()` cannot combine these terms, but
    /// // `simplify_via_bdd()` will:
    /// let expr = Expr::or(
    ///             Expr::and(Expr::Terminal(0), Expr::Terminal(1)),
    ///             Expr::and(Expr::Terminal(0), Expr::not(Expr::Terminal(1))));
    /// let simplified = expr.simplify_via_bdd();
    /// assert_eq!(simplified, Expr::Terminal(0));
    /// ```
    pub fn simplify_via_bdd(self) -> Expr<T> {
        simplify::simplify_via_bdd(self)
    }

    /// Map terminal values using the specified mapping function.
    pub fn map<F, R>(&self, f: F) -> Expr<R>
    where
        F: Fn(&T) -> R,
        R: Clone + Debug + Eq + Hash,
    {
        self.map1(&f)
    }

    fn map1<F, R>(&self, f: &F) -> Expr<R>
    where
        F: Fn(&T) -> R,
        R: Clone + Debug + Eq + Hash,
    {
        match self {
            &Expr::Terminal(ref t) => Expr::Terminal(f(t)),
            &Expr::Const(val) => Expr::Const(val),
            &Expr::Not(ref n) => Expr::not(n.map1(f)),
            &Expr::And(ref a, ref b) => Expr::and(a.map1(f), b.map1(f)),
            &Expr::Or(ref a, ref b) => Expr::or(a.map1(f), b.map1(f)),
        }
    }
}

impl<T> Not for Expr<T>
where
    T: Clone + Debug + Eq + Hash,
{
    type Output = Self;

    fn not(self) -> Self::Output {
        Self::not(self)
    }
}

impl<T> BitAnd<Expr<T>> for Expr<T>
where
    T: Clone + Debug + Eq + Hash,
{
    type Output = Self;

    fn bitand(self, rhs: Expr<T>) -> Self::Output {
        Self::and(self, rhs)
    }
}

impl<T> BitAndAssign<Expr<T>> for Expr<T>
where
    T: Clone + Debug + Eq + Hash,
{
    fn bitand_assign(&mut self, rhs: Expr<T>) {
        *self = Self::and(self.clone(), rhs);
    }
}

impl<T> BitOr<Expr<T>> for Expr<T>
where
    T: Clone + Debug + Eq + Hash,
{
    type Output = Self;

    fn bitor(self, rhs: Expr<T>) -> Self::Output {
        Self::or(self, rhs)
    }
}

impl<T> BitOrAssign<Expr<T>> for Expr<T>
where
    T: Clone + Debug + Eq + Hash,
{
    fn bitor_assign(&mut self, rhs: Expr<T>) {
        *self = Self::or(self.clone(), rhs);
    }
}

impl<T> BitXor<Expr<T>> for Expr<T>
where
    T: Clone + Debug + Eq + Hash,
{
    type Output = Self;

    fn bitxor(self, rhs: Expr<T>) -> Self::Output {
        Self::xor(self, rhs)
    }
}

impl<T> BitXorAssign<Expr<T>> for Expr<T>
where
    T: Clone + Debug + Eq + Hash,
{
    fn bitxor_assign(&mut self, rhs: Expr<T>) {
        *self = Self::xor(self.clone(), rhs);
    }
}
<|endoftext|>


<commit_before>use specs::*;
use templating::*;

use handlebars::{self, Handlebars, HelperDef};
use itertools::Itertools;
use std::collections::BTreeMap;

pub struct CodeGenerator {
    specs:      AMQProtocolDefinition,
    handlebars: Handlebars,
}

impl CodeGenerator {
    pub fn new(specs: AMQProtocolDefinition, templates: AMQPTemplates) -> CodeGenerator {
        let mut handlebars = Handlebars::new();

        handlebars.register_escape_fn(handlebars::no_escape);

        handlebars.register_helper("camel", Box::new(camel_helper));
        handlebars.register_helper("snake", Box::new(snake_helper));

        handlebars.register_template_string("main",     &templates.main).expect("Failed to register main template");
        handlebars.register_template_string("domain",   &templates.domain).expect("Failed to register domain template");
        handlebars.register_template_string("constant", &templates.constant).expect("Failed to register constant template");
        handlebars.register_template_string("class",    &templates.klass).expect("Failed to register class template");
        handlebars.register_template_string("method",   &templates.method).expect("Failed to register method template");
        handlebars.register_template_string("argument", &templates.argument).expect("Failed to register argument template");
        handlebars.register_template_string("property", &templates.property).expect("Failed to register property template");

        CodeGenerator {
            specs:      specs,
            handlebars: handlebars,
        }
    }

    pub fn with_helper(mut self, name: &str, helper: Box<HelperDef + 'static>) -> CodeGenerator {
        self.handlebars.register_helper(name, helper);
        self
    }

    pub fn with_template(mut self, name: &str, template: &str) -> CodeGenerator {
        self.handlebars.register_template_string(name, template).expect(&format!("Failed to register {} template", name));
        self
    }

    pub fn generate(&self) -> String {
        self.generate_from_template_name("main")
    }

    pub fn generate_from_template_name(&self, name: &str) -> String {
        self.handlebars.render(name, &AMQProtocolDefinitionWrapper {
            protocol:  &self.specs,
            copyright: self.specs.copyright.iter().join(""),
            domains:   self.specs.domains.iter().map(|domain| domain.codegen(&self.handlebars)).join("\n"),
            constants: self.specs.constants.iter().map(|constant| constant.codegen(&self.handlebars)).join("\n"),
            classes:   self.specs.classes.iter().map(|klass| klass.codegen(&self.handlebars)).join("\n"),
        }).expect(&format!("Failed to render {} template", name))
    }

    pub fn get_handlebars(&mut self) -> &mut Handlebars {
        &mut self.handlebars
    }
}

#[derive(Debug, Serialize)]
struct AMQProtocolDefinitionWrapper<'a> {
    protocol : &'a AMQProtocolDefinition,
    copyright: String,
    domains:   String,
    constants: String,
    classes:   String,
}

pub trait Codegen {
    fn codegen(&self, handlebars: &Handlebars) -> String;
}

trait BasicGetData {
    fn get_data(&self, handlebars: &Handlebars) -> BTreeMap<String, &Self>;
}

trait ClassGetData {
    fn get_data(&self, handlebars: &Handlebars) -> AMQPClassWrapper;
}

trait MethodGetData {
    fn get_data(&self, handlebars: &Handlebars) -> AMQPMethodWrapper;
}

macro_rules! get_data {
    ($t:ty, $key:expr) => {
        impl BasicGetData for $t {
            #[allow(unused_variables)]
            fn get_data(&self, handlebars: &Handlebars) -> BTreeMap<String, &Self> {
                let mut data = BTreeMap::new();
                data.insert($key.to_string(), self);
                data
            }
        }
    }
}

#[derive(Debug, Serialize)]
struct AMQPClassWrapper<'a> {
    #[serde(rename="class")]
    klass:      &'a AMQPClass,
    methods:    String,
    properties: Option<String>,
}

impl ClassGetData for AMQPClass {
    fn get_data(&self, handlebars: &Handlebars) -> AMQPClassWrapper {
        AMQPClassWrapper {
            klass:      self,
            methods:    self.methods.iter().map(|method| method.codegen(&handlebars)).join("\n"),
            properties: match self.properties {
                Some(ref properties) => Some(properties.iter().map(|method| method.codegen(&handlebars)).join("\n")),
                None                 => None,
            },
        }
    }
}

#[derive(Debug, Serialize)]
struct AMQPMethodWrapper<'a> {
    method:    &'a AMQPMethod,
    arguments: String,
}

impl MethodGetData for AMQPMethod {
    fn get_data(&self, handlebars: &Handlebars) -> AMQPMethodWrapper {
        AMQPMethodWrapper {
            method:    self,
            arguments: self.arguments.iter().map(|arg| arg.codegen(&handlebars)).join("\n"),
        }
    }
}

get_data!(AMQPDomain,   "domain");
get_data!(AMQPConstant, "constant");
get_data!(AMQPArgument, "argument");
get_data!(AMQPProperty, "property");

macro_rules! codegen {
    ($t:ty, $name:expr) => {
        impl Codegen for $t {
            fn codegen (&self, handlebars: &Handlebars) -> String {
                handlebars.render($name, &self.get_data(handlebars)).expect(&format!("Failed to render {} template", $name))
            }
        }
    };
}

codegen!(AMQPDomain,   "domain");
codegen!(AMQPConstant, "constant");
codegen!(AMQPClass,    "class");
codegen!(AMQPMethod,   "method");
codegen!(AMQPArgument, "argument");
codegen!(AMQPProperty, "property");

#[cfg(test)]
mod test {
    use super::*;

    use amq_protocol_types::*;
    use serde_json::Value;
    use templating::AMQPTemplates;

    fn specs() -> AMQProtocolDefinition {
        AMQProtocolDefinition {
            name:          "AMQP".to_string(),
            major_version: 0,
            minor_version: 9,
            revision:      1,
            port:          5672,
            copyright:     vec!["Copyright 1\n".to_string(), "Copyright 2".to_string()],
            domains:       vec![
                AMQPDomain{
                    name:      "domain1".to_string(),
                    amqp_type: AMQPType::ShortInt
                }
            ],
            constants:     vec![
                AMQPConstant {
                    name:  "constant1".to_string(),
                    value: 128,
                    klass: Some("class1".to_string()),
                }
            ],
            classes:       vec![
                AMQPClass {
                    id:         42,
                    methods:    vec![
                        AMQPMethod {
                            id:          64,
                            arguments:   vec![
                                AMQPArgument {
                                    amqp_type:     Some(AMQPType::LongString),
                                    name:          "argument1".to_string(),
                                    default_value: Some(Value::String("value1".to_string())),
                                    domain:        Some("domain1".to_string()),
                                }
                            ],
                            name:        "method1".to_string(),
                            synchronous: Some(true),
                        }
                    ],
                    name:       "class1".to_string(),
                    properties: Some(vec![
                        AMQPProperty {
                            amqp_type: AMQPType::LongString,
                            name:      "property1".to_string(),
                        }
                    ]),
                }
            ],
        }
    }

    fn templates() -> AMQPTemplates {
        AMQPTemplates {
            main:     r#"
{{protocol.name}} - {{protocol.major_version}}.{{protocol.minor_version}}.{{protocol.revision}}
{{copyright}}
port {{protocol.port}}
{{domains}}
{{constants}}
{{classes}}
"#.to_string(),
            domain:   "{{domain.name}}: {{domain.type}}".to_string(),
            constant: "{{constant.name}}({{constant.class}}) = {{constant.value}}".to_string(),
            klass:    r#"
{{class.id}} - {{class.name}}
{{properties}}
{{methods}}
"#.to_string(),
            method:   r#"
{{method.id}} - {{method.name}}
synchronous: {{method.synchronous}}
{{arguments}}
"#.to_string(),
            argument: "{{argument.name}}({{argument.domain}}): {{argument.type}}".to_string(),
            property: "{{property.name}}: {{property.type}}".to_string(),
        }
    }

    #[test]
    fn main_template() {
        assert_eq!(specs().code_generator(templates()).generate(), r#"
AMQP - 0.9.1
Copyright 1
Copyright 2
port 5672
domain1: ShortInt
constant1(class1) = 128

42 - class1
property1: LongString

64 - method1
synchronous: true
argument1(domain1): LongString

"#);
    }
}
<commit_msg>codegen: allow customizing handlbars freely<commit_after>use specs::*;
use templating::*;

use handlebars::{self, Handlebars};
use itertools::Itertools;
use std::collections::BTreeMap;

pub struct CodeGenerator {
    specs:      AMQProtocolDefinition,
    handlebars: Handlebars,
}

impl CodeGenerator {
    pub fn new(specs: AMQProtocolDefinition, templates: AMQPTemplates) -> CodeGenerator {
        let mut handlebars = Handlebars::new();

        handlebars.register_escape_fn(handlebars::no_escape);

        handlebars.register_helper("camel", Box::new(camel_helper));
        handlebars.register_helper("snake", Box::new(snake_helper));

        handlebars.register_template_string("main",     &templates.main).expect("Failed to register main template");
        handlebars.register_template_string("domain",   &templates.domain).expect("Failed to register domain template");
        handlebars.register_template_string("constant", &templates.constant).expect("Failed to register constant template");
        handlebars.register_template_string("class",    &templates.klass).expect("Failed to register class template");
        handlebars.register_template_string("method",   &templates.method).expect("Failed to register method template");
        handlebars.register_template_string("argument", &templates.argument).expect("Failed to register argument template");
        handlebars.register_template_string("property", &templates.property).expect("Failed to register property template");

        CodeGenerator {
            specs:      specs,
            handlebars: handlebars,
        }
    }

    pub fn customize<F>(mut self, mut customize_fn: F) -> CodeGenerator
            where F: FnMut(&mut Handlebars) {
        customize_fn(&mut self.handlebars);
        self
    }

    pub fn generate(&self) -> String {
        self.generate_from_template_name("main")
    }

    pub fn generate_from_template_name(&self, name: &str) -> String {
        self.handlebars.render(name, &AMQProtocolDefinitionWrapper {
            protocol:  &self.specs,
            copyright: self.specs.copyright.iter().join(""),
            domains:   self.specs.domains.iter().map(|domain| domain.codegen(&self.handlebars)).join("\n"),
            constants: self.specs.constants.iter().map(|constant| constant.codegen(&self.handlebars)).join("\n"),
            classes:   self.specs.classes.iter().map(|klass| klass.codegen(&self.handlebars)).join("\n"),
        }).expect(&format!("Failed to render {} template", name))
    }
}

#[derive(Debug, Serialize)]
struct AMQProtocolDefinitionWrapper<'a> {
    protocol : &'a AMQProtocolDefinition,
    copyright: String,
    domains:   String,
    constants: String,
    classes:   String,
}

pub trait Codegen {
    fn codegen(&self, handlebars: &Handlebars) -> String;
}

trait BasicGetData {
    fn get_data(&self, handlebars: &Handlebars) -> BTreeMap<String, &Self>;
}

trait ClassGetData {
    fn get_data(&self, handlebars: &Handlebars) -> AMQPClassWrapper;
}

trait MethodGetData {
    fn get_data(&self, handlebars: &Handlebars) -> AMQPMethodWrapper;
}

macro_rules! get_data {
    ($t:ty, $key:expr) => {
        impl BasicGetData for $t {
            #[allow(unused_variables)]
            fn get_data(&self, handlebars: &Handlebars) -> BTreeMap<String, &Self> {
                let mut data = BTreeMap::new();
                data.insert($key.to_string(), self);
                data
            }
        }
    }
}

#[derive(Debug, Serialize)]
struct AMQPClassWrapper<'a> {
    #[serde(rename="class")]
    klass:      &'a AMQPClass,
    methods:    String,
    properties: Option<String>,
}

impl ClassGetData for AMQPClass {
    fn get_data(&self, handlebars: &Handlebars) -> AMQPClassWrapper {
        AMQPClassWrapper {
            klass:      self,
            methods:    self.methods.iter().map(|method| method.codegen(&handlebars)).join("\n"),
            properties: match self.properties {
                Some(ref properties) => Some(properties.iter().map(|method| method.codegen(&handlebars)).join("\n")),
                None                 => None,
            },
        }
    }
}

#[derive(Debug, Serialize)]
struct AMQPMethodWrapper<'a> {
    method:    &'a AMQPMethod,
    arguments: String,
}

impl MethodGetData for AMQPMethod {
    fn get_data(&self, handlebars: &Handlebars) -> AMQPMethodWrapper {
        AMQPMethodWrapper {
            method:    self,
            arguments: self.arguments.iter().map(|arg| arg.codegen(&handlebars)).join("\n"),
        }
    }
}

get_data!(AMQPDomain,   "domain");
get_data!(AMQPConstant, "constant");
get_data!(AMQPArgument, "argument");
get_data!(AMQPProperty, "property");

macro_rules! codegen {
    ($t:ty, $name:expr) => {
        impl Codegen for $t {
            fn codegen (&self, handlebars: &Handlebars) -> String {
                handlebars.render($name, &self.get_data(handlebars)).expect(&format!("Failed to render {} template", $name))
            }
        }
    };
}

codegen!(AMQPDomain,   "domain");
codegen!(AMQPConstant, "constant");
codegen!(AMQPClass,    "class");
codegen!(AMQPMethod,   "method");
codegen!(AMQPArgument, "argument");
codegen!(AMQPProperty, "property");

#[cfg(test)]
mod test {
    use super::*;

    use amq_protocol_types::*;
    use serde_json::Value;
    use templating::AMQPTemplates;

    fn specs() -> AMQProtocolDefinition {
        AMQProtocolDefinition {
            name:          "AMQP".to_string(),
            major_version: 0,
            minor_version: 9,
            revision:      1,
            port:          5672,
            copyright:     vec!["Copyright 1\n".to_string(), "Copyright 2".to_string()],
            domains:       vec![
                AMQPDomain{
                    name:      "domain1".to_string(),
                    amqp_type: AMQPType::ShortInt
                }
            ],
            constants:     vec![
                AMQPConstant {
                    name:  "constant1".to_string(),
                    value: 128,
                    klass: Some("class1".to_string()),
                }
            ],
            classes:       vec![
                AMQPClass {
                    id:         42,
                    methods:    vec![
                        AMQPMethod {
                            id:          64,
                            arguments:   vec![
                                AMQPArgument {
                                    amqp_type:     Some(AMQPType::LongString),
                                    name:          "argument1".to_string(),
                                    default_value: Some(Value::String("value1".to_string())),
                                    domain:        Some("domain1".to_string()),
                                }
                            ],
                            name:        "method1".to_string(),
                            synchronous: Some(true),
                        }
                    ],
                    name:       "class1".to_string(),
                    properties: Some(vec![
                        AMQPProperty {
                            amqp_type: AMQPType::LongString,
                            name:      "property1".to_string(),
                        }
                    ]),
                }
            ],
        }
    }

    fn templates() -> AMQPTemplates {
        AMQPTemplates {
            main:     r#"
{{protocol.name}} - {{protocol.major_version}}.{{protocol.minor_version}}.{{protocol.revision}}
{{copyright}}
port {{protocol.port}}
{{domains}}
{{constants}}
{{classes}}
"#.to_string(),
            domain:   "{{domain.name}}: {{domain.type}}".to_string(),
            constant: "{{constant.name}}({{constant.class}}) = {{constant.value}}".to_string(),
            klass:    r#"
{{class.id}} - {{class.name}}
{{properties}}
{{methods}}
"#.to_string(),
            method:   r#"
{{method.id}} - {{method.name}}
synchronous: {{method.synchronous}}
{{arguments}}
"#.to_string(),
            argument: "{{argument.name}}({{argument.domain}}): {{argument.type}}".to_string(),
            property: "{{property.name}}: {{property.type}}".to_string(),
        }
    }

    #[test]
    fn main_template() {
        assert_eq!(specs().code_generator(templates()).generate(), r#"
AMQP - 0.9.1
Copyright 1
Copyright 2
port 5672
domain1: ShortInt
constant1(class1) = 128

42 - class1
property1: LongString

64 - method1
synchronous: true
argument1(domain1): LongString

"#);
    }
}
<|endoftext|>


<commit_before>//! Module for working with `Function`s
//!
//! This module contains a type alias for `Rc<Fn(f64) -> f64>`,
//! which is used in many other modules, and functions for
//! working with the alias.

pub use std::rc::Rc;

/// Type alias used to represent functions.
///
/// Functions are stored in an `Rc` so they can be `cloned()`
/// and subsequently consumed in other functions.
pub type Function = Rc<Fn(f64) -> f64>;

/// Macro for creating a `Function`.
///
/// More idiomatic than calling `Rc::new()`.
///
/// # Examples
///
/// ```
/// # #[macro_use]
/// # extern crate reikna;
/// # fn main() {
/// use reikna::func::*;
/// let f = func!(|x| x * x);
/// assert_eq!(f(5), 25);
/// # }
/// ```
#[macro_export]
macro_rules! func {
    ($e:expr) => (Rc::new($e));
}
<commit_msg>improve func! macro and func.rs docs<commit_after>//! Module for working with `Function`s
//!
//! This module contains a type alias for `Rc<Fn(f64) -> f64>`,
//! which is used in many other modules, and functions for
//! working with the alias.

pub use std::rc::Rc;

/// Type alias used to represent functions.
///
/// A `Function` is a `Fn` that takes a single `f64`,
/// does something with it, and returns another `f64`.
///
/// Functions are stored in an `Rc` so they can be `cloned()`
/// and subsequently consumed in other functions.
pub type Function = Rc<Fn(f64) -> f64>;

/// Macro for creating a `Function`.
///
/// More idiomatic than calling `Rc::new()`.
///
/// # Examples
///
/// ```
/// # #[macro_use]
/// # extern crate reikna;
/// # fn main() {
/// use reikna::func::*;
/// let f: Function = func!(|x| x * x);
/// assert_eq!(f(5.0), 25.0);
/// # }
/// ```
#[macro_export]
macro_rules! func {
    ($e:expr) => (Rc::new($e) as Function);
}
<|endoftext|>


<commit_before>//! Module for for the HMAC-based Key Derivation Function (HKDF).
//!
//! # Examples
//!
//! ```
//! use crypto_pure::hkdf::{expand, extract};
//! use crypto_pure::sha2::{HashFunction, Sha512};
//! # let ikm = b"password";
//! # let salt = b"A non-secret random value.";
//! # let info = b"independent of the ikm";
//! let prk = &mut [0; Sha512::DIGEST_SIZE];
//! let okm = &mut [0; 64];
//! extract::<Sha512>(salt, ikm, prk);
//! expand::<Sha512>(prk, info, okm);
//! ```
use hmac::Hmac;
use sha2::{HashFunction, MAX_DIGEST_SIZE};

/// Extracts input keying material into a pseudorandom key using a salt.
///
/// # Panics
///
/// Panics if `prk.len()` is not equal to the digest size for `H`.
pub fn extract<H: HashFunction>(salt: &[u8], ikm: &[u8], prk: &mut [u8]) {
    assert_eq!(H::DIGEST_SIZE, prk.len());
    let mut hmac = Hmac::<H>::new(salt);
    hmac.update(ikm);
    hmac.write_digest(prk);
}

/// Expands a pseudorandom key into output keying material given optional information.
///
/// # Panics
///
/// Panics if `prk.len()` is less than the digest size for `H`, or if `okm.len()` is more than 255
/// times the digest size for `H`.
pub fn expand<H: HashFunction>(prk: &[u8], info: &[u8], okm: &mut [u8]) {
    let digest_size = H::DIGEST_SIZE;
    let l = okm.len();
    assert!(digest_size <= prk.len());
    assert!(255 * digest_size >= l);
    let mut hmac: Hmac<H> = Hmac::new(prk);
    for (i, chunk) in (1..).zip(okm.chunks_mut(digest_size)) {
        hmac.update(info);
        hmac.update(&[i]);
        let chunk_len = chunk.len();
        if chunk_len < digest_size {
            let mut final_digest = [0; MAX_DIGEST_SIZE];
            hmac.write_digest(&mut final_digest[..digest_size]);
            chunk.copy_from_slice(&final_digest[..chunk_len]);
            return;
        }
        hmac.write_digest(chunk);
        hmac = Hmac::new(prk);
        hmac.update(chunk);
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use test_helpers::*;
    use sha2::Sha256;

    fn check(ikm: &str, salt: &str, info: &str, prk: &str, okm: &str) {
        let ikm = h2b(ikm);
        let salt = h2b(salt);
        let info = h2b(info);
        let prk = h2b(prk);
        let okm = h2b(okm);
        let mut actual = prk.clone();
        extract::<Sha256>(&salt, &ikm, &mut actual);
        assert_eq!(prk, actual);

        let mut actual = okm.clone();
        expand::<Sha256>(&prk, &info, &mut actual);
        assert_eq!(okm, actual);
    }

    #[test]
    fn test() {
        let ikm = "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b";
        let salt = "000102030405060708090a0b0c";
        let info = "f0f1f2f3f4f5f6f7f8f9";
        let prk = "077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5";
        let okm = "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf\
                   34007208d5b887185865";
        check(ikm, salt, info, prk, okm);

        let ikm = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f\
                   202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f\
                   404142434445464748494a4b4c4d4e4f";
        let salt = "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f\
                    808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f\
                    a0a1a2a3a4a5a6a7a8a9aaabacadaeaf";
        let info = "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecf\
                    d0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeef\
                    f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
        let prk = "06a6b88c5853361a06104c9ceb35b45cef760014904671014a193f40c15fc244";
        let okm = "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c\
                   59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71\
                   cc30c58179ec3e87c14c01d5c1f3434f1d87";
        check(ikm, salt, info, prk, okm);

        let ikm = "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b";
        let salt = "";
        let info = "";
        let prk = "19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293ccb04";
        let okm = "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d\
                   9d201395faa4b61a96c8";
        check(ikm, salt, info, prk, okm);
    }
}
<commit_msg>hkdf: remove okm length declaration<commit_after>//! Module for for the HMAC-based Key Derivation Function (HKDF).
//!
//! # Examples
//!
//! ```
//! use crypto_pure::hkdf::{expand, extract};
//! use crypto_pure::sha2::{HashFunction, Sha512};
//! # let ikm = b"password";
//! # let salt = b"A non-secret random value.";
//! # let info = b"independent of the ikm";
//! let prk = &mut [0; Sha512::DIGEST_SIZE];
//! let okm = &mut [0; 64];
//! extract::<Sha512>(salt, ikm, prk);
//! expand::<Sha512>(prk, info, okm);
//! ```
use hmac::Hmac;
use sha2::{HashFunction, MAX_DIGEST_SIZE};

/// Extracts input keying material into a pseudorandom key using a salt.
///
/// # Panics
///
/// Panics if `prk.len()` is not equal to the digest size for `H`.
pub fn extract<H: HashFunction>(salt: &[u8], ikm: &[u8], prk: &mut [u8]) {
    assert_eq!(H::DIGEST_SIZE, prk.len());
    let mut hmac = Hmac::<H>::new(salt);
    hmac.update(ikm);
    hmac.write_digest(prk);
}

/// Expands a pseudorandom key into output keying material given optional information.
///
/// # Panics
///
/// Panics if `prk.len()` is less than the digest size for `H`, or if `okm.len()` is more than 255
/// times the digest size for `H`.
pub fn expand<H: HashFunction>(prk: &[u8], info: &[u8], okm: &mut [u8]) {
    let digest_size = H::DIGEST_SIZE;
    assert!(digest_size <= prk.len());
    assert!(255 * digest_size >= okm.len());
    let mut hmac: Hmac<H> = Hmac::new(prk);
    for (i, chunk) in (1..).zip(okm.chunks_mut(digest_size)) {
        hmac.update(info);
        hmac.update(&[i]);
        let chunk_len = chunk.len();
        if chunk_len < digest_size {
            let mut final_digest = [0; MAX_DIGEST_SIZE];
            hmac.write_digest(&mut final_digest[..digest_size]);
            chunk.copy_from_slice(&final_digest[..chunk_len]);
            return;
        }
        hmac.write_digest(chunk);
        hmac = Hmac::new(prk);
        hmac.update(chunk);
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use test_helpers::*;
    use sha2::Sha256;

    fn check(ikm: &str, salt: &str, info: &str, prk: &str, okm: &str) {
        let ikm = h2b(ikm);
        let salt = h2b(salt);
        let info = h2b(info);
        let prk = h2b(prk);
        let okm = h2b(okm);
        let mut actual = prk.clone();
        extract::<Sha256>(&salt, &ikm, &mut actual);
        assert_eq!(prk, actual);

        let mut actual = okm.clone();
        expand::<Sha256>(&prk, &info, &mut actual);
        assert_eq!(okm, actual);
    }

    #[test]
    fn test() {
        let ikm = "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b";
        let salt = "000102030405060708090a0b0c";
        let info = "f0f1f2f3f4f5f6f7f8f9";
        let prk = "077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2b3e5";
        let okm = "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf\
                   34007208d5b887185865";
        check(ikm, salt, info, prk, okm);

        let ikm = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f\
                   202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f\
                   404142434445464748494a4b4c4d4e4f";
        let salt = "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f\
                    808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f\
                    a0a1a2a3a4a5a6a7a8a9aaabacadaeaf";
        let info = "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecf\
                    d0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeef\
                    f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
        let prk = "06a6b88c5853361a06104c9ceb35b45cef760014904671014a193f40c15fc244";
        let okm = "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c\
                   59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71\
                   cc30c58179ec3e87c14c01d5c1f3434f1d87";
        check(ikm, salt, info, prk, okm);

        let ikm = "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b";
        let salt = "";
        let info = "";
        let prk = "19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293ccb04";
        let okm = "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d\
                   9d201395faa4b61a96c8";
        check(ikm, salt, info, prk, okm);
    }
}
<|endoftext|>


<commit_before>use sha2::{HashFunction, MAX_DIGEST_SIZE, Sha256, Sha384, Sha512};

const IPAD: u8 = 0x36;
const OPAD: u8 = 0x5c;

pub struct Hmac<T> {
    inner_hash_function: T,
    outer_hash_function: T,
}

pub fn hmac_sha512(key: &[u8], message: &[u8]) -> [u8; Sha512::DIGEST_SIZE] {
    let mut digest = [0; Sha512::DIGEST_SIZE];
    let mut hmac = Hmac::<Sha512>::new(key);
    hmac.update(message);
    hmac.write_digest(&mut digest);
    digest
}

pub fn hmac_sha384(key: &[u8], message: &[u8]) -> [u8; Sha384::DIGEST_SIZE] {
    let mut digest = [0; Sha384::DIGEST_SIZE];
    let mut hmac = Hmac::<Sha384>::new(key);
    hmac.update(message);
    hmac.write_digest(&mut digest);
    digest
}

pub fn hmac_sha256(key: &[u8], message: &[u8]) -> [u8; Sha256::DIGEST_SIZE] {
    let mut digest = [0; Sha256::DIGEST_SIZE];
    let mut hmac = Hmac::<Sha256>::new(key);
    hmac.update(message);
    hmac.write_digest(&mut digest);
    digest
}

impl<T: HashFunction> Hmac<T> {
    pub fn new(key: &[u8]) -> Self {
        let mut hashed_key;
        let new_key;
        if key.len() > T::BLOCK_SIZE {
            hashed_key = [0; MAX_DIGEST_SIZE];
            let mut hash_function = T::default();
            hash_function.update(key);
            hash_function.write_digest(&mut hashed_key[..T::DIGEST_SIZE]);
            new_key = &hashed_key[..T::DIGEST_SIZE];
        } else {
            new_key = key;
        }

        let mut hmac = Self {
            inner_hash_function: T::default(),
            outer_hash_function: T::default(),
        };
        for byte in new_key {
            hmac.inner_hash_function.update(&[byte ^ IPAD]);
            hmac.outer_hash_function.update(&[byte ^ OPAD]);
        }
        for _ in new_key.len()..T::BLOCK_SIZE {
            hmac.inner_hash_function.update(&[IPAD]);
            hmac.outer_hash_function.update(&[OPAD]);
        }
        hmac
    }

    pub fn update(&mut self, input: &[u8]) {
        self.inner_hash_function.update(input);
    }

    pub fn write_digest(mut self, output: &mut [u8]) {
        self.inner_hash_function.write_digest(output);
        self.outer_hash_function.update(output);
        self.outer_hash_function.write_digest(output);
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use test_helpers::*;

    fn check(exp512: &str, exp384: &str, exp256: &str, key: &[u8], data: &[u8]) {
        let expected = h2b(exp512);
        let mut actual = hmac_sha512(key, data);
        assert_eq!(expected, actual.to_vec());

        let mut hmac = Hmac::<Sha512>::new(key);
        for word in data.chunks(4) {
            hmac.update(word);
        }
        hmac.write_digest(&mut actual);
        assert_eq!(expected, actual.to_vec());

        let expected = h2b(exp384);
        let mut actual = hmac_sha384(key, data);
        assert_eq!(expected, actual.to_vec());

        let mut hmac = Hmac::<Sha384>::new(key);
        for word in data.chunks(4) {
            hmac.update(word);
        }
        hmac.write_digest(&mut actual);
        assert_eq!(expected, actual.to_vec());

        let expected = h2b(exp256);
        let mut actual = hmac_sha256(key, data);
        assert_eq!(expected, actual.to_vec());

        let mut hmac = Hmac::<Sha256>::new(key);
        for word in data.chunks(4) {
            hmac.update(word);
        }
        hmac.write_digest(&mut actual);
        assert_eq!(expected, actual.to_vec());
    }

    #[test]
    fn test_digest() {
        let key = h2b("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
        let data = b"Hi There";
        let exp512 = "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cde\
                      daa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854";
        let exp384 = "afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59c\
                      faea9ea9076ede7f4af152e8b2fa9cb6";
        let exp256 = "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7";
        check(exp512, exp384, exp256, &key, data);

        let key = b"Jefe";
        let data = b"what do ya want for nothing?";
        let exp512 = "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea250554\
                      9758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737";
        let exp384 = "af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e\
                      8e2240ca5e69e2c78b3239ecfab21649";
        let exp256 = "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843";
        check(exp512, exp384, exp256, key, data);

        let key = [0xaa; 20];
        let data = [0xdd; 50];
        let exp512 = "fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39\
                      bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb";
        let exp384 = "88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e55966144b\
                      2a5ab39dc13814b94e3ab6e101a34f27";
        let exp256 = "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe";
        check(exp512, exp384, exp256, &key, &data);

        let key: Vec<_> = (0x01..0x1a).collect();
        let data = [0xcd; 50];
        let exp512 = "b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3db\
                      a91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd";
        let exp384 = "3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e1f573b4e\
                      6801dd23c4a7d679ccf8a386c674cffb";
        let exp256 = "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b";
        check(exp512, exp384, exp256, &key, &data);

        let key = [0xaa; 131];
        let data = b"Test Using Larger Than Block-Size Key - Hash Key First";
        let exp512 = "80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f352\
                      6b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598";
        let exp384 = "4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05033ac4c6\
                      0c2ef6ab4030fe8296248df163f44952";
        let exp256 = "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54";
        check(exp512, exp384, exp256, &key, data);

        let data =
            b"This is a test using a larger than block-size key and a larger than block-\
              size data. The key needs to be hashed before being used by the HMAC algorithm.";
        let exp512 = "e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944\
                      b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58";
        let exp384 = "6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82461e99c5\
                      a678cc31e799176d3860e6110c46523e";
        let exp256 = "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2";
        check(exp512, exp384, exp256, &key, data);
    }
}
<commit_msg>hmac: refactor hash function preparation<commit_after>use sha2::{HashFunction, MAX_DIGEST_SIZE, Sha256, Sha384, Sha512};

const IPAD: u8 = 0x36;
const OPAD: u8 = 0x5c;

pub struct Hmac<T> {
    inner_hash_function: T,
    outer_hash_function: T,
}

pub fn hmac_sha512(key: &[u8], message: &[u8]) -> [u8; Sha512::DIGEST_SIZE] {
    let mut digest = [0; Sha512::DIGEST_SIZE];
    let mut hmac = Hmac::<Sha512>::new(key);
    hmac.update(message);
    hmac.write_digest(&mut digest);
    digest
}

pub fn hmac_sha384(key: &[u8], message: &[u8]) -> [u8; Sha384::DIGEST_SIZE] {
    let mut digest = [0; Sha384::DIGEST_SIZE];
    let mut hmac = Hmac::<Sha384>::new(key);
    hmac.update(message);
    hmac.write_digest(&mut digest);
    digest
}

pub fn hmac_sha256(key: &[u8], message: &[u8]) -> [u8; Sha256::DIGEST_SIZE] {
    let mut digest = [0; Sha256::DIGEST_SIZE];
    let mut hmac = Hmac::<Sha256>::new(key);
    hmac.update(message);
    hmac.write_digest(&mut digest);
    digest
}

impl<T: HashFunction> Hmac<T> {
    pub fn new(key: &[u8]) -> Self {
        let mut hashed_key;
        let new_key;
        if key.len() > T::BLOCK_SIZE {
            hashed_key = [0; MAX_DIGEST_SIZE];
            let mut hash_function = T::default();
            hash_function.update(key);
            hash_function.write_digest(&mut hashed_key[..T::DIGEST_SIZE]);
            new_key = &hashed_key[..T::DIGEST_SIZE];
        } else {
            new_key = key;
        }
        Self {
            inner_hash_function: Self::keyed_hash_function(new_key, IPAD),
            outer_hash_function: Self::keyed_hash_function(new_key, OPAD),
        }
    }

    pub fn update(&mut self, input: &[u8]) {
        self.inner_hash_function.update(input);
    }

    pub fn write_digest(mut self, output: &mut [u8]) {
        self.inner_hash_function.write_digest(output);
        self.outer_hash_function.update(output);
        self.outer_hash_function.write_digest(output);
    }

    fn keyed_hash_function(key: &[u8], pad: u8) -> T {
        let mut hash_function = T::default();
        for byte in key {
            hash_function.update(&[byte ^ pad]);
        }
        for _ in key.len()..T::BLOCK_SIZE {
            hash_function.update(&[pad]);
        }
        hash_function
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use test_helpers::*;

    fn check(exp512: &str, exp384: &str, exp256: &str, key: &[u8], data: &[u8]) {
        let expected = h2b(exp512);
        let mut actual = hmac_sha512(key, data);
        assert_eq!(expected, actual.to_vec());

        let mut hmac = Hmac::<Sha512>::new(key);
        for word in data.chunks(4) {
            hmac.update(word);
        }
        hmac.write_digest(&mut actual);
        assert_eq!(expected, actual.to_vec());

        let expected = h2b(exp384);
        let mut actual = hmac_sha384(key, data);
        assert_eq!(expected, actual.to_vec());

        let mut hmac = Hmac::<Sha384>::new(key);
        for word in data.chunks(4) {
            hmac.update(word);
        }
        hmac.write_digest(&mut actual);
        assert_eq!(expected, actual.to_vec());

        let expected = h2b(exp256);
        let mut actual = hmac_sha256(key, data);
        assert_eq!(expected, actual.to_vec());

        let mut hmac = Hmac::<Sha256>::new(key);
        for word in data.chunks(4) {
            hmac.update(word);
        }
        hmac.write_digest(&mut actual);
        assert_eq!(expected, actual.to_vec());
    }

    #[test]
    fn test_digest() {
        let key = h2b("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b");
        let data = b"Hi There";
        let exp512 = "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cde\
                      daa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854";
        let exp384 = "afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59c\
                      faea9ea9076ede7f4af152e8b2fa9cb6";
        let exp256 = "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7";
        check(exp512, exp384, exp256, &key, data);

        let key = b"Jefe";
        let data = b"what do ya want for nothing?";
        let exp512 = "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea250554\
                      9758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737";
        let exp384 = "af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e\
                      8e2240ca5e69e2c78b3239ecfab21649";
        let exp256 = "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843";
        check(exp512, exp384, exp256, key, data);

        let key = [0xaa; 20];
        let data = [0xdd; 50];
        let exp512 = "fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39\
                      bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb";
        let exp384 = "88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e55966144b\
                      2a5ab39dc13814b94e3ab6e101a34f27";
        let exp256 = "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe";
        check(exp512, exp384, exp256, &key, &data);

        let key: Vec<_> = (0x01..0x1a).collect();
        let data = [0xcd; 50];
        let exp512 = "b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3db\
                      a91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd";
        let exp384 = "3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e1f573b4e\
                      6801dd23c4a7d679ccf8a386c674cffb";
        let exp256 = "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b";
        check(exp512, exp384, exp256, &key, &data);

        let key = [0xaa; 131];
        let data = b"Test Using Larger Than Block-Size Key - Hash Key First";
        let exp512 = "80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f352\
                      6b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598";
        let exp384 = "4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05033ac4c6\
                      0c2ef6ab4030fe8296248df163f44952";
        let exp256 = "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54";
        check(exp512, exp384, exp256, &key, data);

        let data =
            b"This is a test using a larger than block-size key and a larger than block-\
              size data. The key needs to be hashed before being used by the HMAC algorithm.";
        let exp512 = "e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944\
                      b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58";
        let exp384 = "6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82461e99c5\
                      a678cc31e799176d3860e6110c46523e";
        let exp256 = "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2";
        check(exp512, exp384, exp256, &key, data);
    }
}
<|endoftext|>


<commit_before>use reqwest::header::{CONTENT_TYPE, USER_AGENT};
use reqwest::Client;
use std::collections::HashMap;
use std::time::Duration;
use utils::{data_to_dataurl, is_data_url};

pub fn retrieve_asset(
    cache: &mut HashMap<String, String>,
    url: &str,
    as_dataurl: bool,
    mime: &str,
    opt_user_agent: &str,
    opt_silent: bool,
    opt_insecure: bool,
) -> Result<(String, String), reqwest::Error> {
    if is_data_url(&url).unwrap() {
        Ok((url.to_string(), url.to_string()))
    } else {
        if cache.contains_key(&url.to_string()) {
            // url is in cache
            if !opt_silent {
                eprintln!("[ {} ] (from cache)", &url);
            }
            let data = cache.get(&url.to_string()).unwrap();
            Ok((data.to_string(), url.to_string()))
        } else {
            // url not in cache, we request it
            let client = Client::builder()
                .timeout(Duration::from_secs(10))
                .danger_accept_invalid_certs(opt_insecure)
                .build()?;
            let mut response = client.get(url).header(USER_AGENT, opt_user_agent).send()?;

            if !opt_silent {
                if url == response.url().as_str() {
                    eprintln!("[ {} ]", &url);
                } else {
                    eprintln!("[ {} -> {} ]", &url, &response.url().as_str());
                }
            }

            if as_dataurl {
                // Convert response into a byte array
                let mut data: Vec<u8> = vec![];
                response.copy_to(&mut data)?;

                // Attempt to obtain MIME type by reading the Content-Type header
                let mimetype = if mime == "" {
                    response
                        .headers()
                        .get(CONTENT_TYPE)
                        .and_then(|header| header.to_str().ok())
                        .unwrap_or(&mime)
                } else {
                    mime
                };
                let dataurl = data_to_dataurl(&mimetype, &data);
                // insert in cache
                cache.insert(response.url().to_string(), dataurl.to_string());
                Ok((dataurl, response.url().to_string()))
            } else {
                let content = response.text().unwrap();
                // insert in cache
                cache.insert(response.url().to_string(), content.clone());
                Ok((content, response.url().to_string()))
            }
        }
    }
}
<commit_msg>Get rid of brackets around URLs<commit_after>use reqwest::header::{CONTENT_TYPE, USER_AGENT};
use reqwest::Client;
use std::collections::HashMap;
use std::time::Duration;
use utils::{data_to_dataurl, is_data_url};

pub fn retrieve_asset(
    cache: &mut HashMap<String, String>,
    url: &str,
    as_dataurl: bool,
    mime: &str,
    opt_user_agent: &str,
    opt_silent: bool,
    opt_insecure: bool,
) -> Result<(String, String), reqwest::Error> {
    if is_data_url(&url).unwrap() {
        Ok((url.to_string(), url.to_string()))
    } else {
        if cache.contains_key(&url.to_string()) {
            // url is in cache
            if !opt_silent {
                eprintln!("{} (from cache)", &url);
            }
            let data = cache.get(&url.to_string()).unwrap();
            Ok((data.to_string(), url.to_string()))
        } else {
            // url not in cache, we request it
            let client = Client::builder()
                .timeout(Duration::from_secs(10))
                .danger_accept_invalid_certs(opt_insecure)
                .build()?;
            let mut response = client.get(url).header(USER_AGENT, opt_user_agent).send()?;

            if !opt_silent {
                if url == response.url().as_str() {
                    eprintln!("{}", &url);
                } else {
                    eprintln!("{} -> {}", &url, &response.url().as_str());
                }
            }

            if as_dataurl {
                // Convert response into a byte array
                let mut data: Vec<u8> = vec![];
                response.copy_to(&mut data)?;

                // Attempt to obtain MIME type by reading the Content-Type header
                let mimetype = if mime == "" {
                    response
                        .headers()
                        .get(CONTENT_TYPE)
                        .and_then(|header| header.to_str().ok())
                        .unwrap_or(&mime)
                } else {
                    mime
                };
                let dataurl = data_to_dataurl(&mimetype, &data);
                // insert in cache
                cache.insert(response.url().to_string(), dataurl.to_string());
                Ok((dataurl, response.url().to_string()))
            } else {
                let content = response.text().unwrap();
                // insert in cache
                cache.insert(response.url().to_string(), content.clone());
                Ok((content, response.url().to_string()))
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::net::Ipv6Addr;
use std::str::FromStr;

use common::{IpNetworkError, cidr_parts, parse_prefix};

const IPV6_BITS: u8 = 128;

#[derive(Debug,Clone,Copy,Hash,PartialEq,Eq)]
pub struct Ipv6Network {
    addr: Ipv6Addr,
    prefix: u8,
}

impl Ipv6Network {
    /// Constructs a new `Ipv6Network` from any `Ipv6Addr` and a prefix denoting the network size.
    /// If the prefix is larger than 128 this will return an `IpNetworkError::InvalidPrefix`.
    pub fn new(addr: Ipv6Addr, prefix: u8) -> Result<Ipv6Network, IpNetworkError> {
        if prefix > IPV6_BITS {
            Err(IpNetworkError::InvalidPrefix)
        } else {
            Ok(Ipv6Network {
                addr: addr,
                prefix: prefix,
            })
        }
    }

    pub fn from_cidr(cidr: &str) -> Result<Ipv6Network, IpNetworkError> {
        let (addr_str, prefix_str) = try!(cidr_parts(cidr));
        let addr = try!(Ipv6Addr::from_str(addr_str)
            .map_err(|_| IpNetworkError::InvalidAddr(format!("{}", addr_str))));
        let prefix = try!(parse_prefix(prefix_str, IPV6_BITS));
        Self::new(addr, prefix)
    }

    pub fn ip(&self) -> Ipv6Addr {
        self.addr
    }

    pub fn prefix(&self) -> u8 {
        self.prefix
    }
}

impl fmt::Display for Ipv6Network {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}/{}", self.ip(), self.prefix())
    }
}

#[cfg(test)]
mod test {
    use std::net::Ipv6Addr;
    use super::*;

    #[test]
    fn create_v6() {
        let cidr = Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 24).unwrap();
        assert_eq!(cidr.prefix(), 24);
    }

    #[test]
    fn create_v6_invalid_prefix() {
        let cidr = Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 129);
        assert!(cidr.is_err());
    }

    #[test]
    fn parse_v6() {
        let cidr = Ipv6Network::from_cidr("::1/0").unwrap();
        assert_eq!(cidr.ip(), Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
        assert_eq!(cidr.prefix(), 0);
    }

    #[test]
    fn parse_v6_2() {
        let cidr = Ipv6Network::from_cidr("FF01:0:0:17:0:0:0:2/64").unwrap();
        assert_eq!(cidr.ip(), Ipv6Addr::new(0xff01, 0, 0, 0x17, 0, 0, 0, 0x2));
        assert_eq!(cidr.prefix(), 64);
    }

    #[test]
    fn parse_v6_fail_addr() {
        let cidr = Ipv6Network::from_cidr("2001::1::/8");
        assert!(cidr.is_err());
    }

    #[test]
    fn parse_v6_fail_prefix() {
        let cidr = Ipv6Network::from_cidr("::1/129");
        assert!(cidr.is_err());
    }
}
<commit_msg>Add mask and contains to Ipv6Network<commit_after>use std::cmp;
use std::fmt;
use std::net::Ipv6Addr;
use std::str::FromStr;

use common::{IpNetworkError, cidr_parts, parse_prefix};

const IPV6_BITS: u8 = 128;

#[derive(Debug,Clone,Copy,Hash,PartialEq,Eq)]
pub struct Ipv6Network {
    addr: Ipv6Addr,
    prefix: u8,
}

impl Ipv6Network {
    /// Constructs a new `Ipv6Network` from any `Ipv6Addr` and a prefix denoting the network size.
    /// If the prefix is larger than 128 this will return an `IpNetworkError::InvalidPrefix`.
    pub fn new(addr: Ipv6Addr, prefix: u8) -> Result<Ipv6Network, IpNetworkError> {
        if prefix > IPV6_BITS {
            Err(IpNetworkError::InvalidPrefix)
        } else {
            Ok(Ipv6Network {
                addr: addr,
                prefix: prefix,
            })
        }
    }

    pub fn from_cidr(cidr: &str) -> Result<Ipv6Network, IpNetworkError> {
        let (addr_str, prefix_str) = try!(cidr_parts(cidr));
        let addr = try!(Ipv6Addr::from_str(addr_str)
            .map_err(|_| IpNetworkError::InvalidAddr(format!("{}", addr_str))));
        let prefix = try!(parse_prefix(prefix_str, IPV6_BITS));
        Self::new(addr, prefix)
    }

    pub fn ip(&self) -> Ipv6Addr {
        self.addr
    }

    pub fn prefix(&self) -> u8 {
        self.prefix
    }

    /// Returns the mask for this `Ipv6Network`.
    /// That means the `prefix` most significant bits will be 1 and the rest 0
    ///
    /// # Examples
    ///
    /// ```
    /// use std::net::Ipv6Addr;
    /// use ipnetwork::Ipv6Network;
    ///
    /// let net = Ipv6Network::from_cidr("ff01::0/32").unwrap();
    /// assert_eq!(net.mask(), Ipv6Addr::new(0xffff, 0xffff, 0, 0, 0, 0, 0, 0));
    /// ```
    pub fn mask(&self) -> Ipv6Addr {
        // Ipv6Addr::from is only implemented for [u8; 16]
        let mut segments = [0; 16];
        for (i, segment) in segments.iter_mut().enumerate() {
            let bits_remaining = self.prefix.saturating_sub(i as u8 * 8);
            let set_bits = cmp::min(bits_remaining, 8);
            *segment = !(0xff as u16 >> set_bits) as u8;
        }
        Ipv6Addr::from(segments)
    }

    /// Checks if a given `Ipv6Addr` is in this `Ipv6Network`
    ///
    /// # Examples
    ///
    /// ```
    /// use std::net::Ipv6Addr;
    /// use ipnetwork::Ipv6Network;
    ///
    /// let net = Ipv6Network::from_cidr("ff01::0/32").unwrap();
    /// assert!(net.contains(Ipv6Addr::new(0xff01, 0, 0, 0, 0, 0, 0, 0x1)));
    /// assert!(!net.contains(Ipv6Addr::new(0xffff, 0, 0, 0, 0, 0, 0, 0x1)));
    /// ```
    pub fn contains(&self, ip: Ipv6Addr) -> bool {
        let a = self.addr.segments();
        let b = ip.segments();
        let addrs = Iterator::zip(a.iter(), b.iter());
        self.mask().segments().iter().zip(addrs).all(|(mask, (a, b))|
            a & mask == b & mask
        )
    }
}

impl fmt::Display for Ipv6Network {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}/{}", self.ip(), self.prefix())
    }
}

#[cfg(test)]
mod test {
    use std::net::Ipv6Addr;
    use super::*;

    #[test]
    fn create_v6() {
        let cidr = Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 24).unwrap();
        assert_eq!(cidr.prefix(), 24);
    }

    #[test]
    fn create_v6_invalid_prefix() {
        let cidr = Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 129);
        assert!(cidr.is_err());
    }

    #[test]
    fn parse_v6() {
        let cidr = Ipv6Network::from_cidr("::1/0").unwrap();
        assert_eq!(cidr.ip(), Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1));
        assert_eq!(cidr.prefix(), 0);
    }

    #[test]
    fn parse_v6_2() {
        let cidr = Ipv6Network::from_cidr("FF01:0:0:17:0:0:0:2/64").unwrap();
        assert_eq!(cidr.ip(), Ipv6Addr::new(0xff01, 0, 0, 0x17, 0, 0, 0, 0x2));
        assert_eq!(cidr.prefix(), 64);
    }

    #[test]
    fn parse_v6_fail_addr() {
        let cidr = Ipv6Network::from_cidr("2001::1::/8");
        assert!(cidr.is_err());
    }

    #[test]
    fn parse_v6_fail_prefix() {
        let cidr = Ipv6Network::from_cidr("::1/129");
        assert!(cidr.is_err());
    }

    #[test]
    fn mask_v6() {
        let cidr = Ipv6Network::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0), 40).unwrap();
        let mask = cidr.mask();
        assert_eq!(mask, Ipv6Addr::new(0xffff, 0xffff, 0xff00, 0, 0, 0, 0, 0));
    }

    #[test]
    fn contains_v6() {
        let cidr = Ipv6Network::new(Ipv6Addr::new(0xff01, 0, 0, 0x17, 0, 0, 0, 0x2), 65).unwrap();
        let ip = Ipv6Addr::new(0xff01, 0, 0, 0x17, 0x7fff, 0, 0, 0x2);
        assert!(cidr.contains(ip));
    }

    #[test]
    fn not_contains_v6() {
        let cidr = Ipv6Network::new(Ipv6Addr::new(0xff01, 0, 0, 0x17, 0, 0, 0, 0x2), 65).unwrap();
        let ip = Ipv6Addr::new(0xff01, 0, 0, 0x17, 0xffff, 0, 0, 0x2);
        assert!(!cidr.contains(ip));
    }
}
<|endoftext|>