<commit_before>// SPDX-License-Identifier: MIT
// Copyright (C) 2018-present iced project and contributors

use crate::lua::Lua;
use crate::lua_api::lua_CFunction;
use crate::prelude::LuaUserData;
use libc::c_int;

pub trait FromLua<'lua> {
	type RetType;

	/// # Safety
	///
	/// `idx` must be a valid index that can be passed to Lua API functions.
	unsafe fn from_lua(lua: &Lua<'lua>, idx: c_int) -> Self::RetType;
}

pub trait ToLua {
	/// # Safety
	///
	/// There must be enough Lua stack space left when pushing the value on the stack (see `check_stack()`)
	unsafe fn to_lua(&self, lua: &Lua<'_>);
}

/// A value that is ignored
#[derive(Debug, Clone, Copy)]
pub struct LuaIgnore;

impl<'lua> FromLua<'lua> for LuaIgnore {
	type RetType = Self;

	#[inline]
	unsafe fn from_lua(_lua: &Lua<'lua>, _idx: c_int) -> Self::RetType {
		Self
	}
}

/// Any value, the index is stored in the instance
#[derive(Debug, Clone, Copy)]
pub struct LuaAny {
	/// Index of value
	pub idx: c_int,
}

impl<'lua> FromLua<'lua> for LuaAny {
	type RetType = Self;

	#[inline]
	unsafe fn from_lua(_lua: &Lua<'lua>, idx: c_int) -> Self::RetType {
		Self { idx }
	}
}

macro_rules! create_lua_option {
    ($lua:ident, $idx:ident { $($struct_name:ident : $ty:ty => $expr:expr,)+ }) => {
		$(
			#[derive(Debug, Clone, Copy)]
			pub struct $struct_name<const DEFAULT: $ty>;

			impl<'lua, const DEFAULT: $ty> $crate::tofrom::FromLua<'lua> for $struct_name<DEFAULT> {
				type RetType = $ty;

				#[inline]
				unsafe fn from_lua($lua: &Lua<'lua>, $idx: c_int) -> Self::RetType {
					// SAFETY: caller guarantees `$idx` is valid to pass to this function
					if unsafe { $lua.is_none_or_nil($idx) } {
						DEFAULT
					} else {
						$expr
					}
				}
			}
		)+
    };
}

// SAFETY: caller guarantees `idx` is valid to pass to these functions
create_lua_option! { lua, idx {
	LuaDefaultBool : bool => unsafe { lua.get_bool(idx) },
	LuaDefaultChar : char => unsafe { lua.get_char(idx) },
	LuaDefaultI8 : i8 => unsafe { lua.get_i8(idx) },
	LuaDefaultI16 : i16 => unsafe { lua.get_i16(idx) },
	LuaDefaultI32 : i32 => unsafe { lua.get_i32(idx) },
	LuaDefaultI64 : i64 => unsafe { lua.get_i64(idx) },
	LuaDefaultIsize : isize => unsafe { lua.get_isize(idx) },
	LuaDefaultU8 : u8 => unsafe { lua.get_u8(idx) },
	LuaDefaultU16 : u16 => unsafe { lua.get_u16(idx) },
	LuaDefaultU32 : u32 => unsafe { lua.get_u32(idx) },
	LuaDefaultU64 : u64 => unsafe { lua.get_u64(idx) },
	LuaDefaultUsize : usize => unsafe { lua.get_usize(idx) },
}}

macro_rules! impl_from_lua {
	($lua_lt:lifetime, $lua:ident, $idx:ident { $($ty:ty => $cvt:expr,)+ }) => {
		$(
			impl<$lua_lt> $crate::tofrom::FromLua<$lua_lt> for $ty {
				type RetType = $ty;

				#[inline]
				unsafe fn from_lua($lua: &Lua<$lua_lt>, $idx: c_int) -> Self {
					$cvt
				}
			}

			impl<$lua_lt> $crate::tofrom::FromLua<$lua_lt> for Option<$ty> {
				type RetType = Option<$ty>;

				#[inline]
				unsafe fn from_lua($lua: &Lua<$lua_lt>, $idx: c_int) -> Self::RetType {
					// SAFETY: caller guarantees `$idx` is valid to pass to this function
					if unsafe { $lua.is_none_or_nil($idx) } {
						None
					} else {
						Some($cvt)
					}
				}
			}
		)+
	};
}

// SAFETY: caller guarantees `idx` is valid to pass to these functions
impl_from_lua! { 'lua, lua, idx {
	bool => unsafe { lua.get_bool(idx) },
	char => unsafe { lua.get_char(idx) },
	i8 => unsafe { lua.get_i8(idx) },
	i16 => unsafe { lua.get_i16(idx) },
	i32 => unsafe { lua.get_i32(idx) },
	i64 => unsafe { lua.get_i64(idx) },
	isize => unsafe { lua.get_isize(idx) },
	u8 => unsafe { lua.get_u8(idx) },
	u16 => unsafe { lua.get_u16(idx) },
	u32 => unsafe { lua.get_u32(idx) },
	u64 => unsafe { lua.get_u64(idx) },
	usize => unsafe { lua.get_usize(idx) },
	&'lua [u8] => unsafe { lua.get_byte_slice(idx) },
	Vec<u8> => unsafe { lua.get_bytes(idx) },
}}

impl<'lua, T: LuaUserData + 'lua> FromLua<'lua> for &T {
	type RetType = &'lua T;

	#[inline]
	unsafe fn from_lua(lua: &Lua<'lua>, idx: c_int) -> Self::RetType {
		// SAFETY: caller guarantees `idx` is valid to pass to this function
		unsafe { lua.get_user_data(idx) }
	}
}

impl<'lua, T: LuaUserData + 'lua> FromLua<'lua> for Option<&T> {
	type RetType = Option<&'lua T>;

	#[inline]
	unsafe fn from_lua(lua: &Lua<'lua>, idx: c_int) -> Self::RetType {
		// SAFETY: caller guarantees `idx` is valid to pass to these functions
		unsafe {
			if lua.is_none_or_nil(idx) {
				None
			} else {
				Some(lua.get_user_data(idx))
			}
		}
	}
}

impl<'lua, T: LuaUserData + 'lua> FromLua<'lua> for &mut T {
	type RetType = &'lua mut T;

	#[inline]
	unsafe fn from_lua(lua: &Lua<'lua>, idx: c_int) -> Self::RetType {
		// SAFETY: caller guarantees `idx` is valid to pass to this function
		unsafe { lua.get_user_data_mut(idx) }
	}
}

impl<'lua, T: LuaUserData + 'lua> FromLua<'lua> for Option<&mut T> {
	type RetType = Option<&'lua mut T>;

	#[inline]
	unsafe fn from_lua(lua: &Lua<'lua>, idx: c_int) -> Self::RetType {
		// SAFETY: caller guarantees `idx` is valid to pass to these functions
		unsafe {
			if lua.is_none_or_nil(idx) {
				None
			} else {
				Some(lua.get_user_data_mut(idx))
			}
		}
	}
}

/// Pushes a Lua `nil` value, eg. `lua.push(Nil)`
#[derive(Debug, Clone, Copy)]
pub struct Nil;

macro_rules! impl_to_lua {
    ($lua:ident, $value:ident { $($ty:ty => $block:expr,)+ }) => {
		$(
			impl ToLua for $ty {
				#[inline]
				unsafe fn to_lua(&self, $lua: &Lua<'_>) {
					let $value = self;
					$block
				}
			}

			impl ToLua for Option<$ty> {
				#[inline]
				unsafe fn to_lua(&self, $lua: &Lua<'_>) {
					if let Some($value) = self {
						$block
					} else {
						// SAFETY: caller guarantees we can push a value
						unsafe { $lua.push_nil(); }
					}
				}
			}
		)+
    };
}

// SAFETY: caller guarantees we can push a value
impl_to_lua! { lua, value {
	Nil => unsafe { let _ = value; lua.push_nil() },
	bool => unsafe { lua.push_bool(*value) },
	char => unsafe { lua.push_char(*value) },
	i8 => unsafe { lua.push_i8(*value) },
	i16 => unsafe { lua.push_i16(*value) },
	i32 => unsafe { lua.push_i32(*value) },
	i64 => unsafe { lua.push_i64(*value) },
	isize => unsafe { lua.push_isize(*value) },
	u8 => unsafe { lua.push_u8(*value) },
	u16 => unsafe { lua.push_u16(*value) },
	u32 => unsafe { lua.push_u32(*value) },
	u64 => unsafe { lua.push_u64(*value) },
	usize => unsafe { lua.push_usize(*value) },
	&str => unsafe { lua.push_literal(*value) },
	String => unsafe { lua.push_literal(&*value) },
	&String => unsafe { lua.push_literal(*value) },
	&[u8] => unsafe { lua.push_bytes(*value) },
	Vec<u8> => unsafe { lua.push_bytes(&*value) },
	&Vec<u8> => unsafe { lua.push_bytes(&**value) },
	//TODO: lua.push(method_name) doesn't work, but if we add `let method_name: lua_CFunction = method_name` before the push() it works...
	lua_CFunction => unsafe { lua.push_c_function(*value) },
}}
<commit_msg>Add `LuaLossyString`<commit_after>// SPDX-License-Identifier: MIT
// Copyright (C) 2018-present iced project and contributors

use crate::lua::Lua;
use crate::lua_api::lua_CFunction;
use crate::prelude::LuaUserData;
use libc::c_int;
use std::borrow::Cow;

pub trait FromLua<'lua> {
	type RetType;

	/// # Safety
	///
	/// `idx` must be a valid index that can be passed to Lua API functions.
	unsafe fn from_lua(lua: &Lua<'lua>, idx: c_int) -> Self::RetType;
}

pub trait ToLua {
	/// # Safety
	///
	/// There must be enough Lua stack space left when pushing the value on the stack (see `check_stack()`)
	unsafe fn to_lua(&self, lua: &Lua<'_>);
}

/// A value that is ignored
#[derive(Debug, Clone, Copy)]
pub struct LuaIgnore;

impl<'lua> FromLua<'lua> for LuaIgnore {
	type RetType = Self;

	#[inline]
	unsafe fn from_lua(_lua: &Lua<'lua>, _idx: c_int) -> Self::RetType {
		Self
	}
}

/// Any value, the index is stored in the instance
#[derive(Debug, Clone, Copy)]
pub struct LuaAny {
	/// Index of value
	pub idx: c_int,
}

impl<'lua> FromLua<'lua> for LuaAny {
	type RetType = Self;

	#[inline]
	unsafe fn from_lua(_lua: &Lua<'lua>, idx: c_int) -> Self::RetType {
		Self { idx }
	}
}

/// A Lua string converted to UTF-8 (lossy conversion if it's not utf-8)
#[derive(Debug, Clone)]
pub struct LuaLossyString<'a>(pub Cow<'a, str>);

impl<'a, 'lua: 'a> FromLua<'lua> for LuaLossyString<'a> {
	type RetType = Self;

	#[inline]
	unsafe fn from_lua(lua: &Lua<'lua>, idx: c_int) -> Self::RetType {
		let bytes = unsafe { lua.get_byte_slice(idx) };
		Self(String::from_utf8_lossy(bytes))
	}
}

macro_rules! create_lua_option {
    ($lua:ident, $idx:ident { $($struct_name:ident : $ty:ty => $expr:expr,)+ }) => {
		$(
			#[derive(Debug, Clone, Copy)]
			pub struct $struct_name<const DEFAULT: $ty>;

			impl<'lua, const DEFAULT: $ty> $crate::tofrom::FromLua<'lua> for $struct_name<DEFAULT> {
				type RetType = $ty;

				#[inline]
				unsafe fn from_lua($lua: &Lua<'lua>, $idx: c_int) -> Self::RetType {
					// SAFETY: caller guarantees `$idx` is valid to pass to this function
					if unsafe { $lua.is_none_or_nil($idx) } {
						DEFAULT
					} else {
						$expr
					}
				}
			}
		)+
    };
}

// SAFETY: caller guarantees `idx` is valid to pass to these functions
create_lua_option! { lua, idx {
	LuaDefaultBool : bool => unsafe { lua.get_bool(idx) },
	LuaDefaultChar : char => unsafe { lua.get_char(idx) },
	LuaDefaultI8 : i8 => unsafe { lua.get_i8(idx) },
	LuaDefaultI16 : i16 => unsafe { lua.get_i16(idx) },
	LuaDefaultI32 : i32 => unsafe { lua.get_i32(idx) },
	LuaDefaultI64 : i64 => unsafe { lua.get_i64(idx) },
	LuaDefaultIsize : isize => unsafe { lua.get_isize(idx) },
	LuaDefaultU8 : u8 => unsafe { lua.get_u8(idx) },
	LuaDefaultU16 : u16 => unsafe { lua.get_u16(idx) },
	LuaDefaultU32 : u32 => unsafe { lua.get_u32(idx) },
	LuaDefaultU64 : u64 => unsafe { lua.get_u64(idx) },
	LuaDefaultUsize : usize => unsafe { lua.get_usize(idx) },
}}

macro_rules! impl_from_lua {
	($lua_lt:lifetime, $lua:ident, $idx:ident { $($ty:ty => $cvt:expr,)+ }) => {
		$(
			impl<$lua_lt> $crate::tofrom::FromLua<$lua_lt> for $ty {
				type RetType = $ty;

				#[inline]
				unsafe fn from_lua($lua: &Lua<$lua_lt>, $idx: c_int) -> Self {
					$cvt
				}
			}

			impl<$lua_lt> $crate::tofrom::FromLua<$lua_lt> for Option<$ty> {
				type RetType = Option<$ty>;

				#[inline]
				unsafe fn from_lua($lua: &Lua<$lua_lt>, $idx: c_int) -> Self::RetType {
					// SAFETY: caller guarantees `$idx` is valid to pass to this function
					if unsafe { $lua.is_none_or_nil($idx) } {
						None
					} else {
						Some($cvt)
					}
				}
			}
		)+
	};
}

// SAFETY: caller guarantees `idx` is valid to pass to these functions
impl_from_lua! { 'lua, lua, idx {
	bool => unsafe { lua.get_bool(idx) },
	char => unsafe { lua.get_char(idx) },
	i8 => unsafe { lua.get_i8(idx) },
	i16 => unsafe { lua.get_i16(idx) },
	i32 => unsafe { lua.get_i32(idx) },
	i64 => unsafe { lua.get_i64(idx) },
	isize => unsafe { lua.get_isize(idx) },
	u8 => unsafe { lua.get_u8(idx) },
	u16 => unsafe { lua.get_u16(idx) },
	u32 => unsafe { lua.get_u32(idx) },
	u64 => unsafe { lua.get_u64(idx) },
	usize => unsafe { lua.get_usize(idx) },
	&'lua [u8] => unsafe { lua.get_byte_slice(idx) },
	Vec<u8> => unsafe { lua.get_bytes(idx) },
}}

impl<'lua, T: LuaUserData + 'lua> FromLua<'lua> for &T {
	type RetType = &'lua T;

	#[inline]
	unsafe fn from_lua(lua: &Lua<'lua>, idx: c_int) -> Self::RetType {
		// SAFETY: caller guarantees `idx` is valid to pass to this function
		unsafe { lua.get_user_data(idx) }
	}
}

impl<'lua, T: LuaUserData + 'lua> FromLua<'lua> for Option<&T> {
	type RetType = Option<&'lua T>;

	#[inline]
	unsafe fn from_lua(lua: &Lua<'lua>, idx: c_int) -> Self::RetType {
		// SAFETY: caller guarantees `idx` is valid to pass to these functions
		unsafe {
			if lua.is_none_or_nil(idx) {
				None
			} else {
				Some(lua.get_user_data(idx))
			}
		}
	}
}

impl<'lua, T: LuaUserData + 'lua> FromLua<'lua> for &mut T {
	type RetType = &'lua mut T;

	#[inline]
	unsafe fn from_lua(lua: &Lua<'lua>, idx: c_int) -> Self::RetType {
		// SAFETY: caller guarantees `idx` is valid to pass to this function
		unsafe { lua.get_user_data_mut(idx) }
	}
}

impl<'lua, T: LuaUserData + 'lua> FromLua<'lua> for Option<&mut T> {
	type RetType = Option<&'lua mut T>;

	#[inline]
	unsafe fn from_lua(lua: &Lua<'lua>, idx: c_int) -> Self::RetType {
		// SAFETY: caller guarantees `idx` is valid to pass to these functions
		unsafe {
			if lua.is_none_or_nil(idx) {
				None
			} else {
				Some(lua.get_user_data_mut(idx))
			}
		}
	}
}

/// Pushes a Lua `nil` value, eg. `lua.push(Nil)`
#[derive(Debug, Clone, Copy)]
pub struct Nil;

macro_rules! impl_to_lua {
    ($lua:ident, $value:ident { $($ty:ty => $block:expr,)+ }) => {
		$(
			impl ToLua for $ty {
				#[inline]
				unsafe fn to_lua(&self, $lua: &Lua<'_>) {
					let $value = self;
					$block
				}
			}

			impl ToLua for Option<$ty> {
				#[inline]
				unsafe fn to_lua(&self, $lua: &Lua<'_>) {
					if let Some($value) = self {
						$block
					} else {
						// SAFETY: caller guarantees we can push a value
						unsafe { $lua.push_nil(); }
					}
				}
			}
		)+
    };
}

// SAFETY: caller guarantees we can push a value
impl_to_lua! { lua, value {
	Nil => unsafe { let _ = value; lua.push_nil() },
	bool => unsafe { lua.push_bool(*value) },
	char => unsafe { lua.push_char(*value) },
	i8 => unsafe { lua.push_i8(*value) },
	i16 => unsafe { lua.push_i16(*value) },
	i32 => unsafe { lua.push_i32(*value) },
	i64 => unsafe { lua.push_i64(*value) },
	isize => unsafe { lua.push_isize(*value) },
	u8 => unsafe { lua.push_u8(*value) },
	u16 => unsafe { lua.push_u16(*value) },
	u32 => unsafe { lua.push_u32(*value) },
	u64 => unsafe { lua.push_u64(*value) },
	usize => unsafe { lua.push_usize(*value) },
	&str => unsafe { lua.push_literal(*value) },
	String => unsafe { lua.push_literal(&*value) },
	&String => unsafe { lua.push_literal(*value) },
	&[u8] => unsafe { lua.push_bytes(*value) },
	Vec<u8> => unsafe { lua.push_bytes(&*value) },
	&Vec<u8> => unsafe { lua.push_bytes(&**value) },
	//TODO: lua.push(method_name) doesn't work, but if we add `let method_name: lua_CFunction = method_name` before the push() it works...
	lua_CFunction => unsafe { lua.push_c_function(*value) },
}}
<|endoftext|>


<commit_before>use super::super::{Grid, Y, X, Coord};
use grid_loop::{Edge, GridLoopField};
use super::*;

use rand::Rng;

pub fn generate<R: Rng>(has_clue: &Grid<bool>, dic: &Dictionary, rng: &mut R) -> Option<Grid<Clue>> {
    let height = has_clue.height();
    let width = has_clue.width();
    let max_step = height * width * 10;

    let mut current_problem = Grid::new(height, width, NO_CLUE);
    let mut prev_decided_edges = 0;
    let temperature = 5.0f64;

    let mut unplaced_clues = 0;
    for y in 0..height {
        for x in 0..width {
            if has_clue[(Y(y), X(x))] {
                unplaced_clues += 1;
            }
        }
    }

    let mut last_field = Field::new(&current_problem, dic);

    for _ in 0..max_step {
        let mut pos_cand = vec![];
        for y in 0..height {
            for x in 0..width {
                let cd = (Y(y), X(x));
                if has_clue[cd] && (current_problem[cd] == NO_CLUE || has_undecided_nearby(&last_field, cd)) {
                    pos_cand.push(cd);
                }
            }
        }

        rng.shuffle(&mut pos_cand);

        let mut updated = false;
        for &pos in &pos_cand {
            let prev_clue = current_problem[pos];
            let is_zero_ok = !has_zero_nearby(&current_problem, pos);

            let mut new_clue_cand = vec![];
            for c in (if is_zero_ok { 0 } else { 1 })..4 {
                let c = Clue(c);
                if c != prev_clue {
                    new_clue_cand.push(c);
                }
            }

            rng.shuffle(&mut new_clue_cand);

            for &c in &new_clue_cand {
                current_problem[pos] = c;

                let mut field = Field::new(&current_problem, dic);
                field.check_all_cell();

                let isok;
                let current_decided_edges;
                if field.inconsistent() {
                    isok = false;
                    current_decided_edges = -1;
                } else {
                    current_decided_edges = field.grid_loop().num_decided_edges();

                    if prev_decided_edges < current_decided_edges {
                        isok = true;
                    } else {
                        isok = rng.next_f64() < ((current_decided_edges - prev_decided_edges) as f64 / temperature).exp()
                    }
                }

                if isok {
                    updated = true;
                    prev_decided_edges = current_decided_edges;
                    if prev_clue == NO_CLUE {
                        unplaced_clues -= 1;
                    }

                    if field.fully_solved() && unplaced_clues == 0 {
                        return Some(current_problem);
                    }

                    last_field = field;
                    break;
                } else {
                    current_problem[pos] = prev_clue;
                }
            }

            if updated {
                break;
            }
        }
    }

    None
}

fn has_undecided_nearby(field: &Field, clue_pos: Coord) -> bool {
    let (Y(y), X(x)) = clue_pos;
    let y = y * 2 + 1;
    let x = x * 2 + 1;

    let neighbor_size: i32 = 7;
    for dy in -neighbor_size..(neighbor_size + 1) {
        let dx_max = neighbor_size - dy.abs();
        for dx in -dx_max..(dx_max + 1) {
            let y2 = y + dy;
            let x2 = x + dx;

            let cd = (Y(y2), X(x2));
            if (dy & 1) != (dx & 1) {
                if field.get_edge_safe(cd) == Edge::Undecided {
                    return true;
                }
            }
        }
    }
    false
}

fn has_zero_nearby(problem: &Grid<Clue>, (Y(y), X(x)): Coord) -> bool {
    for dy in -1..2 {
        for dx in -1..2 {
            let cd = (Y(y + dy), X(x + dx));
            if problem.is_valid_coord(cd) && problem[cd] == Clue(0) {
                return true;
            }
        }
    }
    false
}

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

    fn run_placement_test<R: Rng>(placement: Vec<Vec<bool>>, dic: &Dictionary, rng: &mut R) {
        let placement = ::common::vec_to_grid(&placement);
        let mut succeeded = false;

        for _ in 0..10 {
            let problem = generate(&placement, dic, rng);

            if let Some(problem) = problem {
                succeeded = true;

                assert_eq!(problem.height(), placement.height());
                assert_eq!(problem.width(), placement.width());

                for y in 0..placement.height() {
                    for x in 0..placement.width() {
                        let clue = problem[(Y(y), X(x))];
                        assert_eq!(placement[(Y(y), X(x))], clue != NO_CLUE);

                        if clue == Clue(0) {
                            for dy in -1..2 {
                                for dx in -1..2 {
                                    let y2 = y + dy;
                                    let x2 = x + dx;

                                    if 0 <= y2 && y2 < placement.height() && 0 <= x2 && x2 < placement.width() && (dy, dx) != (0, 0) {
                                        assert!(problem[(Y(y2), X(x2))] != Clue(0));
                                    }
                                }
                            }
                        }
                    }
                }

                let mut field = Field::new(&problem, &dic);
                field.check_all_cell();
                assert!(!field.inconsistent());
                assert!(field.fully_solved());

                break;
            }
        }

        assert!(succeeded);
    }

    #[test]
    fn test_generator() {
        let mut rng = rand::thread_rng();
        let dic = Dictionary::complete();

        run_placement_test(vec![
            vec![true , true , true , true , true ],
            vec![true , false, false, false, true ],
            vec![true , false, false, false, true ],
            vec![true , false, false, false, true ],
            vec![true , true , true , true , true ],
        ], &dic, &mut rng);

        run_placement_test(vec![
            vec![true , false, true , true , true ],
            vec![false, false, false, false, true ],
            vec![true , false, false, false, true ],
            vec![true , false, false, false, false],
            vec![true , true , true , false, true ],
        ], &dic, &mut rng);
    }
}
<commit_msg>Slitherlink: add generate_placement<commit_after>use super::super::{Grid, Y, X, Coord};
use grid_loop::{Edge, GridLoopField};
use super::*;

use rand::Rng;

#[derive(Debug, Clone, Copy)]
pub struct Symmetry {
    pub dyad: bool,         // 180-degree symmetry
    pub tetrad: bool,       // 90-degree symmetry
    pub horizontal: bool,   // horizontal line symmetry
    pub vertical: bool,     // vertical line symmetry
}

pub fn generate<R: Rng>(has_clue: &Grid<bool>, dic: &Dictionary, rng: &mut R) -> Option<Grid<Clue>> {
    let height = has_clue.height();
    let width = has_clue.width();
    let max_step = height * width * 10;

    let mut current_problem = Grid::new(height, width, NO_CLUE);
    let mut prev_decided_edges = 0;
    let temperature = 5.0f64;

    let mut unplaced_clues = 0;
    for y in 0..height {
        for x in 0..width {
            if has_clue[(Y(y), X(x))] {
                unplaced_clues += 1;
            }
        }
    }

    let mut last_field = Field::new(&current_problem, dic);

    for _ in 0..max_step {
        let mut pos_cand = vec![];
        for y in 0..height {
            for x in 0..width {
                let cd = (Y(y), X(x));
                if has_clue[cd] && (current_problem[cd] == NO_CLUE || has_undecided_nearby(&last_field, cd)) {
                    pos_cand.push(cd);
                }
            }
        }

        rng.shuffle(&mut pos_cand);

        let mut updated = false;
        for &pos in &pos_cand {
            let prev_clue = current_problem[pos];
            let is_zero_ok = !has_zero_nearby(&current_problem, pos);

            let mut new_clue_cand = vec![];
            for c in (if is_zero_ok { 0 } else { 1 })..4 {
                let c = Clue(c);
                if c != prev_clue {
                    new_clue_cand.push(c);
                }
            }

            rng.shuffle(&mut new_clue_cand);

            for &c in &new_clue_cand {
                current_problem[pos] = c;

                let mut field = Field::new(&current_problem, dic);
                field.check_all_cell();

                let isok;
                let current_decided_edges;
                if field.inconsistent() {
                    isok = false;
                    current_decided_edges = -1;
                } else {
                    current_decided_edges = field.grid_loop().num_decided_edges();

                    if prev_decided_edges < current_decided_edges {
                        isok = true;
                    } else {
                        isok = rng.next_f64() < ((current_decided_edges - prev_decided_edges) as f64 / temperature).exp()
                    }
                }

                if isok {
                    updated = true;
                    prev_decided_edges = current_decided_edges;
                    if prev_clue == NO_CLUE {
                        unplaced_clues -= 1;
                    }

                    if field.fully_solved() && unplaced_clues == 0 {
                        return Some(current_problem);
                    }

                    last_field = field;
                    break;
                } else {
                    current_problem[pos] = prev_clue;
                }
            }

            if updated {
                break;
            }
        }
    }

    None
}

fn has_undecided_nearby(field: &Field, clue_pos: Coord) -> bool {
    let (Y(y), X(x)) = clue_pos;
    let y = y * 2 + 1;
    let x = x * 2 + 1;

    let neighbor_size: i32 = 7;
    for dy in -neighbor_size..(neighbor_size + 1) {
        let dx_max = neighbor_size - dy.abs();
        for dx in -dx_max..(dx_max + 1) {
            let y2 = y + dy;
            let x2 = x + dx;

            let cd = (Y(y2), X(x2));
            if (dy & 1) != (dx & 1) {
                if field.get_edge_safe(cd) == Edge::Undecided {
                    return true;
                }
            }
        }
    }
    false
}

fn has_zero_nearby(problem: &Grid<Clue>, (Y(y), X(x)): Coord) -> bool {
    for dy in -1..2 {
        for dx in -1..2 {
            let cd = (Y(y + dy), X(x + dx));
            if problem.is_valid_coord(cd) && problem[cd] == Clue(0) {
                return true;
            }
        }
    }
    false
}

pub fn generate_placement<R: Rng>(height: i32, width: i32, num_clues: i32, symmetry: Symmetry, rng: &mut R) -> Grid<bool> {
    let mut num_clues = num_clues;
    let mut symmetry = symmetry;

    symmetry.dyad |= symmetry.tetrad;
    symmetry.tetrad &= (height == width);

    let mut grp_ids = Grid::new(height, width, false);
    let mut last_id = 0;

    let mut clue_positions: Vec<Vec<Coord>> = vec![];

    for y in 0..height {
        for x in 0..width {
            if !grp_ids[(Y(y), X(x))] {
                let mut sto = vec![];
                update_grp(y, x, last_id, symmetry, &mut grp_ids, &mut sto);
                clue_positions.push(sto);
            }
        }
    }

    let mut ret = Grid::new(height, width, false);
    while clue_positions.len() > 0 && num_clues > 0 {
        let mut scores = vec![];
        let mut scores_total = 0.0f64;

        for pos in &clue_positions {
            let (Y(y), X(x)) = pos[0];
            let mut score_base = 0.0f64;

            for dy in -2..3 {
                for dx in -2..3 {
                    let cd2 = (Y(y + dy), X(x + dx));
                    if ret.is_valid_coord(cd2) && ret[cd2] {
                        let dist = dy.abs() + dx.abs();
                        score_base += 5.0f64 - (dist as f64);
                        if dist == 1 {
                            score_base += 2.0f64;
                        }
                    }
                }
            }

            let pos_score = 64.0f64 * 2.0f64.powf((16.0f64 - score_base) / 2.0f64) + 4.0f64;
            scores.push(pos_score);
            scores_total += pos_score;
        }

        let mut thresh = rng.gen_range(0.0f64, scores_total);
        for i in 0..clue_positions.len() {
            if thresh < scores[i] {
                for &c in &(clue_positions[i]) {
                    ret[c] = true;
                    num_clues -= 1;
                }
                clue_positions.swap_remove(i);
                break;
            } else {
                thresh -= scores[i];
            }
        }
    }

    ret
}

fn update_grp(y: i32, x: i32, id: i32, symmetry: Symmetry, grp_ids: &mut Grid<bool>, sto: &mut Vec<Coord>) {
    if grp_ids[(Y(y), X(x))] {
        return;
    }
    grp_ids[(Y(y), X(x))] = true;
    sto.push((Y(y), X(x)));

    if symmetry.tetrad {
        update_grp(grp_ids.height() - 1 - x, y, id, symmetry, grp_ids, sto);
    } else if symmetry.dyad {
        update_grp(grp_ids.height() - 1 - y, grp_ids.width() - 1 - x, id, symmetry, grp_ids, sto);
    }
    if symmetry.horizontal {
        update_grp(grp_ids.height() - 1 - y, x, id, symmetry, grp_ids, sto);
    }
    if symmetry.vertical {
        update_grp(y, grp_ids.width() - 1 - x, id, symmetry, grp_ids, sto);
    }
}

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

    fn run_placement_test<R: Rng>(placement: Vec<Vec<bool>>, dic: &Dictionary, rng: &mut R) {
        let placement = ::common::vec_to_grid(&placement);
        let mut succeeded = false;

        for _ in 0..10 {
            let problem = generate(&placement, dic, rng);

            if let Some(problem) = problem {
                succeeded = true;

                assert_eq!(problem.height(), placement.height());
                assert_eq!(problem.width(), placement.width());

                for y in 0..placement.height() {
                    for x in 0..placement.width() {
                        let clue = problem[(Y(y), X(x))];
                        assert_eq!(placement[(Y(y), X(x))], clue != NO_CLUE);

                        if clue == Clue(0) {
                            for dy in -1..2 {
                                for dx in -1..2 {
                                    let y2 = y + dy;
                                    let x2 = x + dx;

                                    if 0 <= y2 && y2 < placement.height() && 0 <= x2 && x2 < placement.width() && (dy, dx) != (0, 0) {
                                        assert!(problem[(Y(y2), X(x2))] != Clue(0));
                                    }
                                }
                            }
                        }
                    }
                }

                let mut field = Field::new(&problem, &dic);
                field.check_all_cell();
                assert!(!field.inconsistent());
                assert!(field.fully_solved());

                break;
            }
        }

        assert!(succeeded);
    }

    #[test]
    fn test_generator() {
        let mut rng = rand::thread_rng();
        let dic = Dictionary::complete();

        run_placement_test(vec![
            vec![true , true , true , true , true ],
            vec![true , false, false, false, true ],
            vec![true , false, false, false, true ],
            vec![true , false, false, false, true ],
            vec![true , true , true , true , true ],
        ], &dic, &mut rng);

        run_placement_test(vec![
            vec![true , false, true , true , true ],
            vec![false, false, false, false, true ],
            vec![true , false, false, false, true ],
            vec![true , false, false, false, false],
            vec![true , true , true , false, true ],
        ], &dic, &mut rng);
    }
}
<|endoftext|>


<commit_before>//! Abstractions for page tables and other paging related structures.
//!
//! Page tables translate virtual memory “pages” to physical memory “frames”.

pub use self::frame_alloc::*;
pub use self::page_table::*;
#[cfg(target_arch = "x86_64")]
pub use self::recursive::*;
pub use self::page::{Page, PageSize, Size4KiB, Size2MiB, Size1GiB};
pub use self::frame::PhysFrame;

use crate::{PhysAddr, VirtAddr};
use core::fmt;
use core::marker::PhantomData;
use core::ops::{Add, AddAssign, Sub, SubAssign};
use ux::*;

pub mod page;
pub mod frame;
mod frame_alloc;
mod page_table;
mod recursive;
<commit_msg>Be explicit about frame_alloc re-exports<commit_after>//! Abstractions for page tables and other paging related structures.
//!
//! Page tables translate virtual memory “pages” to physical memory “frames”.

pub use self::frame_alloc::{FrameAllocator, FrameDeallocator};
pub use self::page_table::*;
#[cfg(target_arch = "x86_64")]
pub use self::recursive::*;
pub use self::page::{Page, PageSize, Size4KiB, Size2MiB, Size1GiB};
pub use self::frame::PhysFrame;

use crate::{PhysAddr, VirtAddr};
use core::fmt;
use core::marker::PhantomData;
use core::ops::{Add, AddAssign, Sub, SubAssign};
use ux::*;

pub mod page;
pub mod frame;
mod frame_alloc;
mod page_table;
mod recursive;
<|endoftext|>


<commit_before>fn guess_this() -> i32 {
    let one = 5;
    let two = 7;
    let three = 3;
    let result = (one + two) / three;
    return result;
}

fn simple() -> &'static str {
    let hello = "Hello World!";
    return hello;
}

mod tests {
    use super::*;

    pub fn test_simple() {
        verify!("Hello World!", simple(), "Simple example");
    }

    pub fn test_complicated() {
        verify!(1, guess_this(), "Complicated example");
    }
}

pub fn exec() {
    tests::test_simple();
    tests::test_complicated();
}
<commit_msg>port the first exercise from the old curriculum<commit_after>// Welcome to Rustlings! If you're here, that means you've either successfully
// downloaded Rustlings, or are looking at this on GitHub. Either way, let me
// introduce you to one of the most basic elements of Rust:
//
// === VARIABLES ===
//
// Variables are essentially little containers that hold, well, something. Think
// of them as a little cardboard box that you put stuff into. What can you put
// into a virtual cardboard box in Rust? All kinds of stuff, it turns out!
// Numbers, words, sequences, and much more. Let's start out simple, though.
// Here's our first exercise:

pub fn exercise_one() {
    let x = 5;
    verify!(0, x, "Number assignment");
    //      ^  ^
    //      |  |
    // What's  The variable
    //  in it  itself
}

// Did you get all that? The "let" word basically tells us that we now want to
// define a variable, and what follows it, the "x" is the name of the variable.
// Each variable has a name, like a label you put on your cardboard box so you
// don't confuse it with another, similar looking one.
// The whole "verify!" deal essentially means that Rustlings is checking if you
// solved the exercise correctly. It compares the first argument with the
// second, so in this case "0" with "x", where "x" is the _value_ of the variable
// we called "x". When you write "x", you pull out the cardboard box labelled "x"
// and take out what's inside of it.
// Speaking of which, what *is* inside of our "x" cardboard box? I don't think it's
// "0"... do you know? Replace the "0" with the value of the variable we defined.
// After that, run "cargo run" in your command line, and see if you put in the
// right answer.

pub fn exec() {
    exercise_one();
}
<|endoftext|>


<commit_before>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Manages the communication between the compiler's main thread and
//! the thread that constructs the dependency graph. The basic idea is
//! to use double buffering to lower the cost of producing a message.
//! In the compiler thread, we accumulate messages in a vector until
//! the vector is full, or until we want to query the graph, and then
//! we send that vector over to the depgraph thread. At the same time,
//! we receive an empty vector from the depgraph thread that we can use
//! to accumulate more messages. This way we only ever have two vectors
//! allocated (and both have a fairly large capacity).

use rustc_data_structures::veccell::VecCell;
use std::sync::mpsc::{self, Sender, Receiver};
use std::thread;

use super::DepGraphQuery;
use super::DepNode;
use super::edges::DepGraphEdges;

pub enum DepMessage {
    Read(DepNode),
    Write(DepNode),
    PushTask(DepNode),
    PopTask(DepNode),
    PushIgnore,
    PopIgnore,
    Query,
}

pub struct DepGraphThreadData {
    enabled: bool,

    // current buffer, where we accumulate messages
    messages: VecCell<DepMessage>,

    // whence to receive new buffer when full
    swap_in: Receiver<Vec<DepMessage>>,

    // where to send buffer when full
    swap_out: Sender<Vec<DepMessage>>,

    // where to receive query results
    query_in: Receiver<DepGraphQuery>,
}

const INITIAL_CAPACITY: usize = 2048;

impl DepGraphThreadData {
    pub fn new(enabled: bool) -> DepGraphThreadData {
        let (tx1, rx1) = mpsc::channel();
        let (tx2, rx2) = mpsc::channel();
        let (txq, rxq) = mpsc::channel();
        if enabled {
            thread::spawn(move || main(rx1, tx2, txq));
        }
        DepGraphThreadData {
            enabled: enabled,
            messages: VecCell::with_capacity(INITIAL_CAPACITY),
            swap_in: rx2,
            swap_out: tx1,
            query_in: rxq,
        }
    }

    /// Sends the current batch of messages to the thread. Installs a
    /// new vector of messages.
    fn swap(&self) {
        assert!(self.enabled, "should never swap if not enabled");

        // should be a buffer waiting for us (though of course we may
        // have to wait for depgraph thread to finish processing the
        // old messages)
        let new_messages = self.swap_in.recv().unwrap();
        assert!(new_messages.is_empty());

        // swap in the empty buffer and extract the full one
        let old_messages = self.messages.swap(new_messages);

        // send full buffer to depgraph thread to be processed
        self.swap_out.send(old_messages).unwrap();
    }

    pub fn query(&self) -> DepGraphQuery {
        assert!(self.enabled, "cannot query if dep graph construction not enabled");
        self.enqueue(DepMessage::Query);
        self.swap();
        self.query_in.recv().unwrap()
    }

    /// Enqueue a message to be sent when things are next swapped. (If
    /// the buffer is full, this may swap.)
    #[inline]
    pub fn enqueue(&self, message: DepMessage) {
        if self.enabled {
            let len = self.messages.push(message);
            if len == INITIAL_CAPACITY {
                self.swap();
            }
        }
    }
}

/// Definition of the depgraph thread.
pub fn main(swap_in: Receiver<Vec<DepMessage>>,
            swap_out: Sender<Vec<DepMessage>>,
            query_out: Sender<DepGraphQuery>) {
    let mut edges = DepGraphEdges::new();

    // the compiler thread always expects a fresh buffer to be
    // waiting, so queue one up
    swap_out.send(Vec::with_capacity(INITIAL_CAPACITY)).unwrap();

    // process the buffers from compiler thread as we receive them
    for mut messages in swap_in {
        for msg in messages.drain(..) {
            match msg {
                DepMessage::Read(node) => edges.read(node),
                DepMessage::Write(node) => edges.write(node),
                DepMessage::PushTask(node) => edges.push_task(node),
                DepMessage::PopTask(node) => edges.pop_task(node),
                DepMessage::PushIgnore => edges.push_ignore(),
                DepMessage::PopIgnore => edges.pop_ignore(),
                DepMessage::Query => query_out.send(edges.query()).unwrap(),
            }
        }
        swap_out.send(messages).unwrap();
    }
}
<commit_msg>Add a local counter that tracks how many tasks are pushed or not pushed, so that we can still get assertion failures even when dep-graph construction is disabled.<commit_after>// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Manages the communication between the compiler's main thread and
//! the thread that constructs the dependency graph. The basic idea is
//! to use double buffering to lower the cost of producing a message.
//! In the compiler thread, we accumulate messages in a vector until
//! the vector is full, or until we want to query the graph, and then
//! we send that vector over to the depgraph thread. At the same time,
//! we receive an empty vector from the depgraph thread that we can use
//! to accumulate more messages. This way we only ever have two vectors
//! allocated (and both have a fairly large capacity).

use rustc_data_structures::veccell::VecCell;
use std::cell::Cell;
use std::sync::mpsc::{self, Sender, Receiver};
use std::thread;

use super::DepGraphQuery;
use super::DepNode;
use super::edges::DepGraphEdges;

pub enum DepMessage {
    Read(DepNode),
    Write(DepNode),
    PushTask(DepNode),
    PopTask(DepNode),
    PushIgnore,
    PopIgnore,
    Query,
}

pub struct DepGraphThreadData {
    enabled: bool,

    // Local counter that just tracks how many tasks are pushed onto the
    // stack, so that we still get an error in the case where one is
    // missing. If dep-graph construction is enabled, we'd get the same
    // error when processing tasks later on, but that's annoying because
    // it lacks precision about the source of the error.
    tasks_pushed: Cell<usize>,

    // current buffer, where we accumulate messages
    messages: VecCell<DepMessage>,

    // whence to receive new buffer when full
    swap_in: Receiver<Vec<DepMessage>>,

    // where to send buffer when full
    swap_out: Sender<Vec<DepMessage>>,

    // where to receive query results
    query_in: Receiver<DepGraphQuery>,
}

const INITIAL_CAPACITY: usize = 2048;

impl DepGraphThreadData {
    pub fn new(enabled: bool) -> DepGraphThreadData {
        let (tx1, rx1) = mpsc::channel();
        let (tx2, rx2) = mpsc::channel();
        let (txq, rxq) = mpsc::channel();

        if enabled {
            thread::spawn(move || main(rx1, tx2, txq));
        }

        DepGraphThreadData {
            enabled: enabled,
            tasks_pushed: Cell::new(0),
            messages: VecCell::with_capacity(INITIAL_CAPACITY),
            swap_in: rx2,
            swap_out: tx1,
            query_in: rxq,
        }
    }

    #[inline]
    pub fn enabled(&self) -> bool {
        self.enabled
    }

    /// Sends the current batch of messages to the thread. Installs a
    /// new vector of messages.
    fn swap(&self) {
        assert!(self.enabled, "should never swap if not enabled");

        // should be a buffer waiting for us (though of course we may
        // have to wait for depgraph thread to finish processing the
        // old messages)
        let new_messages = self.swap_in.recv().unwrap();
        assert!(new_messages.is_empty());

        // swap in the empty buffer and extract the full one
        let old_messages = self.messages.swap(new_messages);

        // send full buffer to depgraph thread to be processed
        self.swap_out.send(old_messages).unwrap();
    }

    pub fn query(&self) -> DepGraphQuery {
        assert!(self.enabled, "cannot query if dep graph construction not enabled");
        self.enqueue(DepMessage::Query);
        self.swap();
        self.query_in.recv().unwrap()
    }

    /// Enqueue a message to be sent when things are next swapped. (If
    /// the buffer is full, this may swap.)
    #[inline]
    pub fn enqueue(&self, message: DepMessage) {
        // Regardless of whether dep graph construction is enabled, we
        // still want to check that we always have a valid task on the
        // stack when a read/write/etc event occurs.
        match message {
            DepMessage::Read(_) | DepMessage::Write(_) =>
                if self.tasks_pushed.get() == 0 {
                    self.invalid_message("read/write but no current task")
                },
            DepMessage::PushTask(_) | DepMessage::PushIgnore =>
                self.tasks_pushed.set(self.tasks_pushed.get() + 1),
            DepMessage::PopTask(_) | DepMessage::PopIgnore =>
                self.tasks_pushed.set(self.tasks_pushed.get() - 1),
            DepMessage::Query =>
                (),
        }

        if self.enabled {
            self.enqueue_enabled(message);
        }
    }

    // Outline this fn since I expect it may want to be inlined
    // separately.
    fn enqueue_enabled(&self, message: DepMessage) {
        let len = self.messages.push(message);
        if len == INITIAL_CAPACITY {
            self.swap();
        }
    }

    // Outline this too.
    fn invalid_message(&self, string: &str) {
        panic!("{}; see src/librustc/dep_graph/README.md for more information", string)
    }
}

/// Definition of the depgraph thread.
pub fn main(swap_in: Receiver<Vec<DepMessage>>,
            swap_out: Sender<Vec<DepMessage>>,
            query_out: Sender<DepGraphQuery>) {
    let mut edges = DepGraphEdges::new();

    // the compiler thread always expects a fresh buffer to be
    // waiting, so queue one up
    swap_out.send(Vec::with_capacity(INITIAL_CAPACITY)).unwrap();

    // process the buffers from compiler thread as we receive them
    for mut messages in swap_in {
        for msg in messages.drain(..) {
            match msg {
                DepMessage::Read(node) => edges.read(node),
                DepMessage::Write(node) => edges.write(node),
                DepMessage::PushTask(node) => edges.push_task(node),
                DepMessage::PopTask(node) => edges.pop_task(node),
                DepMessage::PushIgnore => edges.push_ignore(),
                DepMessage::PopIgnore => edges.pop_ignore(),
                DepMessage::Query => query_out.send(edges.query()).unwrap(),
            }
        }
        swap_out.send(messages).unwrap();
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation of `make clean` in rustbuild.
//!
//! Responsible for cleaning out a build directory of all old and stale
//! artifacts to prepare for a fresh build. Currently doesn't remove the
//! `build/cache` directory (download cache) or the `build/$target/llvm`
//! directory as we want that cached between builds.

use std::fs;
use std::io::{self, ErrorKind};
use std::path::Path;

use Build;

pub fn clean(build: &Build) {
    rm_rf(build, "tmp".as_ref());
    rm_rf(build, &build.out.join("tmp"));
    rm_rf(build, &build.out.join("dist"));

    for host in build.config.host.iter() {
        let entries = match build.out.join(host).read_dir() {
            Ok(iter) => iter,
            Err(_) => continue,
        };

        for entry in entries {
            let entry = t!(entry);
            if entry.file_name().to_str() == Some("llvm") {
                continue
            }
            let path = t!(entry.path().canonicalize());
            rm_rf(build, &path);
        }
    }
}

fn rm_rf(build: &Build, path: &Path) {
    if !path.exists() {
        return
    }
    if path.is_file() {
        return do_op(path, "remove file", |p| fs::remove_file(p));
    }

    for file in t!(fs::read_dir(path)) {
        let file = t!(file).path();

        if file.is_dir() {
            rm_rf(build, &file);
        } else {
            // On windows we can't remove a readonly file, and git will
            // often clone files as readonly. As a result, we have some
            // special logic to remove readonly files on windows.
            do_op(&file, "remove file", |p| fs::remove_file(p));
        }
    }
    do_op(path, "remove dir", |p| fs::remove_dir(p));
}

fn do_op<F>(path: &Path, desc: &str, mut f: F)
    where F: FnMut(&Path) -> io::Result<()>
{
    match f(path) {
        Ok(()) => {}
        Err(ref e) if cfg!(windows) &&
                      e.kind() == ErrorKind::PermissionDenied => {
            let mut p = t!(path.metadata()).permissions();
            p.set_readonly(false);
            t!(fs::set_permissions(path, p));
            f(path).unwrap_or_else(|e| {
                panic!("failed to {} {}: {}", desc, path.display(), e);
            })
        }
        Err(e) => {
            panic!("failed to {} {}: {}", desc, path.display(), e);
        }
    }
}
<commit_msg>Rollup merge of #40562 - mbrubeck:bootstrap, r=alexcrichton<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Implementation of `make clean` in rustbuild.
//!
//! Responsible for cleaning out a build directory of all old and stale
//! artifacts to prepare for a fresh build. Currently doesn't remove the
//! `build/cache` directory (download cache) or the `build/$target/llvm`
//! directory as we want that cached between builds.

use std::fs;
use std::io::{self, ErrorKind};
use std::path::Path;

use Build;

pub fn clean(build: &Build) {
    rm_rf("tmp".as_ref());
    rm_rf(&build.out.join("tmp"));
    rm_rf(&build.out.join("dist"));

    for host in build.config.host.iter() {
        let entries = match build.out.join(host).read_dir() {
            Ok(iter) => iter,
            Err(_) => continue,
        };

        for entry in entries {
            let entry = t!(entry);
            if entry.file_name().to_str() == Some("llvm") {
                continue
            }
            let path = t!(entry.path().canonicalize());
            rm_rf(&path);
        }
    }
}

fn rm_rf(path: &Path) {
    if !path.exists() {
        return
    }
    if path.is_file() {
        return do_op(path, "remove file", |p| fs::remove_file(p));
    }

    for file in t!(fs::read_dir(path)) {
        let file = t!(file).path();

        if file.is_dir() {
            rm_rf(&file);
        } else {
            // On windows we can't remove a readonly file, and git will
            // often clone files as readonly. As a result, we have some
            // special logic to remove readonly files on windows.
            do_op(&file, "remove file", |p| fs::remove_file(p));
        }
    }
    do_op(path, "remove dir", |p| fs::remove_dir(p));
}

fn do_op<F>(path: &Path, desc: &str, mut f: F)
    where F: FnMut(&Path) -> io::Result<()>
{
    match f(path) {
        Ok(()) => {}
        Err(ref e) if cfg!(windows) &&
                      e.kind() == ErrorKind::PermissionDenied => {
            let mut p = t!(path.metadata()).permissions();
            p.set_readonly(false);
            t!(fs::set_permissions(path, p));
            f(path).unwrap_or_else(|e| {
                panic!("failed to {} {}: {}", desc, path.display(), e);
            })
        }
        Err(e) => {
            panic!("failed to {} {}: {}", desc, path.display(), e);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Command-line interface of the rustbuild build system.
//!
//! This module implements the command-line parsing of the build system which
//! has various flags to configure how it's run.

use std::env;
use std::fs;
use std::path::PathBuf;
use std::process;

use getopts::{Options};

use Build;
use config::Config;
use metadata;
use step;

/// Deserialized version of all flags for this compile.
pub struct Flags {
    pub verbose: usize, // verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose
    pub on_fail: Option<String>,
    pub stage: Option<u32>,
    pub keep_stage: Option<u32>,
    pub build: String,
    pub host: Vec<String>,
    pub target: Vec<String>,
    pub config: Option<PathBuf>,
    pub src: Option<PathBuf>,
    pub jobs: Option<u32>,
    pub cmd: Subcommand,
    pub incremental: bool,
}

impl Flags {
    pub fn verbose(&self) -> bool {
        self.verbose > 0
    }

    pub fn very_verbose(&self) -> bool {
        self.verbose > 1
    }
}

pub enum Subcommand {
    Build {
        paths: Vec<PathBuf>,
    },
    Doc {
        paths: Vec<PathBuf>,
    },
    Test {
        paths: Vec<PathBuf>,
        test_args: Vec<String>,
    },
    Bench {
        paths: Vec<PathBuf>,
        test_args: Vec<String>,
    },
    Clean,
    Dist {
        paths: Vec<PathBuf>,
        install: bool,
    },
}

impl Flags {
    pub fn parse(args: &[String]) -> Flags {
        let mut extra_help = String::new();
        let mut subcommand_help = format!("\
Usage: x.py <subcommand> [options] [<paths>...]

Subcommands:
    build       Compile either the compiler or libraries
    test        Build and run some test suites
    bench       Build and run some benchmarks
    doc         Build documentation
    clean       Clean out build directories
    dist        Build and/or install distribution artifacts

To learn more about a subcommand, run `./x.py <subcommand> -h`");

        let mut opts = Options::new();
        // Options common to all subcommands
        opts.optflagmulti("v", "verbose", "use verbose output (-vv for very verbose)");
        opts.optflag("i", "incremental", "use incremental compilation");
        opts.optopt("", "config", "TOML configuration file for build", "FILE");
        opts.optopt("", "build", "build target of the stage0 compiler", "BUILD");
        opts.optmulti("", "host", "host targets to build", "HOST");
        opts.optmulti("", "target", "target targets to build", "TARGET");
        opts.optopt("", "on-fail", "command to run on failure", "CMD");
        opts.optopt("", "stage", "stage to build", "N");
        opts.optopt("", "keep-stage", "stage to keep without recompiling", "N");
        opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
        opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
        opts.optflag("h", "help", "print this help message");

        // fn usage()
        let usage = |exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! {
            println!("{}", opts.usage(subcommand_help));
            if !extra_help.is_empty() {
                println!("{}", extra_help);
            }
            process::exit(exit_code);
        };

        // We can't use getopt to parse the options until we have completed specifying which
        // options are valid, but under the current implementation, some options are conditional on
        // the subcommand. Therefore we must manually identify the subcommand first, so that we can
        // complete the definition of the options.  Then we can use the getopt::Matches object from
        // there on out.
        let mut possible_subcommands = args.iter().collect::<Vec<_>>();
        possible_subcommands.retain(|&s| !s.starts_with('-'));
        let subcommand = match possible_subcommands.first() {
            Some(s) => s,
            None => {
                // No subcommand -- show the general usage and subcommand help
                println!("{}\n", subcommand_help);
                process::exit(0);
            }
        };

        // Some subcommands have specific arguments help text
        match subcommand.as_str() {
            "build" => {
                subcommand_help.push_str("\n
Arguments:
    This subcommand accepts a number of paths to directories to the crates
    and/or artifacts to compile. For example:

        ./x.py build src/libcore
        ./x.py build src/libcore src/libproc_macro
        ./x.py build src/libstd --stage 1

    If no arguments are passed then the complete artifacts for that stage are
    also compiled.

        ./x.py build
        ./x.py build --stage 1

    For a quick build with a usable compile, you can pass:

        ./x.py build --stage 1 src/libtest");
            }
            "test" => {
                opts.optmulti("", "test-args", "extra arguments", "ARGS");
                subcommand_help.push_str("\n
Arguments:
    This subcommand accepts a number of paths to directories to tests that
    should be compiled and run. For example:

        ./x.py test src/test/run-pass
        ./x.py test src/libstd --test-args hash_map
        ./x.py test src/libstd --stage 0

    If no arguments are passed then the complete artifacts for that stage are
    compiled and tested.

        ./x.py test
        ./x.py test --stage 1");
            }
            "bench" => {
                opts.optmulti("", "test-args", "extra arguments", "ARGS");
            }
            "doc" => {
                subcommand_help.push_str("\n
Arguments:
    This subcommand accepts a number of paths to directories of documentation
    to build. For example:

        ./x.py doc src/doc/book
        ./x.py doc src/doc/nomicon
        ./x.py doc src/doc/book src/libstd

    If no arguments are passed then everything is documented:

        ./x.py doc
        ./x.py doc --stage 1");
            }
            "dist" => {
                opts.optflag("", "install", "run installer as well");
            }
            _ => { }
        };

        // Done specifying what options are possible, so do the getopts parsing
        let matches = opts.parse(&args[..]).unwrap_or_else(|e| {
            // Invalid argument/option format
            println!("\n{}\n", e);
            usage(1, &opts, &subcommand_help, &extra_help);
        });
        // Get any optional paths which occur after the subcommand
        let cwd = t!(env::current_dir());
        let paths = matches.free[1..].iter().map(|p| cwd.join(p)).collect::<Vec<_>>();

        // All subcommands can have an optional "Available paths" section
        if matches.opt_present("verbose") {
            let flags = Flags::parse(&["build".to_string()]);
            let mut config = Config::default();
            config.build = flags.build.clone();
            let mut build = Build::new(flags, config);
            metadata::build(&mut build);
            let maybe_rules_help = step::build_rules(&build).get_help(subcommand);
            if maybe_rules_help.is_some() {
                extra_help.push_str(maybe_rules_help.unwrap().as_str());
            }
        } else {
            extra_help.push_str(format!("Run `./x.py {} -h -v` to see a list of available paths.",
                     subcommand).as_str());
        }

        // User passed in -h/--help?
        if matches.opt_present("help") {
            usage(0, &opts, &subcommand_help, &extra_help);
        }

        let cmd = match subcommand.as_str() {
            "build" => {
                Subcommand::Build { paths: paths }
            }
            "test" => {
                Subcommand::Test {
                    paths: paths,
                    test_args: matches.opt_strs("test-args"),
                }
            }
            "bench" => {
                Subcommand::Bench {
                    paths: paths,
                    test_args: matches.opt_strs("test-args"),
                }
            }
            "doc" => {
                Subcommand::Doc { paths: paths }
            }
            "clean" => {
                if matches.free.len() > 0 {
                    println!("\nclean takes no arguments\n");
                    usage(1, &opts, &subcommand_help, &extra_help);
                }
                Subcommand::Clean
            }
            "dist" => {
                Subcommand::Dist {
                    paths: paths,
                    install: matches.opt_present("install"),
                }
            }
            _ => {
                usage(1, &opts, &subcommand_help, &extra_help);
            }
        };

        let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| {
            if fs::metadata("config.toml").is_ok() {
                Some(PathBuf::from("config.toml"))
            } else {
                None
            }
        });

        let mut stage = matches.opt_str("stage").map(|j| j.parse().unwrap());

        if matches.opt_present("incremental") {
            if stage.is_none() {
                stage = Some(1);
            }
        }

        Flags {
            verbose: matches.opt_count("verbose"),
            stage: stage,
            on_fail: matches.opt_str("on-fail"),
            keep_stage: matches.opt_str("keep-stage").map(|j| j.parse().unwrap()),
            build: matches.opt_str("build").unwrap_or_else(|| {
                env::var("BUILD").unwrap()
            }),
            host: split(matches.opt_strs("host")),
            target: split(matches.opt_strs("target")),
            config: cfg_file,
            src: matches.opt_str("src").map(PathBuf::from),
            jobs: matches.opt_str("jobs").map(|j| j.parse().unwrap()),
            cmd: cmd,
            incremental: matches.opt_present("incremental"),
        }
    }
}

impl Subcommand {
    pub fn test_args(&self) -> Vec<&str> {
        match *self {
            Subcommand::Test { ref test_args, .. } |
            Subcommand::Bench { ref test_args, .. } => {
                test_args.iter().flat_map(|s| s.split_whitespace()).collect()
            }
            _ => Vec::new(),
        }
    }
}

fn split(s: Vec<String>) -> Vec<String> {
    s.iter().flat_map(|s| s.split(',')).map(|s| s.to_string()).collect()
}
<commit_msg>Simplify a "use" statement as per @grunweg's feedback.<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Command-line interface of the rustbuild build system.
//!
//! This module implements the command-line parsing of the build system which
//! has various flags to configure how it's run.

use std::env;
use std::fs;
use std::path::PathBuf;
use std::process;

use getopts::Options;

use Build;
use config::Config;
use metadata;
use step;

/// Deserialized version of all flags for this compile.
pub struct Flags {
    pub verbose: usize, // verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose
    pub on_fail: Option<String>,
    pub stage: Option<u32>,
    pub keep_stage: Option<u32>,
    pub build: String,
    pub host: Vec<String>,
    pub target: Vec<String>,
    pub config: Option<PathBuf>,
    pub src: Option<PathBuf>,
    pub jobs: Option<u32>,
    pub cmd: Subcommand,
    pub incremental: bool,
}

impl Flags {
    pub fn verbose(&self) -> bool {
        self.verbose > 0
    }

    pub fn very_verbose(&self) -> bool {
        self.verbose > 1
    }
}

pub enum Subcommand {
    Build {
        paths: Vec<PathBuf>,
    },
    Doc {
        paths: Vec<PathBuf>,
    },
    Test {
        paths: Vec<PathBuf>,
        test_args: Vec<String>,
    },
    Bench {
        paths: Vec<PathBuf>,
        test_args: Vec<String>,
    },
    Clean,
    Dist {
        paths: Vec<PathBuf>,
        install: bool,
    },
}

impl Flags {
    pub fn parse(args: &[String]) -> Flags {
        let mut extra_help = String::new();
        let mut subcommand_help = format!("\
Usage: x.py <subcommand> [options] [<paths>...]

Subcommands:
    build       Compile either the compiler or libraries
    test        Build and run some test suites
    bench       Build and run some benchmarks
    doc         Build documentation
    clean       Clean out build directories
    dist        Build and/or install distribution artifacts

To learn more about a subcommand, run `./x.py <subcommand> -h`");

        let mut opts = Options::new();
        // Options common to all subcommands
        opts.optflagmulti("v", "verbose", "use verbose output (-vv for very verbose)");
        opts.optflag("i", "incremental", "use incremental compilation");
        opts.optopt("", "config", "TOML configuration file for build", "FILE");
        opts.optopt("", "build", "build target of the stage0 compiler", "BUILD");
        opts.optmulti("", "host", "host targets to build", "HOST");
        opts.optmulti("", "target", "target targets to build", "TARGET");
        opts.optopt("", "on-fail", "command to run on failure", "CMD");
        opts.optopt("", "stage", "stage to build", "N");
        opts.optopt("", "keep-stage", "stage to keep without recompiling", "N");
        opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
        opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
        opts.optflag("h", "help", "print this help message");

        // fn usage()
        let usage = |exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! {
            println!("{}", opts.usage(subcommand_help));
            if !extra_help.is_empty() {
                println!("{}", extra_help);
            }
            process::exit(exit_code);
        };

        // We can't use getopt to parse the options until we have completed specifying which
        // options are valid, but under the current implementation, some options are conditional on
        // the subcommand. Therefore we must manually identify the subcommand first, so that we can
        // complete the definition of the options.  Then we can use the getopt::Matches object from
        // there on out.
        let mut possible_subcommands = args.iter().collect::<Vec<_>>();
        possible_subcommands.retain(|&s| !s.starts_with('-'));
        let subcommand = match possible_subcommands.first() {
            Some(s) => s,
            None => {
                // No subcommand -- show the general usage and subcommand help
                println!("{}\n", subcommand_help);
                process::exit(0);
            }
        };

        // Some subcommands have specific arguments help text
        match subcommand.as_str() {
            "build" => {
                subcommand_help.push_str("\n
Arguments:
    This subcommand accepts a number of paths to directories to the crates
    and/or artifacts to compile. For example:

        ./x.py build src/libcore
        ./x.py build src/libcore src/libproc_macro
        ./x.py build src/libstd --stage 1

    If no arguments are passed then the complete artifacts for that stage are
    also compiled.

        ./x.py build
        ./x.py build --stage 1

    For a quick build with a usable compile, you can pass:

        ./x.py build --stage 1 src/libtest");
            }
            "test" => {
                opts.optmulti("", "test-args", "extra arguments", "ARGS");
                subcommand_help.push_str("\n
Arguments:
    This subcommand accepts a number of paths to directories to tests that
    should be compiled and run. For example:

        ./x.py test src/test/run-pass
        ./x.py test src/libstd --test-args hash_map
        ./x.py test src/libstd --stage 0

    If no arguments are passed then the complete artifacts for that stage are
    compiled and tested.

        ./x.py test
        ./x.py test --stage 1");
            }
            "bench" => {
                opts.optmulti("", "test-args", "extra arguments", "ARGS");
            }
            "doc" => {
                subcommand_help.push_str("\n
Arguments:
    This subcommand accepts a number of paths to directories of documentation
    to build. For example:

        ./x.py doc src/doc/book
        ./x.py doc src/doc/nomicon
        ./x.py doc src/doc/book src/libstd

    If no arguments are passed then everything is documented:

        ./x.py doc
        ./x.py doc --stage 1");
            }
            "dist" => {
                opts.optflag("", "install", "run installer as well");
            }
            _ => { }
        };

        // Done specifying what options are possible, so do the getopts parsing
        let matches = opts.parse(&args[..]).unwrap_or_else(|e| {
            // Invalid argument/option format
            println!("\n{}\n", e);
            usage(1, &opts, &subcommand_help, &extra_help);
        });
        // Get any optional paths which occur after the subcommand
        let cwd = t!(env::current_dir());
        let paths = matches.free[1..].iter().map(|p| cwd.join(p)).collect::<Vec<_>>();

        // All subcommands can have an optional "Available paths" section
        if matches.opt_present("verbose") {
            let flags = Flags::parse(&["build".to_string()]);
            let mut config = Config::default();
            config.build = flags.build.clone();
            let mut build = Build::new(flags, config);
            metadata::build(&mut build);
            let maybe_rules_help = step::build_rules(&build).get_help(subcommand);
            if maybe_rules_help.is_some() {
                extra_help.push_str(maybe_rules_help.unwrap().as_str());
            }
        } else {
            extra_help.push_str(format!("Run `./x.py {} -h -v` to see a list of available paths.",
                     subcommand).as_str());
        }

        // User passed in -h/--help?
        if matches.opt_present("help") {
            usage(0, &opts, &subcommand_help, &extra_help);
        }

        let cmd = match subcommand.as_str() {
            "build" => {
                Subcommand::Build { paths: paths }
            }
            "test" => {
                Subcommand::Test {
                    paths: paths,
                    test_args: matches.opt_strs("test-args"),
                }
            }
            "bench" => {
                Subcommand::Bench {
                    paths: paths,
                    test_args: matches.opt_strs("test-args"),
                }
            }
            "doc" => {
                Subcommand::Doc { paths: paths }
            }
            "clean" => {
                if matches.free.len() > 0 {
                    println!("\nclean takes no arguments\n");
                    usage(1, &opts, &subcommand_help, &extra_help);
                }
                Subcommand::Clean
            }
            "dist" => {
                Subcommand::Dist {
                    paths: paths,
                    install: matches.opt_present("install"),
                }
            }
            _ => {
                usage(1, &opts, &subcommand_help, &extra_help);
            }
        };

        let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| {
            if fs::metadata("config.toml").is_ok() {
                Some(PathBuf::from("config.toml"))
            } else {
                None
            }
        });

        let mut stage = matches.opt_str("stage").map(|j| j.parse().unwrap());

        if matches.opt_present("incremental") {
            if stage.is_none() {
                stage = Some(1);
            }
        }

        Flags {
            verbose: matches.opt_count("verbose"),
            stage: stage,
            on_fail: matches.opt_str("on-fail"),
            keep_stage: matches.opt_str("keep-stage").map(|j| j.parse().unwrap()),
            build: matches.opt_str("build").unwrap_or_else(|| {
                env::var("BUILD").unwrap()
            }),
            host: split(matches.opt_strs("host")),
            target: split(matches.opt_strs("target")),
            config: cfg_file,
            src: matches.opt_str("src").map(PathBuf::from),
            jobs: matches.opt_str("jobs").map(|j| j.parse().unwrap()),
            cmd: cmd,
            incremental: matches.opt_present("incremental"),
        }
    }
}

impl Subcommand {
    pub fn test_args(&self) -> Vec<&str> {
        match *self {
            Subcommand::Test { ref test_args, .. } |
            Subcommand::Bench { ref test_args, .. } => {
                test_args.iter().flat_map(|s| s.split_whitespace()).collect()
            }
            _ => Vec::new(),
        }
    }
}

fn split(s: Vec<String>) -> Vec<String> {
    s.iter().flat_map(|s| s.split(',')).map(|s| s.to_string()).collect()
}
<|endoftext|>


<commit_before>#![feature (plugin, custom_derive)]
#![plugin (serde_macros)]

#[macro_use]
extern crate time_steward as steward;
extern crate rand;
extern crate serde;

use steward::{RowId, DeterministicRandomId, ColumnId, PredictorId, Column, TimeStewardSettings};
use std::marker::PhantomData;
use rand::{Rng, SeedableRng, ChaChaRng};

/*Tried to hunt an ICE, but failed
trait Hack <B> {type Whatever;}
use std::iter::{self, Empty};
struct IntoIter; impl <'a> IntoIterator for & 'a IntoIter {type Item = i32; type IntoIter = Empty <i32>; fn into_iter(self)->Self::IntoIter {iter::empty()}}
struct Original <B> {field: PhantomData <B>}
impl <B> Hack <B> for Original <B> {type Whatever = IntoIter;}
struct Wrapper <B, Inner: Hack <B>> {field: PhantomData <(B, Inner)>,}
impl <B, Inner: Hack <B>> Hack <B> for Wrapper <B, Inner> {type Whatever = Inner::Whatever;}
fn thingy <B, H: Hack <B>>() where for <'a> & 'a H::Whatever: IntoIterator <Item = i32> {}
#[test]
fn chunk() {thingy::<i32, Wrapper <i32, Wrapper <i32, Original<i32>>>>();}
*/

#[derive (Clone, PartialEq, Eq, Serialize, Deserialize, Debug, Default)]
struct Basics;
impl steward::Basics for Basics {
  type Time = DeterministicRandomId;
  type Constants = DeterministicRandomId;
}
  struct ColumnHack;
  impl Column for ColumnHack {
    type FieldType = DeterministicRandomId;
    fn column_id()->ColumnId {ColumnId (0x8e07f5045b91d636)}
  }
// As in, "putting it through its paces"
#[allow (unused_must_use)]
fn paces <Steward: steward::TimeSteward <Basics>, G: Rng> (generator: &mut G)
where Steward::Settings: Clone,
for <'a> & 'a Steward::Snapshot: IntoIterator <Item = steward::SnapshotEntry <'a, Basics>>
{

  let mut settings = Steward::Settings::new();
  settings.insert_predictor (PredictorId (0x59c5a4cce2789300), ColumnHack::column_id(),
    time_steward_predictor! (Basics, struct Predictor {}, | &self, accessor, id | {
      for index in 0.. (id.data() [0] ^ accessor.constants().data() [0]).leading_zeros() {
        let data_0 = DeterministicRandomId::new (& (index, id));
        let data_1 = DeterministicRandomId::new (& (index, id, "something different"));
        accessor.predict_at_time (data_0, time_steward_event! (Basics, struct Event {data: DeterministicRandomId = data_1}, | &self, mutator | {
          let mut generator = mutator.gen::<ChaChaRng>();
          for _ in 0.. (mutator.gen::<u32> ().leading_zeros()*10) {
            match mutator.gen_range::<u8>(0, 16) {
              0 => mutator.set:: <ColumnHack> (RowId::new (& generator.gen::<u8>()), Some (RowId::new (& generator.gen::<u8>()))),
              1 => mutator.set:: <ColumnHack> (RowId::new (& generator.gen::<u8>()), None),
              2 => if mutator.get:: <ColumnHack> (RowId::new (& generator.gen::<u8>())).is_some() { mutator.gen_id(); },
              _ =>(),
            }
          }
        }));
      }
    })
  );

  let mut stew: Steward = Steward::new_empty (RowId::new (& generator.gen::<u64>()), settings.clone());
  let mut snapshots = Vec::new();

  for index in 0..1000 {
    let time = RowId::new (& generator.gen::<u64>());
    match generator.gen_range::<u64> (0, 16) {
      0 => { stew.insert_fiat_event (time, RowId::new (& index),

      time_steward_event! (Basics, struct Event {}, | &self, mutator | {
        let who =RowId::new (& mutator.gen::<u8>());
          mutator.get:: <ColumnHack> (who);
          let who =RowId::new (& mutator.gen::<u8>());
          let what = if mutator.gen() {None} else {Some (mutator.gen_id())};
          mutator.set:: <ColumnHack> (who, what);

         })

      );},
      1 => if let Some (snapshot) = stew.snapshot_before (& time) {snapshots.push (snapshot);},
      2 => if !snapshots.is_empty() {let who = generator.gen_range (0, snapshots.len()); snapshots.remove (who);},
      3 => if let Some (snapshot) = generator.choose (snapshots.as_slice()) { stew = Steward::from_snapshot::<Steward::Snapshot> (snapshot, settings.clone());},
      _ =>(),
    }
  }
}

#[test]
//#[ignore]
fn main() {
  let mut generator = ChaChaRng::from_seed(& [1337]);
  use steward::stewards::{amortized, memoized_flat, flat_to_inefficient_full, crossverified};
  paces:: <crossverified::Steward <Basics,
    PhantomData <ColumnHack>,
    amortized::Steward <Basics>,
    /*flat_to_inefficient_full::Steward <Basics, */memoized_flat::Steward <Basics>/*>*/
  >,_> (&mut generator);
}
<commit_msg>Added some debug messages<commit_after>#![feature (plugin, custom_derive)]
#![plugin (serde_macros)]

#[macro_use]
extern crate time_steward as steward;
extern crate rand;
extern crate serde;

use steward::{RowId, DeterministicRandomId, ColumnId, PredictorId, Column, TimeStewardSettings};
use std::marker::PhantomData;
use rand::{Rng, SeedableRng, ChaChaRng};

macro_rules! printlnerr(
    ($($arg:tt)*) => { {use std::io::Write;
        let r = writeln!(&mut ::std::io::stderr(), $($arg)*);
        r.expect("failed printing to stderr");
    } }
);

/*Tried to hunt an ICE, but failed
trait Hack <B> {type Whatever;}
use std::iter::{self, Empty};
struct IntoIter; impl <'a> IntoIterator for & 'a IntoIter {type Item = i32; type IntoIter = Empty <i32>; fn into_iter(self)->Self::IntoIter {iter::empty()}}
struct Original <B> {field: PhantomData <B>}
impl <B> Hack <B> for Original <B> {type Whatever = IntoIter;}
struct Wrapper <B, Inner: Hack <B>> {field: PhantomData <(B, Inner)>,}
impl <B, Inner: Hack <B>> Hack <B> for Wrapper <B, Inner> {type Whatever = Inner::Whatever;}
fn thingy <B, H: Hack <B>>() where for <'a> & 'a H::Whatever: IntoIterator <Item = i32> {}
#[test]
fn chunk() {thingy::<i32, Wrapper <i32, Wrapper <i32, Original<i32>>>>();}
*/

#[derive (Clone, PartialEq, Eq, Serialize, Deserialize, Debug, Default)]
struct Basics;
impl steward::Basics for Basics {
  type Time = DeterministicRandomId;
  type Constants = DeterministicRandomId;
}
  struct ColumnHack;
  impl Column for ColumnHack {
    type FieldType = DeterministicRandomId;
    fn column_id()->ColumnId {ColumnId (0x8e07f5045b91d636)}
  }
// As in, "putting it through its paces"
#[allow (unused_must_use)]
fn paces <Steward: steward::TimeSteward <Basics>, G: Rng> (generator: &mut G)
where Steward::Settings: Clone,
for <'a> & 'a Steward::Snapshot: IntoIterator <Item = steward::SnapshotEntry <'a, Basics>>
{

  let mut settings = Steward::Settings::new();
  settings.insert_predictor (PredictorId (0x59c5a4cce2789300), ColumnHack::column_id(),
    time_steward_predictor! (Basics, struct Predictor {}, | &self, accessor, id | {
      for index in 0.. (id.data() [0] ^ accessor.constants().data() [0]).leading_zeros() {
        let data_0 = DeterministicRandomId::new (& (index, id));
        let data_1 = DeterministicRandomId::new (& (index, id, "something different"));
        accessor.predict_at_time (data_0, time_steward_event! (Basics, struct Event {data: DeterministicRandomId = data_1}, | &self, mutator | {
          let mut generator = mutator.gen::<ChaChaRng>();
          for _ in 0.. (mutator.gen::<u32> ().leading_zeros()*10) {
            match mutator.gen_range::<u8>(0, 16) {
              0 => mutator.set:: <ColumnHack> (RowId::new (& generator.gen::<u8>()), Some (RowId::new (& generator.gen::<u8>()))),
              1 => mutator.set:: <ColumnHack> (RowId::new (& generator.gen::<u8>()), None),
              2 => if mutator.get:: <ColumnHack> (RowId::new (& generator.gen::<u8>())).is_some() { mutator.gen_id(); },
              _ =>(),
            }
          }
        }));
      }
    })
  );

  let mut stew: Steward = Steward::new_empty (RowId::new (& generator.gen::<u64>()), settings.clone());
  let mut snapshots = Vec::new();

  for index in 0..1000 {
    let time = RowId::new (& generator.gen::<u64>());
    match generator.gen_range::<u64> (0, 16) {
      0 => { printlnerr!("inserting fiat event"); stew.insert_fiat_event (time, RowId::new (& index),

      time_steward_event! (Basics, struct Event {}, | &self, mutator | {
        let who =RowId::new (& mutator.gen::<u8>());
          mutator.get:: <ColumnHack> (who);
          let who =RowId::new (& mutator.gen::<u8>());
          let what = if mutator.gen() {None} else {Some (mutator.gen_id())};
          mutator.set:: <ColumnHack> (who, what);

         })

      );},
      1 => if let Some (snapshot) = stew.snapshot_before (& time) {printlnerr!("recorded snapshot"); snapshots.push (snapshot);},
      2 => if !snapshots.is_empty() {printlnerr!("deleting_snapshot"); let who = generator.gen_range (0, snapshots.len()); snapshots.remove (who);},
      3 => if let Some (snapshot) = generator.choose (snapshots.as_slice()) { printlnerr!("reloading from snapshot"); stew = Steward::from_snapshot::<Steward::Snapshot> (snapshot, settings.clone());},
      _ =>(),
    }
  }
}

#[test]
//#[ignore]
fn main() {
  let mut generator = ChaChaRng::from_seed(& [1337]);
  use steward::stewards::{amortized, memoized_flat, flat_to_inefficient_full, crossverified};
  paces:: <crossverified::Steward <Basics,
    PhantomData <ColumnHack>,
    amortized::Steward <Basics>,
    /*flat_to_inefficient_full::Steward <Basics, */memoized_flat::Steward <Basics>/*>*/
  >,_> (&mut generator);
}
<|endoftext|>


<commit_before><commit_msg>Auto merge of #60 - matthiasbeyer:notes-open-include-tags, r=matthiasbeyer<commit_after><|endoftext|>


<commit_before>use gen::GenError;

pub trait SerializeFn<I>: Fn(I) -> Result<I, GenError> {}

impl<I, F:  Fn(I) ->Result<I, GenError>> SerializeFn<I> for F {}

pub fn slice<'a, S: 'a + AsRef<[u8]>>(data: S) -> impl SerializeFn<&'a mut [u8]> {
    let len = data.as_ref().len();

    move |out: &'a mut [u8]| {
        if out.len() < len {
            Err(GenError::BufferTooSmall(len))
        } else {
            (&mut out[..len]).copy_from_slice(data.as_ref());
            Ok(&mut out[len..])
        }
    }
}

pub fn string<'a, S: 'a+AsRef<str>>(data: S) -> impl SerializeFn<&'a mut [u8]> {

    let len = data.as_ref().len();
    move |out: &'a mut [u8]| {
        if out.len() < len {
            Err(GenError::BufferTooSmall(len))
        } else {
            (&mut out[..len]).copy_from_slice(data.as_ref().as_bytes());
            Ok(&mut out[len..])
        }
    }
}

use std::io::{Cursor, Write};
use std::fmt;
pub fn hex<'a, S: 'a + fmt::UpperHex>(data: S) -> impl SerializeFn<&'a mut [u8]> {

  move |out: &'a mut [u8]| {
    let mut c = Cursor::new(out);
    match write!(&mut c, "{:X}", data) {
      Err(_) => Err(GenError::CustomError(42)),
      Ok(_) => {
        let pos = c.position() as usize;
        let out = c.into_inner();
        Ok(&mut out[pos..])
      }
    }
  }
}

pub fn skip<'a>(len: usize) -> impl SerializeFn<&'a mut [u8]> {

    move |out: &'a mut [u8]| {
        if out.len() < len {
            Err(GenError::BufferTooSmall(len))
        } else {
            Ok(&mut out[len..])
        }
    }
}

pub fn position<'a, F>(f: F) -> impl Fn(&'a mut [u8]) -> Result<(&'a mut [u8], &'a mut [u8]), GenError>
  where F: SerializeFn<&'a mut [u8]> {

    move |out: &'a mut [u8]| {
        unsafe {
            let ptr = out.as_mut_ptr();
            let out = f(out)?;
            let len = out.as_ptr() as usize - ptr as usize;

            Ok((std::slice::from_raw_parts_mut(ptr, len), out))
        }
    }
}

fn pair<F, G, I>(first: F, second: G) -> impl SerializeFn<I>
where F: SerializeFn<I>,
      G: SerializeFn<I> {

  move |out: I| {
    let out = first(out)?;
    second(out)
  }
}

fn cond<F, G, I>(condition: bool, f: F) -> impl SerializeFn<I>
where F: SerializeFn<I>, {

  move |out: I| {
    if condition {
      f(out)
    } else {
      Ok(out)
    }
  }
}

pub fn all<'a, 'b, G, I, It>(values: It) -> impl SerializeFn<I> + 'a
  where G: SerializeFn<I> + 'b,
        It: 'a + Clone + Iterator<Item=G> {

  move |mut out: I| {
    let it = values.clone();

    for v in it {
      out = v(out)?;
    }

    Ok(out)
  }
}

pub fn separated_list<'a, 'b, 'c, F, G, I, It: Iterator<Item=G>, Arg: 'a+Clone+IntoIterator<Item=G, IntoIter=It>>(sep: F, values: Arg) -> impl SerializeFn<I> + 'a
  where F: SerializeFn<I> + 'b + 'a,
        G: SerializeFn<I> + 'c {

  move |mut out: I| {
    let mut it = values.clone().into_iter();
    match it.next() {
      None => return Ok(out),
      Some(first) => {
        out = first(out)?;
      }
    }

    for v in it {
      out = sep(out)?;
      out = v(out)?;
    }

    Ok(out)
  }
}

pub fn be_u8<'a>(i: u8) -> impl SerializeFn<&'a mut [u8]> {
   let len = 1;

    move |out: &'a mut [u8]| {
        if out.len() < len {
            Err(GenError::BufferTooSmall(len))
        } else {
            out[0] = i;
            Ok(&mut out[len..])
        }
    }
}

pub fn be_u16<'a>(i: u16) -> impl SerializeFn<&'a mut [u8]> {
   let len = 2;

    move |out: &'a mut [u8]| {
        if out.len() < len {
            Err(GenError::BufferTooSmall(len))
        } else {
            out[0] = ((i >> 8) & 0xff) as u8;
            out[1] = (i        & 0xff) as u8;
            Ok(&mut out[len..])
        }
    }
}

pub fn be_u32<'a>(i: u32) -> impl SerializeFn<&'a mut [u8]> {
   let len = 4;

    move |out: &'a mut [u8]| {
        if out.len() < len {
            Err(GenError::BufferTooSmall(len))
        } else {
            out[0] = ((i >> 24) & 0xff) as u8;
            out[1] = ((i >> 16) & 0xff) as u8;
            out[2] = ((i >> 8)  & 0xff) as u8;
            out[3] = (i         & 0xff) as u8;
            Ok(&mut out[len..])
        }
    }
}

pub fn be_u64<'a>(i: u64) -> impl SerializeFn<&'a mut [u8]> {
   let len = 8;

    move |out: &'a mut [u8]| {
        if out.len() < len {
            Err(GenError::BufferTooSmall(len))
        } else {
            out[0] = ((i >> 56) & 0xff) as u8;
            out[1] = ((i >> 48) & 0xff) as u8;
            out[2] = ((i >> 40) & 0xff) as u8;
            out[3] = ((i >> 32) & 0xff) as u8;
            out[4] = ((i >> 24) & 0xff) as u8;
            out[5] = ((i >> 16) & 0xff) as u8;
            out[6] = ((i >> 8)  & 0xff) as u8;
            out[7] = (i         & 0xff) as u8;
            Ok(&mut out[len..])
        }
    }
}

pub fn be_i8<'a>(i: i8) -> impl SerializeFn<&'a mut [u8]> {
    be_u8(i as u8)
}

pub fn be_i16<'a>(i: i16) -> impl SerializeFn<&'a mut [u8]> {
    be_u16(i as u16)
}

pub fn be_i32<'a>(i: i32) -> impl SerializeFn<&'a mut [u8]> {
    be_u32(i as u32)
}

pub fn be_i64<'a>(i: i64) -> impl SerializeFn<&'a mut [u8]> {
    be_u64(i as u64)
}

pub fn be_f32<'a>(i: f32) -> impl SerializeFn<&'a mut [u8]> {
    be_u32(unsafe { std::mem::transmute::<f32, u32>(i) })
}

pub fn be_f64<'a>(i: f64) -> impl SerializeFn<&'a mut [u8]> {
    be_u64(unsafe { std::mem::transmute::<f64, u64>(i) })
}

pub fn le_u8<'a>(i: u8) -> impl SerializeFn<&'a mut [u8]> {
   let len = 1;

    move |out: &'a mut [u8]| {
        if out.len() < len {
            Err(GenError::BufferTooSmall(len))
        } else {
            out[0] = i;
            Ok(&mut out[len..])
        }
    }
}

pub fn le_u16<'a>(i: u16) -> impl SerializeFn<&'a mut [u8]> {
   let len = 2;

    move |out: &'a mut [u8]| {
        if out.len() < len {
            Err(GenError::BufferTooSmall(len))
        } else {
            out[0] = (i        & 0xff) as u8;
            out[1] = ((i >> 8) & 0xff) as u8;
            Ok(&mut out[len..])
        }
    }
}

pub fn le_u32<'a>(i: u32) -> impl SerializeFn<&'a mut [u8]> {
   let len = 4;

    move |out: &'a mut [u8]| {
        if out.len() < len {
            Err(GenError::BufferTooSmall(len))
        } else {
            out[0] = (i         & 0xff) as u8;
            out[1] = ((i >> 8)  & 0xff) as u8;
            out[2] = ((i >> 16) & 0xff) as u8;
            out[3] = ((i >> 24) & 0xff) as u8;
            Ok(&mut out[len..])
        }
    }
}

pub fn le_u64<'a>(i: u64) -> impl SerializeFn<&'a mut [u8]> {
   let len = 8;

    move |out: &'a mut [u8]| {
        if out.len() < len {
            Err(GenError::BufferTooSmall(len))
        } else {
            out[0] = (i         & 0xff) as u8;
            out[1] = ((i >> 8)  & 0xff) as u8;
            out[2] = ((i >> 16) & 0xff) as u8;
            out[3] = ((i >> 24) & 0xff) as u8;
            out[4] = ((i >> 32) & 0xff) as u8;
            out[5] = ((i >> 40) & 0xff) as u8;
            out[6] = ((i >> 48) & 0xff) as u8;
            out[7] = ((i >> 56) & 0xff) as u8;
            Ok(&mut out[len..])
        }
    }
}

pub fn le_i8<'a>(i: i8) -> impl SerializeFn<&'a mut [u8]> {
    le_u8(i as u8)
}

pub fn le_i16<'a>(i: i16) -> impl SerializeFn<&'a mut [u8]> {
    le_u16(i as u16)
}

pub fn le_i32<'a>(i: i32) -> impl SerializeFn<&'a mut [u8]> {
    le_u32(i as u32)
}

pub fn le_i64<'a>(i: i64) -> impl SerializeFn<&'a mut [u8]> {
    le_u64(i as u64)
}

pub fn le_f32<'a>(i: f32) -> impl SerializeFn<&'a mut [u8]> {
    le_u32(unsafe { std::mem::transmute::<f32, u32>(i) })
}

pub fn le_f64<'a>(i: f64) -> impl SerializeFn<&'a mut [u8]> {
    le_u64(unsafe { std::mem::transmute::<f64, u64>(i) })
}

pub fn many_ref<'a, E, It, I, F, G, O>(items: I, generator: F) -> impl SerializeFn<O> + 'a
where
    It: Iterator<Item = E> + Clone + 'a,
    I: IntoIterator<Item = E, IntoIter = It>,
    F: Fn(E) -> G + 'a,
    G: SerializeFn<O> + 'a,
    O: 'a
{
    let items = items.into_iter();
    move |mut out: O| {
        for item in items.clone() {
            out = generator(item)(out)?;
        }
        Ok(out)
    }
}

//missing combinators:
//or
//empty
//then
//stream
//length_value
//text print
//text upperhex
//text lowerhex
<commit_msg>add the length combinator<commit_after>use gen::GenError;

pub trait SerializeFn<I>: Fn(I) -> Result<I, GenError> {}

impl<I, F:  Fn(I) ->Result<I, GenError>> SerializeFn<I> for F {}

pub fn slice<'a, S: 'a + AsRef<[u8]>>(data: S) -> impl SerializeFn<&'a mut [u8]> {
    let len = data.as_ref().len();

    move |out: &'a mut [u8]| {
        if out.len() < len {
            Err(GenError::BufferTooSmall(len))
        } else {
            (&mut out[..len]).copy_from_slice(data.as_ref());
            Ok(&mut out[len..])
        }
    }
}

pub fn string<'a, S: 'a+AsRef<str>>(data: S) -> impl SerializeFn<&'a mut [u8]> {

    let len = data.as_ref().len();
    move |out: &'a mut [u8]| {
        if out.len() < len {
            Err(GenError::BufferTooSmall(len))
        } else {
            (&mut out[..len]).copy_from_slice(data.as_ref().as_bytes());
            Ok(&mut out[len..])
        }
    }
}

use std::io::{Cursor, Write};
use std::fmt;
pub fn hex<'a, S: 'a + fmt::UpperHex>(data: S) -> impl SerializeFn<&'a mut [u8]> {

  move |out: &'a mut [u8]| {
    let mut c = Cursor::new(out);
    match write!(&mut c, "{:X}", data) {
      Err(_) => Err(GenError::CustomError(42)),
      Ok(_) => {
        let pos = c.position() as usize;
        let out = c.into_inner();
        Ok(&mut out[pos..])
      }
    }
  }
}

pub fn skip<'a>(len: usize) -> impl SerializeFn<&'a mut [u8]> {

    move |out: &'a mut [u8]| {
        if out.len() < len {
            Err(GenError::BufferTooSmall(len))
        } else {
            Ok(&mut out[len..])
        }
    }
}

pub fn position<'a, F>(f: F) -> impl Fn(&'a mut [u8]) -> Result<(&'a mut [u8], &'a mut [u8]), GenError>
  where F: SerializeFn<&'a mut [u8]> {

    move |out: &'a mut [u8]| {
        unsafe {
            let ptr = out.as_mut_ptr();
            let out = f(out)?;
            let len = out.as_ptr() as usize - ptr as usize;

            Ok((std::slice::from_raw_parts_mut(ptr, len), out))
        }
    }
}

fn pair<F, G, I>(first: F, second: G) -> impl SerializeFn<I>
where F: SerializeFn<I>,
      G: SerializeFn<I> {

  move |out: I| {
    let out = first(out)?;
    second(out)
  }
}

fn cond<F, G, I>(condition: bool, f: F) -> impl SerializeFn<I>
where F: SerializeFn<I>, {

  move |out: I| {
    if condition {
      f(out)
    } else {
      Ok(out)
    }
  }
}

pub fn all<'a, 'b, G, I, It>(values: It) -> impl SerializeFn<I> + 'a
  where G: SerializeFn<I> + 'b,
        It: 'a + Clone + Iterator<Item=G> {

  move |mut out: I| {
    let it = values.clone();

    for v in it {
      out = v(out)?;
    }

    Ok(out)
  }
}

pub fn separated_list<'a, 'b, 'c, F, G, I, It: Iterator<Item=G>, Arg: 'a+Clone+IntoIterator<Item=G, IntoIter=It>>(sep: F, values: Arg) -> impl SerializeFn<I> + 'a
  where F: SerializeFn<I> + 'b + 'a,
        G: SerializeFn<I> + 'c {

  move |mut out: I| {
    let mut it = values.clone().into_iter();
    match it.next() {
      None => return Ok(out),
      Some(first) => {
        out = first(out)?;
      }
    }

    for v in it {
      out = sep(out)?;
      out = v(out)?;
    }

    Ok(out)
  }
}

pub fn be_u8<'a>(i: u8) -> impl SerializeFn<&'a mut [u8]> {
   let len = 1;

    move |out: &'a mut [u8]| {
        if out.len() < len {
            Err(GenError::BufferTooSmall(len))
        } else {
            out[0] = i;
            Ok(&mut out[len..])
        }
    }
}

pub fn be_u16<'a>(i: u16) -> impl SerializeFn<&'a mut [u8]> {
   let len = 2;

    move |out: &'a mut [u8]| {
        if out.len() < len {
            Err(GenError::BufferTooSmall(len))
        } else {
            out[0] = ((i >> 8) & 0xff) as u8;
            out[1] = (i        & 0xff) as u8;
            Ok(&mut out[len..])
        }
    }
}

pub fn be_u32<'a>(i: u32) -> impl SerializeFn<&'a mut [u8]> {
   let len = 4;

    move |out: &'a mut [u8]| {
        if out.len() < len {
            Err(GenError::BufferTooSmall(len))
        } else {
            out[0] = ((i >> 24) & 0xff) as u8;
            out[1] = ((i >> 16) & 0xff) as u8;
            out[2] = ((i >> 8)  & 0xff) as u8;
            out[3] = (i         & 0xff) as u8;
            Ok(&mut out[len..])
        }
    }
}

pub fn be_u64<'a>(i: u64) -> impl SerializeFn<&'a mut [u8]> {
   let len = 8;

    move |out: &'a mut [u8]| {
        if out.len() < len {
            Err(GenError::BufferTooSmall(len))
        } else {
            out[0] = ((i >> 56) & 0xff) as u8;
            out[1] = ((i >> 48) & 0xff) as u8;
            out[2] = ((i >> 40) & 0xff) as u8;
            out[3] = ((i >> 32) & 0xff) as u8;
            out[4] = ((i >> 24) & 0xff) as u8;
            out[5] = ((i >> 16) & 0xff) as u8;
            out[6] = ((i >> 8)  & 0xff) as u8;
            out[7] = (i         & 0xff) as u8;
            Ok(&mut out[len..])
        }
    }
}

pub fn be_i8<'a>(i: i8) -> impl SerializeFn<&'a mut [u8]> {
    be_u8(i as u8)
}

pub fn be_i16<'a>(i: i16) -> impl SerializeFn<&'a mut [u8]> {
    be_u16(i as u16)
}

pub fn be_i32<'a>(i: i32) -> impl SerializeFn<&'a mut [u8]> {
    be_u32(i as u32)
}

pub fn be_i64<'a>(i: i64) -> impl SerializeFn<&'a mut [u8]> {
    be_u64(i as u64)
}

pub fn be_f32<'a>(i: f32) -> impl SerializeFn<&'a mut [u8]> {
    be_u32(unsafe { std::mem::transmute::<f32, u32>(i) })
}

pub fn be_f64<'a>(i: f64) -> impl SerializeFn<&'a mut [u8]> {
    be_u64(unsafe { std::mem::transmute::<f64, u64>(i) })
}

pub fn le_u8<'a>(i: u8) -> impl SerializeFn<&'a mut [u8]> {
   let len = 1;

    move |out: &'a mut [u8]| {
        if out.len() < len {
            Err(GenError::BufferTooSmall(len))
        } else {
            out[0] = i;
            Ok(&mut out[len..])
        }
    }
}

pub fn le_u16<'a>(i: u16) -> impl SerializeFn<&'a mut [u8]> {
   let len = 2;

    move |out: &'a mut [u8]| {
        if out.len() < len {
            Err(GenError::BufferTooSmall(len))
        } else {
            out[0] = (i        & 0xff) as u8;
            out[1] = ((i >> 8) & 0xff) as u8;
            Ok(&mut out[len..])
        }
    }
}

pub fn le_u32<'a>(i: u32) -> impl SerializeFn<&'a mut [u8]> {
   let len = 4;

    move |out: &'a mut [u8]| {
        if out.len() < len {
            Err(GenError::BufferTooSmall(len))
        } else {
            out[0] = (i         & 0xff) as u8;
            out[1] = ((i >> 8)  & 0xff) as u8;
            out[2] = ((i >> 16) & 0xff) as u8;
            out[3] = ((i >> 24) & 0xff) as u8;
            Ok(&mut out[len..])
        }
    }
}

pub fn le_u64<'a>(i: u64) -> impl SerializeFn<&'a mut [u8]> {
   let len = 8;

    move |out: &'a mut [u8]| {
        if out.len() < len {
            Err(GenError::BufferTooSmall(len))
        } else {
            out[0] = (i         & 0xff) as u8;
            out[1] = ((i >> 8)  & 0xff) as u8;
            out[2] = ((i >> 16) & 0xff) as u8;
            out[3] = ((i >> 24) & 0xff) as u8;
            out[4] = ((i >> 32) & 0xff) as u8;
            out[5] = ((i >> 40) & 0xff) as u8;
            out[6] = ((i >> 48) & 0xff) as u8;
            out[7] = ((i >> 56) & 0xff) as u8;
            Ok(&mut out[len..])
        }
    }
}

pub fn le_i8<'a>(i: i8) -> impl SerializeFn<&'a mut [u8]> {
    le_u8(i as u8)
}

pub fn le_i16<'a>(i: i16) -> impl SerializeFn<&'a mut [u8]> {
    le_u16(i as u16)
}

pub fn le_i32<'a>(i: i32) -> impl SerializeFn<&'a mut [u8]> {
    le_u32(i as u32)
}

pub fn le_i64<'a>(i: i64) -> impl SerializeFn<&'a mut [u8]> {
    le_u64(i as u64)
}

pub fn le_f32<'a>(i: f32) -> impl SerializeFn<&'a mut [u8]> {
    le_u32(unsafe { std::mem::transmute::<f32, u32>(i) })
}

pub fn le_f64<'a>(i: f64) -> impl SerializeFn<&'a mut [u8]> {
    le_u64(unsafe { std::mem::transmute::<f64, u64>(i) })
}

pub fn many_ref<'a, E, It, I, F, G, O>(items: I, generator: F) -> impl SerializeFn<O> + 'a
where
    It: Iterator<Item = E> + Clone + 'a,
    I: IntoIterator<Item = E, IntoIter = It>,
    F: Fn(E) -> G + 'a,
    G: SerializeFn<O> + 'a,
    O: 'a
{
    let items = items.into_iter();
    move |mut out: O| {
        for item in items.clone() {
            out = generator(item)(out)?;
        }
        Ok(out)
    }
}

pub fn length<'a, F>(f: F) -> impl Fn(&'a mut [u8]) -> Result<(usize, &'a mut [u8]), GenError>
  where F: SerializeFn<&'a mut [u8]> {
  move |out: &'a mut [u8]| {
    let start = out.as_ptr() as usize;

    let out = f(out)?;

    let end = out.as_ptr() as usize;
    Ok((end - start, out))
  }
}
//missing combinators:
//or
//empty
//then
//stream
//length_value
//text print
//text upperhex
//text lowerhex
<|endoftext|>