<commit_before>// APIs that changed in FreeBSD12

pub type nlink_t = u64;
pub type dev_t = u64;
pub type ino_t = ::c_ulong;
pub type shmatt_t = ::c_uint;

s! {
    pub struct shmid_ds {
        pub shm_perm: ::ipc_perm,
        pub shm_segsz: ::size_t,
        pub shm_lpid: ::pid_t,
        pub shm_cpid: ::pid_t,
        pub shm_nattch: ::shmatt_t,
        pub shm_atime: ::time_t,
        pub shm_dtime: ::time_t,
        pub shm_ctime: ::time_t,
    }

    pub struct kevent {
        pub ident: ::uintptr_t,
        pub filter: ::c_short,
        pub flags: ::c_ushort,
        pub fflags: ::c_uint,
        pub data: ::intptr_t,
        pub udata: *mut ::c_void,
        pub ext: [u64; 4],
    }
}

s_no_extra_traits! {
    pub struct dirent {
        pub d_fileno: ::ino_t,
        pub d_off: ::off_t,
        pub d_reclen: u16,
        pub d_type: u8,
        d_pad0: u8,
        pub d_namlen: u16,
        d_pad1: u16,
        pub d_name: [::c_char; 256],
    }

    pub struct statfs {
        pub f_version: u32,
        pub f_type: u32,
        pub f_flags: u64,
        pub f_bsize: u64,
        pub f_iosize: u64,
        pub f_blocks: u64,
        pub f_bfree: u64,
        pub f_bavail: i64,
        pub f_files: u64,
        pub f_ffree: i64,
        pub f_syncwrites: u64,
        pub f_asyncwrites: u64,
        pub f_syncreads: u64,
        pub f_asyncreads: u64,
        f_spare: [u64; 10],
        pub f_namemax: u32,
        pub f_owner: ::uid_t,
        pub f_fsid: ::fsid_t,
        f_charspare: [::c_char; 80],
        pub f_fstypename: [::c_char; 16],
        pub f_mntfromname: [::c_char; 1024],
        pub f_mntonname: [::c_char; 1024],
    }
}

cfg_if! {
    if #[cfg(feature = "extra_traits")] {
        impl PartialEq for statfs {
            fn eq(&self, other: &statfs) -> bool {
                self.f_version == other.f_version
                    && self.f_type == other.f_type
                    && self.f_flags == other.f_flags
                    && self.f_bsize == other.f_bsize
                    && self.f_iosize == other.f_iosize
                    && self.f_blocks == other.f_blocks
                    && self.f_bfree == other.f_bfree
                    && self.f_bavail == other.f_bavail
                    && self.f_files == other.f_files
                    && self.f_ffree == other.f_ffree
                    && self.f_syncwrites == other.f_syncwrites
                    && self.f_asyncwrites == other.f_asyncwrites
                    && self.f_syncreads == other.f_syncreads
                    && self.f_asyncreads == other.f_asyncreads
                    && self.f_namemax == other.f_namemax
                    && self.f_owner == other.f_owner
                    && self.f_fsid == other.f_fsid
                    && self.f_fstypename == other.f_fstypename
                    && self
                    .f_mntfromname
                    .iter()
                    .zip(other.f_mntfromname.iter())
                    .all(|(a,b)| a == b)
                    && self
                    .f_mntonname
                    .iter()
                    .zip(other.f_mntonname.iter())
                    .all(|(a,b)| a == b)
            }
        }
        impl Eq for statfs {}
        impl ::fmt::Debug for statfs {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("statfs")
                    .field("f_bsize", &self.f_bsize)
                    .field("f_iosize", &self.f_iosize)
                    .field("f_blocks", &self.f_blocks)
                    .field("f_bfree", &self.f_bfree)
                    .field("f_bavail", &self.f_bavail)
                    .field("f_files", &self.f_files)
                    .field("f_ffree", &self.f_ffree)
                    .field("f_syncwrites", &self.f_syncwrites)
                    .field("f_asyncwrites", &self.f_asyncwrites)
                    .field("f_syncreads", &self.f_syncreads)
                    .field("f_asyncreads", &self.f_asyncreads)
                    .field("f_namemax", &self.f_namemax)
                    .field("f_owner", &self.f_owner)
                    .field("f_fsid", &self.f_fsid)
                    .field("f_fstypename", &self.f_fstypename)
                    .field("f_mntfromname", &&self.f_mntfromname[..])
                    .field("f_mntonname", &&self.f_mntonname[..])
                    .finish()
            }
        }
        impl ::hash::Hash for statfs {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.f_version.hash(state);
                self.f_type.hash(state);
                self.f_flags.hash(state);
                self.f_bsize.hash(state);
                self.f_iosize.hash(state);
                self.f_blocks.hash(state);
                self.f_bfree.hash(state);
                self.f_bavail.hash(state);
                self.f_files.hash(state);
                self.f_ffree.hash(state);
                self.f_syncwrites.hash(state);
                self.f_asyncwrites.hash(state);
                self.f_syncreads.hash(state);
                self.f_asyncreads.hash(state);
                self.f_namemax.hash(state);
                self.f_owner.hash(state);
                self.f_fsid.hash(state);
                self.f_charspare.hash(state);
                self.f_fstypename.hash(state);
                self.f_mntfromname.hash(state);
                self.f_mntonname.hash(state);
            }
        }

        impl PartialEq for dirent {
            fn eq(&self, other: &dirent) -> bool {
                self.d_fileno == other.d_fileno
                    && self.d_off == other.d_off
                    && self.d_reclen == other.d_reclen
                    && self.d_type == other.d_type
                    && self.d_namlen == other.d_namlen
                    && self
                    .d_name[..self.d_namlen as _]
                    .iter()
                    .zip(other.d_name.iter())
                    .all(|(a,b)| a == b)
            }
        }
        impl Eq for dirent {}
        impl ::fmt::Debug for dirent {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("dirent")
                    .field("d_fileno", &self.d_fileno)
                    .field("d_off", &self.d_off)
                    .field("d_reclen", &self.d_reclen)
                    .field("d_type", &self.d_type)
                    .field("d_namlen", &self.d_namlen)
                    .field("d_name", &&self.d_name[..self.d_namlen as _])
                    .finish()
            }
        }
        impl ::hash::Hash for dirent {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.d_fileno.hash(state);
                self.d_off.hash(state);
                self.d_reclen.hash(state);
                self.d_type.hash(state);
                self.d_namlen.hash(state);
                self.d_name[..self.d_namlen as _].hash(state);
            }
        }
    }
}

pub const F_ADD_SEALS: ::c_int = 19;
pub const F_GET_SEALS: ::c_int = 20;
pub const F_SEAL_SEAL: ::c_int = 0x0001;
pub const F_SEAL_SHRINK: ::c_int = 0x0002;
pub const F_SEAL_GROW: ::c_int = 0x0004;
pub const F_SEAL_WRITE: ::c_int = 0x0008;

pub const GRND_NONBLOCK: ::c_uint = 0x1;
pub const GRND_RANDOM: ::c_uint = 0x2;

cfg_if! {
    if #[cfg(not(freebsd13))] {
        pub const ELAST: ::c_int = 96;
    } else {
        pub const EINTEGRITY: ::c_int = 97;
        pub const ELAST: ::c_int = 97;
        pub const GRND_INSECURE: ::c_uint = 0x4;
    }
}

extern "C" {
    pub fn setgrent();
    pub fn mprotect(
        addr: *mut ::c_void,
        len: ::size_t,
        prot: ::c_int,
    ) -> ::c_int;
    pub fn freelocale(loc: ::locale_t);
    pub fn msgrcv(
        msqid: ::c_int,
        msgp: *mut ::c_void,
        msgsz: ::size_t,
        msgtyp: ::c_long,
        msgflg: ::c_int,
    ) -> ::ssize_t;
    pub fn clock_nanosleep(
        clk_id: ::clockid_t,
        flags: ::c_int,
        rqtp: *const ::timespec,
        rmtp: *mut ::timespec,
    ) -> ::c_int;

    pub fn fdatasync(fd: ::c_int) -> ::c_int;

    pub fn getrandom(
        buf: *mut ::c_void,
        buflen: ::size_t,
        flags: ::c_uint
    ) -> ::ssize_t;
}

cfg_if! {
    if #[cfg(any(target_arch = "x86_64",
                 target_arch = "aarch64"))] {
        mod b64;
        pub use self::b64::*;
    }
}
<commit_msg>Auto merge of #2013 - Thomasdezeeuw:freebsd-constants, r=JohnTitor<commit_after>// APIs that changed in FreeBSD12

pub type nlink_t = u64;
pub type dev_t = u64;
pub type ino_t = ::c_ulong;
pub type shmatt_t = ::c_uint;

s! {
    pub struct shmid_ds {
        pub shm_perm: ::ipc_perm,
        pub shm_segsz: ::size_t,
        pub shm_lpid: ::pid_t,
        pub shm_cpid: ::pid_t,
        pub shm_nattch: ::shmatt_t,
        pub shm_atime: ::time_t,
        pub shm_dtime: ::time_t,
        pub shm_ctime: ::time_t,
    }

    pub struct kevent {
        pub ident: ::uintptr_t,
        pub filter: ::c_short,
        pub flags: ::c_ushort,
        pub fflags: ::c_uint,
        pub data: ::intptr_t,
        pub udata: *mut ::c_void,
        pub ext: [u64; 4],
    }
}

s_no_extra_traits! {
    pub struct dirent {
        pub d_fileno: ::ino_t,
        pub d_off: ::off_t,
        pub d_reclen: u16,
        pub d_type: u8,
        d_pad0: u8,
        pub d_namlen: u16,
        d_pad1: u16,
        pub d_name: [::c_char; 256],
    }

    pub struct statfs {
        pub f_version: u32,
        pub f_type: u32,
        pub f_flags: u64,
        pub f_bsize: u64,
        pub f_iosize: u64,
        pub f_blocks: u64,
        pub f_bfree: u64,
        pub f_bavail: i64,
        pub f_files: u64,
        pub f_ffree: i64,
        pub f_syncwrites: u64,
        pub f_asyncwrites: u64,
        pub f_syncreads: u64,
        pub f_asyncreads: u64,
        f_spare: [u64; 10],
        pub f_namemax: u32,
        pub f_owner: ::uid_t,
        pub f_fsid: ::fsid_t,
        f_charspare: [::c_char; 80],
        pub f_fstypename: [::c_char; 16],
        pub f_mntfromname: [::c_char; 1024],
        pub f_mntonname: [::c_char; 1024],
    }
}

cfg_if! {
    if #[cfg(feature = "extra_traits")] {
        impl PartialEq for statfs {
            fn eq(&self, other: &statfs) -> bool {
                self.f_version == other.f_version
                    && self.f_type == other.f_type
                    && self.f_flags == other.f_flags
                    && self.f_bsize == other.f_bsize
                    && self.f_iosize == other.f_iosize
                    && self.f_blocks == other.f_blocks
                    && self.f_bfree == other.f_bfree
                    && self.f_bavail == other.f_bavail
                    && self.f_files == other.f_files
                    && self.f_ffree == other.f_ffree
                    && self.f_syncwrites == other.f_syncwrites
                    && self.f_asyncwrites == other.f_asyncwrites
                    && self.f_syncreads == other.f_syncreads
                    && self.f_asyncreads == other.f_asyncreads
                    && self.f_namemax == other.f_namemax
                    && self.f_owner == other.f_owner
                    && self.f_fsid == other.f_fsid
                    && self.f_fstypename == other.f_fstypename
                    && self
                    .f_mntfromname
                    .iter()
                    .zip(other.f_mntfromname.iter())
                    .all(|(a,b)| a == b)
                    && self
                    .f_mntonname
                    .iter()
                    .zip(other.f_mntonname.iter())
                    .all(|(a,b)| a == b)
            }
        }
        impl Eq for statfs {}
        impl ::fmt::Debug for statfs {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("statfs")
                    .field("f_bsize", &self.f_bsize)
                    .field("f_iosize", &self.f_iosize)
                    .field("f_blocks", &self.f_blocks)
                    .field("f_bfree", &self.f_bfree)
                    .field("f_bavail", &self.f_bavail)
                    .field("f_files", &self.f_files)
                    .field("f_ffree", &self.f_ffree)
                    .field("f_syncwrites", &self.f_syncwrites)
                    .field("f_asyncwrites", &self.f_asyncwrites)
                    .field("f_syncreads", &self.f_syncreads)
                    .field("f_asyncreads", &self.f_asyncreads)
                    .field("f_namemax", &self.f_namemax)
                    .field("f_owner", &self.f_owner)
                    .field("f_fsid", &self.f_fsid)
                    .field("f_fstypename", &self.f_fstypename)
                    .field("f_mntfromname", &&self.f_mntfromname[..])
                    .field("f_mntonname", &&self.f_mntonname[..])
                    .finish()
            }
        }
        impl ::hash::Hash for statfs {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.f_version.hash(state);
                self.f_type.hash(state);
                self.f_flags.hash(state);
                self.f_bsize.hash(state);
                self.f_iosize.hash(state);
                self.f_blocks.hash(state);
                self.f_bfree.hash(state);
                self.f_bavail.hash(state);
                self.f_files.hash(state);
                self.f_ffree.hash(state);
                self.f_syncwrites.hash(state);
                self.f_asyncwrites.hash(state);
                self.f_syncreads.hash(state);
                self.f_asyncreads.hash(state);
                self.f_namemax.hash(state);
                self.f_owner.hash(state);
                self.f_fsid.hash(state);
                self.f_charspare.hash(state);
                self.f_fstypename.hash(state);
                self.f_mntfromname.hash(state);
                self.f_mntonname.hash(state);
            }
        }

        impl PartialEq for dirent {
            fn eq(&self, other: &dirent) -> bool {
                self.d_fileno == other.d_fileno
                    && self.d_off == other.d_off
                    && self.d_reclen == other.d_reclen
                    && self.d_type == other.d_type
                    && self.d_namlen == other.d_namlen
                    && self
                    .d_name[..self.d_namlen as _]
                    .iter()
                    .zip(other.d_name.iter())
                    .all(|(a,b)| a == b)
            }
        }
        impl Eq for dirent {}
        impl ::fmt::Debug for dirent {
            fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
                f.debug_struct("dirent")
                    .field("d_fileno", &self.d_fileno)
                    .field("d_off", &self.d_off)
                    .field("d_reclen", &self.d_reclen)
                    .field("d_type", &self.d_type)
                    .field("d_namlen", &self.d_namlen)
                    .field("d_name", &&self.d_name[..self.d_namlen as _])
                    .finish()
            }
        }
        impl ::hash::Hash for dirent {
            fn hash<H: ::hash::Hasher>(&self, state: &mut H) {
                self.d_fileno.hash(state);
                self.d_off.hash(state);
                self.d_reclen.hash(state);
                self.d_type.hash(state);
                self.d_namlen.hash(state);
                self.d_name[..self.d_namlen as _].hash(state);
            }
        }
    }
}

pub const F_ADD_SEALS: ::c_int = 19;
pub const F_GET_SEALS: ::c_int = 20;
pub const F_SEAL_SEAL: ::c_int = 0x0001;
pub const F_SEAL_SHRINK: ::c_int = 0x0002;
pub const F_SEAL_GROW: ::c_int = 0x0004;
pub const F_SEAL_WRITE: ::c_int = 0x0008;

pub const GRND_NONBLOCK: ::c_uint = 0x1;
pub const GRND_RANDOM: ::c_uint = 0x2;

pub const SO_DOMAIN: ::c_int = 0x1019;

cfg_if! {
    if #[cfg(not(freebsd13))] {
        pub const ELAST: ::c_int = 96;
    } else {
        pub const EINTEGRITY: ::c_int = 97;
        pub const ELAST: ::c_int = 97;
        pub const GRND_INSECURE: ::c_uint = 0x4;
    }
}

extern "C" {
    pub fn setgrent();
    pub fn mprotect(
        addr: *mut ::c_void,
        len: ::size_t,
        prot: ::c_int,
    ) -> ::c_int;
    pub fn freelocale(loc: ::locale_t);
    pub fn msgrcv(
        msqid: ::c_int,
        msgp: *mut ::c_void,
        msgsz: ::size_t,
        msgtyp: ::c_long,
        msgflg: ::c_int,
    ) -> ::ssize_t;
    pub fn clock_nanosleep(
        clk_id: ::clockid_t,
        flags: ::c_int,
        rqtp: *const ::timespec,
        rmtp: *mut ::timespec,
    ) -> ::c_int;

    pub fn fdatasync(fd: ::c_int) -> ::c_int;

    pub fn getrandom(
        buf: *mut ::c_void,
        buflen: ::size_t,
        flags: ::c_uint,
    ) -> ::ssize_t;
}

cfg_if! {
    if #[cfg(any(target_arch = "x86_64",
                 target_arch = "aarch64"))] {
        mod b64;
        pub use self::b64::*;
    }
}
<|endoftext|>


<commit_before>//! Module containing font changing tools.
//!
//! # Examples
//!
//! The following from [the official documentation](http://foo.wyrd.name/en:bearlibterminal:reference:configuration#font_and_tileset_management):
//!
//! ```text
//! font: UbuntuMono-R.ttf, size=12;
//! 0x5E: curcumflex.png;
//! 0xE000: tileset.png, size=16x16, spacing=2x1;
//! ```
//!
//! Is equivalent to
//!
//! ```
//! use bear_lib_terminal::terminal::{self, config};
//! use bear_lib_terminal::geometry::Size;
//! terminal::set(config::font::true_type(config::font::Origin::Root, "UbuntuMono-R.ttf", Size::new(0, 12)));
//! terminal::set(config::font::bitmap(config::font::Origin::Offset('^'), "circumflex.png"));
//! terminal::set(config::font::bitmap(config::font::Origin::Offset('\u{E000}'), "tileset.png").size(Size::new(16, 16)).spacing(Size::new(2, 1)));
//! ```

use std::fmt;
use std::path::Path;
use geometry::Size;
use terminal::config::{ConfigPart, escape_config_string};

/// Construct a bitmap font override segment repr.
pub fn bitmap<T: AsRef<Path>>(origin: Origin, path: T) -> BitmapFont {
	BitmapFont{
		origin: origin,
		path: path.as_ref().to_str().unwrap().to_string(),
		size: None,
		resize: None,
		resize_filter: None,
		resize_mode: None,
		raw_size: None,
		codepage: None,
		align: None,
		spacing: None,
	}
}

/// Construct a TrueType font override segment repr.
///
/// If `title_size.width` is `0`, the resulting `size` prop will be `size=<title_size.width>` as opposed to `size=<title_size>`.
pub fn true_type<T: AsRef<Path>>(origin: Origin, path: T, tile_size: Size) -> TrueTypeFont {
	TrueTypeFont{
		origin: origin,
		path: path.as_ref().to_str().unwrap().to_string(),
		size: tile_size,
		size_reference: None,
		mode: None,
		codepage: None,
		align: None,
		spacing: None,
	}
}

/// The origin for the font (the part before `:` in the config string).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum Origin {
	/// `font`
	Root,
	/// `0xNNNN`
	Offset(char),
}

/// Rasterization mode for TrueType fonts.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum RasterizationMode {
	Monochrome,
	Normal,
	/// Forces an opaque black background.
	Lcd,
}

/// Resizing filter for bitmaps.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum ResizeFilter {
	Nearest,
	Bilinear,
	Bicubic,
}

/// How to aspect-change when resizing a bitmap.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum ResizeMode {
	Stretch,
	Fit,
	Crop,
}

/// Per-tileset tile alignment.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum Align {
	Center,
	TopLeft,
	BottomLeft,
	TopRight,
	BottomRight,
}

// What's the format for this?
// ref: http://foo.wyrd.name/en:bearlibterminal:reference:configuration#font_and_tileset_management
// pub enum Background {
// 	Auto,
// 	Color(Color),
// }

/// A bitmap font override segment repr, constructed with [`true_type()`](fn.true_type.html).
///
/// Refer to [the official documentation](http://foo.wyrd.name/en:bearlibterminal:reference:configuration#font_and_tileset_management).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct BitmapFont {
	origin       : Origin,
	path         : String,
	size         : Option<Size>,
	resize       : Option<Size>,
	resize_filter: Option<ResizeFilter>,
	resize_mode  : Option<ResizeMode>,
	raw_size     : Option<Size>,
	codepage     : Option<String>,
	align        : Option<Align>,
	spacing      : Option<Size>,
//	transparent  : Option<Background>,
}

/// A TrueType font override segment repr, constructed with [`true_type()`](fn.true_type.html).
///
/// Refer to [the official documentation](http://foo.wyrd.name/en:bearlibterminal:reference:configuration#font_and_tileset_management).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct TrueTypeFont {
	origin        : Origin,
	path          : String,
	size          : Size,
	size_reference: Option<char>,
	mode          : Option<RasterizationMode>,
	codepage      : Option<String>,
	align         : Option<Align>,
	spacing       : Option<Size>,
}

/// For all functions consult the corresponding attributes in
/// [the official docs](http://foo.wyrd.name/en:bearlibterminal:reference:configuration#font_and_tileset_management).
impl BitmapFont {
	/// The size of a single tile in the tileset.
	pub fn size         (mut self, size: Size)                  -> Self {self.size          = Some(size)         ; self}
	/// The size to resize the image to.
	pub fn resize       (mut self, resize: Size)                -> Self {self.resize        = Some(resize)       ; self}
	/// How to resize the image.
	///
	/// Default: `ResizeFilter::Bilinear`.
	pub fn resize_filter(mut self, resize_filter: ResizeFilter) -> Self {self.resize_filter = Some(resize_filter); self}
	/// Resize aspect method.
	///
	/// Default: `ResizeMode::Stretch`.
	pub fn resize_mode  (mut self, resize_mode: ResizeMode)     -> Self {self.resize_mode   = Some(resize_mode)  ; self}
	/// Raw memory size, `size` if not specified.
	pub fn raw_size     (mut self, raw_size: Size)              -> Self {self.raw_size      = Some(raw_size)     ; self}
	/// Tileset's codepage.
	///
	/// Default: `"ascii"`.
	pub fn codepage     (mut self, codepage: String)            -> Self {self.codepage      = Some(codepage)     ; self}
	/// How tiles are to be aligned.
	///
	/// Default: `Align::Center`.
	pub fn align        (mut self, align: Align)                -> Self {self.align         = Some(align)        ; self}
	/// Tile alignment area \[cells\].
	///
	/// Default: `1x1`.
	pub fn spacing      (mut self, spacing: Size)               -> Self {self.spacing       = Some(spacing)      ; self}
}

/// For all functions consult the corresponding attributes in
/// [the official docs](http://foo.wyrd.name/en:bearlibterminal:reference:configuration#font_and_tileset_management).
impl TrueTypeFont {
	/// Character used for size probing.
	///
	/// Default: `'@'`.
	pub fn size_reference(mut self, size_reference: char)    -> Self {self.size_reference = Some(size_reference); self}
	/// Rasterization mode. Note: `RasterizationMode::Lcd` forces opaque black background.
	///
	/// Default: `RasterizationMode::Normal`.
	pub fn mode          (mut self, mode: RasterizationMode) -> Self {self.mode           = Some(mode)          ; self}
	/// Reverse codepage for loading symbols.
	pub fn codepage      (mut self, codepage: String)        -> Self {self.codepage       = Some(codepage)      ; self}
	/// How tiles are to be aligned.
	///
	/// Default: `Align::Center`.
	pub fn align         (mut self, align: Align)            -> Self {self.align          = Some(align)         ; self}
	/// Tile alignment area \[cells\].
	///
	/// Default: `1x1`.
	pub fn spacing       (mut self, spacing: Size)           -> Self {self.spacing        = Some(spacing)       ; self}
}

impl ConfigPart for BitmapFont {
	fn to_config_str(&self) -> String {
		format!("{}: {}{}{}{}{}{}{}{};", self.origin, escape_config_string(&self.path),
			match self.resize {
				None             => "".to_string(),
				Some(ref resize) => format!(", resize={}", resize),
			},
			match self.resize_filter {
				None                    => "".to_string(),
				Some(ref resize_filter) => format!(", resize-filter={}", resize_filter),
			},
			match self.resize_mode {
				None                  => "".to_string(),
				Some(ref resize_mode) => format!(", resize-mode={}", resize_mode),
			},
			match self.raw_size {
				None               => "".to_string(),
				Some(ref raw_size) => format!(", raw-size={}", raw_size),
			},
			match self.codepage {
				None               => "".to_string(),
				Some(ref codepage) => format!(", codepage={}", escape_config_string(codepage)),
			},
			match self.align {
				None            => "".to_string(),
				Some(ref align) => format!(", align={}", align),
			},
			match self.spacing {
				None              => "".to_string(),
				Some(ref spacing) => format!(", spacing={}", spacing),
			}
		)
	}
}

impl ConfigPart for TrueTypeFont {
	fn to_config_str(&self) -> String {
		format!("{}: {}, size={}{}{}{}{}{};", self.origin, escape_config_string(&self.path),
			match self.size {
				Size{width: 0, height} => format!("{}", height),
				size                   => format!("{}", size),
			},
			match self.size_reference {
				None                     => "".to_string(),
				Some(ref size_reference) => format!(", size-reference=0x{:X}", *size_reference as i32),
			},
			match self.mode {
				None           => "".to_string(),
				Some(ref mode) => format!(", mode={}", mode),
			},
			match self.codepage {
				None               => "".to_string(),
				Some(ref codepage) => format!(", codepage={}", escape_config_string(codepage)),
			},
			match self.align {
				None            => "".to_string(),
				Some(ref align) => format!(", align={}", align),
			},
			match self.spacing {
				None              => "".to_string(),
				Some(ref spacing) => format!(", spacing={}", spacing),
			}
		)
	}
}

impl fmt::Display for Origin {
	fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&Origin::Root      => formatter.write_str("font"),
			&Origin::Offset(o) => formatter.write_str(&*&format!("0x{:X}", o as i32)),
		}
	}
}

impl fmt::Display for RasterizationMode {
	fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&RasterizationMode::Monochrome => formatter.write_str("monochrome"),
			&RasterizationMode::Normal     => formatter.write_str("normal"),
			&RasterizationMode::Lcd        => formatter.write_str("lcd"),
		}
	}
}

impl fmt::Display for ResizeFilter {
	fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&ResizeFilter::Nearest  => formatter.write_str("nearest"),
			&ResizeFilter::Bilinear => formatter.write_str("bilinear"),
			&ResizeFilter::Bicubic  => formatter.write_str("bicubic"),
		}
	}
}

impl fmt::Display for ResizeMode {
	fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&ResizeMode::Stretch => formatter.write_str("stretch"),
			&ResizeMode::Fit     => formatter.write_str("fit"),
			&ResizeMode::Crop    => formatter.write_str("crop"),
		}
	}
}

impl fmt::Display for Align {
	fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&Align::Center      => formatter.write_str("center"),
			&Align::TopLeft     => formatter.write_str("top-left"),
			&Align::BottomLeft  => formatter.write_str("bottom-left"),
			&Align::TopRight    => formatter.write_str("top-right"),
			&Align::BottomRight => formatter.write_str("bottom-right"),
		}
	}
}
<commit_msg>Rename (.+)Font to \1<commit_after>//! Module containing font changing tools.
//!
//! # Examples
//!
//! The following from [the official documentation](http://foo.wyrd.name/en:bearlibterminal:reference:configuration#font_and_tileset_management):
//!
//! ```text
//! font: UbuntuMono-R.ttf, size=12;
//! 0x5E: curcumflex.png;
//! 0xE000: tileset.png, size=16x16, spacing=2x1;
//! ```
//!
//! Is equivalent to
//!
//! ```
//! use bear_lib_terminal::terminal::{self, config};
//! use bear_lib_terminal::geometry::Size;
//! terminal::set(config::font::true_type(config::font::Origin::Root, "UbuntuMono-R.ttf", Size::new(0, 12)));
//! terminal::set(config::font::bitmap(config::font::Origin::Offset('^'), "circumflex.png"));
//! terminal::set(config::font::bitmap(config::font::Origin::Offset('\u{E000}'), "tileset.png").size(Size::new(16, 16)).spacing(Size::new(2, 1)));
//! ```

use std::fmt;
use std::path::Path;
use geometry::Size;
use terminal::config::{ConfigPart, escape_config_string};

/// Construct a bitmap font override segment repr.
pub fn bitmap<T: AsRef<Path>>(origin: Origin, path: T) -> Bitmap {
	Bitmap{
		origin: origin,
		path: path.as_ref().to_str().unwrap().to_string(),
		size: None,
		resize: None,
		resize_filter: None,
		resize_mode: None,
		raw_size: None,
		codepage: None,
		align: None,
		spacing: None,
	}
}

/// Construct a TrueType font override segment repr.
///
/// If `title_size.width` is `0`, the resulting `size` prop will be `size=<title_size.width>` as opposed to `size=<title_size>`.
pub fn true_type<T: AsRef<Path>>(origin: Origin, path: T, tile_size: Size) -> TrueType {
	TrueType{
		origin: origin,
		path: path.as_ref().to_str().unwrap().to_string(),
		size: tile_size,
		size_reference: None,
		mode: None,
		codepage: None,
		align: None,
		spacing: None,
	}
}

/// The origin for the font (the part before `:` in the config string).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum Origin {
	/// `font`
	Root,
	/// `0xNNNN`
	Offset(char),
}

/// Rasterization mode for TrueType fonts.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum RasterizationMode {
	Monochrome,
	Normal,
	/// Forces an opaque black background.
	Lcd,
}

/// Resizing filter for bitmaps.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum ResizeFilter {
	Nearest,
	Bilinear,
	Bicubic,
}

/// How to aspect-change when resizing a bitmap.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum ResizeMode {
	Stretch,
	Fit,
	Crop,
}

/// Per-tileset tile alignment.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum Align {
	Center,
	TopLeft,
	BottomLeft,
	TopRight,
	BottomRight,
}

// What's the format for this?
// ref: http://foo.wyrd.name/en:bearlibterminal:reference:configuration#font_and_tileset_management
// pub enum Background {
// 	Auto,
// 	Color(Color),
// }

/// A bitmap font override segment repr, constructed with [`true_type()`](fn.true_type.html).
///
/// Refer to [the official documentation](http://foo.wyrd.name/en:bearlibterminal:reference:configuration#font_and_tileset_management).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Bitmap {
	origin       : Origin,
	path         : String,
	size         : Option<Size>,
	resize       : Option<Size>,
	resize_filter: Option<ResizeFilter>,
	resize_mode  : Option<ResizeMode>,
	raw_size     : Option<Size>,
	codepage     : Option<String>,
	align        : Option<Align>,
	spacing      : Option<Size>,
//	transparent  : Option<Background>,
}

/// A TrueType font override segment repr, constructed with [`true_type()`](fn.true_type.html).
///
/// Refer to [the official documentation](http://foo.wyrd.name/en:bearlibterminal:reference:configuration#font_and_tileset_management).
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct TrueType {
	origin        : Origin,
	path          : String,
	size          : Size,
	size_reference: Option<char>,
	mode          : Option<RasterizationMode>,
	codepage      : Option<String>,
	align         : Option<Align>,
	spacing       : Option<Size>,
}

/// For all functions consult the corresponding attributes in
/// [the official docs](http://foo.wyrd.name/en:bearlibterminal:reference:configuration#font_and_tileset_management).
impl Bitmap {
	/// The size of a single tile in the tileset.
	pub fn size         (mut self, size: Size)                  -> Self {self.size          = Some(size)         ; self}
	/// The size to resize the image to.
	pub fn resize       (mut self, resize: Size)                -> Self {self.resize        = Some(resize)       ; self}
	/// How to resize the image.
	///
	/// Default: `ResizeFilter::Bilinear`.
	pub fn resize_filter(mut self, resize_filter: ResizeFilter) -> Self {self.resize_filter = Some(resize_filter); self}
	/// Resize aspect method.
	///
	/// Default: `ResizeMode::Stretch`.
	pub fn resize_mode  (mut self, resize_mode: ResizeMode)     -> Self {self.resize_mode   = Some(resize_mode)  ; self}
	/// Raw memory size, `size` if not specified.
	pub fn raw_size     (mut self, raw_size: Size)              -> Self {self.raw_size      = Some(raw_size)     ; self}
	/// Tileset's codepage.
	///
	/// Default: `"ascii"`.
	pub fn codepage     (mut self, codepage: String)            -> Self {self.codepage      = Some(codepage)     ; self}
	/// How tiles are to be aligned.
	///
	/// Default: `Align::Center`.
	pub fn align        (mut self, align: Align)                -> Self {self.align         = Some(align)        ; self}
	/// Tile alignment area \[cells\].
	///
	/// Default: `1x1`.
	pub fn spacing      (mut self, spacing: Size)               -> Self {self.spacing       = Some(spacing)      ; self}
}

/// For all functions consult the corresponding attributes in
/// [the official docs](http://foo.wyrd.name/en:bearlibterminal:reference:configuration#font_and_tileset_management).
impl TrueType {
	/// Character used for size probing.
	///
	/// Default: `'@'`.
	pub fn size_reference(mut self, size_reference: char)    -> Self {self.size_reference = Some(size_reference); self}
	/// Rasterization mode. Note: `RasterizationMode::Lcd` forces opaque black background.
	///
	/// Default: `RasterizationMode::Normal`.
	pub fn mode          (mut self, mode: RasterizationMode) -> Self {self.mode           = Some(mode)          ; self}
	/// Reverse codepage for loading symbols.
	pub fn codepage      (mut self, codepage: String)        -> Self {self.codepage       = Some(codepage)      ; self}
	/// How tiles are to be aligned.
	///
	/// Default: `Align::Center`.
	pub fn align         (mut self, align: Align)            -> Self {self.align          = Some(align)         ; self}
	/// Tile alignment area \[cells\].
	///
	/// Default: `1x1`.
	pub fn spacing       (mut self, spacing: Size)           -> Self {self.spacing        = Some(spacing)       ; self}
}

impl ConfigPart for Bitmap {
	fn to_config_str(&self) -> String {
		format!("{}: {}{}{}{}{}{}{}{};", self.origin, escape_config_string(&self.path),
			match self.resize {
				None             => "".to_string(),
				Some(ref resize) => format!(", resize={}", resize),
			},
			match self.resize_filter {
				None                    => "".to_string(),
				Some(ref resize_filter) => format!(", resize-filter={}", resize_filter),
			},
			match self.resize_mode {
				None                  => "".to_string(),
				Some(ref resize_mode) => format!(", resize-mode={}", resize_mode),
			},
			match self.raw_size {
				None               => "".to_string(),
				Some(ref raw_size) => format!(", raw-size={}", raw_size),
			},
			match self.codepage {
				None               => "".to_string(),
				Some(ref codepage) => format!(", codepage={}", escape_config_string(codepage)),
			},
			match self.align {
				None            => "".to_string(),
				Some(ref align) => format!(", align={}", align),
			},
			match self.spacing {
				None              => "".to_string(),
				Some(ref spacing) => format!(", spacing={}", spacing),
			}
		)
	}
}

impl ConfigPart for TrueType {
	fn to_config_str(&self) -> String {
		format!("{}: {}, size={}{}{}{}{}{};", self.origin, escape_config_string(&self.path),
			match self.size {
				Size{width: 0, height} => format!("{}", height),
				size                   => format!("{}", size),
			},
			match self.size_reference {
				None                     => "".to_string(),
				Some(ref size_reference) => format!(", size-reference=0x{:X}", *size_reference as i32),
			},
			match self.mode {
				None           => "".to_string(),
				Some(ref mode) => format!(", mode={}", mode),
			},
			match self.codepage {
				None               => "".to_string(),
				Some(ref codepage) => format!(", codepage={}", escape_config_string(codepage)),
			},
			match self.align {
				None            => "".to_string(),
				Some(ref align) => format!(", align={}", align),
			},
			match self.spacing {
				None              => "".to_string(),
				Some(ref spacing) => format!(", spacing={}", spacing),
			}
		)
	}
}

impl fmt::Display for Origin {
	fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&Origin::Root      => formatter.write_str("font"),
			&Origin::Offset(o) => formatter.write_str(&*&format!("0x{:X}", o as i32)),
		}
	}
}

impl fmt::Display for RasterizationMode {
	fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&RasterizationMode::Monochrome => formatter.write_str("monochrome"),
			&RasterizationMode::Normal     => formatter.write_str("normal"),
			&RasterizationMode::Lcd        => formatter.write_str("lcd"),
		}
	}
}

impl fmt::Display for ResizeFilter {
	fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&ResizeFilter::Nearest  => formatter.write_str("nearest"),
			&ResizeFilter::Bilinear => formatter.write_str("bilinear"),
			&ResizeFilter::Bicubic  => formatter.write_str("bicubic"),
		}
	}
}

impl fmt::Display for ResizeMode {
	fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&ResizeMode::Stretch => formatter.write_str("stretch"),
			&ResizeMode::Fit     => formatter.write_str("fit"),
			&ResizeMode::Crop    => formatter.write_str("crop"),
		}
	}
}

impl fmt::Display for Align {
	fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
		match self {
			&Align::Center      => formatter.write_str("center"),
			&Align::TopLeft     => formatter.write_str("top-left"),
			&Align::BottomLeft  => formatter.write_str("bottom-left"),
			&Align::TopRight    => formatter.write_str("top-right"),
			&Align::BottomRight => formatter.write_str("bottom-right"),
		}
	}
}
<|endoftext|>


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

use super::common::Value;
use super::network::Network;

#[derive(RustcDecodable)]
pub struct Conf {
    pub group_size: usize,
    pub threshold: Value,
}

pub trait Apply {
    fn apply<'r>(&'r self, conf: &'r Conf) -> Application<'r>;
}

impl<'network> Apply for Network<'network> {
    fn apply<'r>(&'r self, conf: &'r Conf) -> Application<'r> {
        Application::new(self, conf)
    }
}

struct ValuesGroup {
    pub sum: Value,
    pub node: usize,
}

pub struct Application<'r> {
    conf: &'r Conf,
    network: &'r Network<'r>,
}

impl<'r> Application<'r> {
    pub fn new(network: &'r Network<'r>, conf: &'r Conf) -> Self {
        Application {network: network, conf: conf}
    }

    pub fn perform(&self, values: &[Value]) -> Vec<Value> {
        assert!(values.len() >= self.network.inputs.len());
        let group_size = self.conf.group_size as Value;
        let mut result: BTreeMap<usize, Value> = self.network.outputs.iter()
            .map(|&x| (x, 0.0)).collect::<_>();
        {
            let groups = self.network.inputs.iter().zip(values)
                .map(|(&node, value)| {
                    self.perform_one(ValuesGroup {sum: value * group_size, node: node})
                })
                .flat_map(|x| x.into_iter());
            for group in groups {
                *result.get_mut(&group.node).unwrap() += group.sum;
            }
        }
        result.values()
            .map(|x| x / group_size as Value)
            .collect::<Vec<Value>>()
    }

    fn perform_one(&self, group: ValuesGroup) -> Box<Iterator<Item=ValuesGroup>> {
        if self.network.outputs.contains(&group.node) {
            Box::new(vec![group].into_iter())
        } else if group.sum > self.conf.threshold {
            let row = self.network.weights.row(group.node);
            let nodes = row.iter()
                .enumerate()
                .filter(|&(_, &w)| w.abs() > 0.0)
                .map(|(n, &w)| (n, w))
                .collect::<Vec<(usize, Value)>>();
            let new_sum = group.sum / nodes.len() as Value;
            Box::new(nodes.iter()
                .map(|&(node, weight)| {
                    self.perform_one(ValuesGroup {sum: new_sum * weight, node: node})
                })
                .flat_map(|x| x.into_iter())
                .collect::<Vec<_>>()
                .into_iter())
        } else {
            Box::new(vec![].into_iter())
        }
    }
}

#[test]
fn test_apply_network_contains_one_arc_with_positive_weight_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let weight = 0.4;
    let weights_values = [
        0.0, weight,
        0.0, 0.0,
    ];
    let inputs = [0].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [1].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(2, &weights_values);
    let nodes = (0..2).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1, threshold: 1e-3};
    let input = 0.6;
    assert_eq!(&network.apply(&conf).perform(&[input])[..], &[input * weight]);
}

#[test]
fn test_apply_network_contains_one_arc_with_negative_weight_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let weight = -0.4;
    let weights_values = [
        0.0, weight,
        0.0, 0.0,
    ];
    let inputs = [0].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [1].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(2, &weights_values);
    let nodes = (0..2).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1, threshold: 1e-3};
    let input = 0.6;
    assert_eq!(&network.apply(&conf).perform(&[input])[..], &[input * weight]);
}

#[test]
fn test_apply_network_with_two_arcs_and_two_inputs_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let w13 = 0.4;
    let w23 = 0.2;
    let weights_values = [
        0.0, 0.0, w13,
        0.0, 0.0, w23,
        0.0, 0.0, 0.0,
    ];
    let inputs = [0, 1].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [2].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(3, &weights_values);
    let nodes = (0..3).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1, threshold: 1e-3};
    let i1 = 0.6;
    let i2 = 0.7;
    assert_eq!(&network.apply(&conf).perform(&[i1, i2])[..], &[i1 * w13 + i2 * w23]);
}

#[test]
fn test_apply_network_with_two_arcs_and_two_outputs_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let w12 = 0.4;
    let w13 = 0.2;
    let weights_values = [
        0.0, w12, w13,
        0.0, 0.0, 0.0,
        0.0, 0.0, 0.0,
    ];
    let inputs = [0].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [1, 2].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(3, &weights_values);
    let nodes = (0..3).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1, threshold: 1e-3};
    let input = 0.6;
    assert_eq!(&network.apply(&conf).perform(&[input])[..],
               &[input * w12 / 2.0, input * w13 / 2.0]);
}

#[test]
fn test_apply_network_with_two_arcs_and_one_middle_node_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let w12 = 0.4;
    let w23 = 0.2;
    let weights_values = [
        0.0, w12, 0.0,
        0.0, 0.0, w23,
        0.0, 0.0, 0.0,
    ];
    let inputs = [0].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [2].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(3, &weights_values);
    let nodes = (0..3).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1, threshold: 1e-3};
    let input = 0.6;
    assert_eq!(&network.apply(&conf).perform(&[input])[..], &[input * w12 * w23]);
}

#[test]
fn test_apply_network_with_two_arcs_and_self_add_arced_input_node_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let w11 = 0.2;
    let w12 = 0.4;
    let weights_values = [
        w11, w12,
        0.0, 0.0,
    ];
    let inputs = [0].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [1].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(2, &weights_values);
    let nodes = (0..2).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1000, threshold: 1e-8};
    let input = 0.6;
    let actual = network.apply(&conf).perform(&[input]);
    let expected = [input * w12 * (1.0 + w11 / (2.0 - w11)) / 2.0];
    assert_eq!(actual.len(), expected.len());
    assert!((actual[0] - expected[0]).abs() <= 1e-8);
}

#[test]
fn test_apply_network_without_arcs_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let weights_values = [
        0.0, 0.0,
        0.0, 0.0,
    ];
    let inputs = [0].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [1].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(2, &weights_values);
    let nodes = (0..2).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1000, threshold: 1e-8};
    assert_eq!(&network.apply(&conf).perform(&[1.0]), &[0.0]);
}
<commit_msg>Use parallel map in apply<commit_after>extern crate rayon;

use std::collections::HashMap;

use super::common::Value;
use super::network::Network;

#[derive(RustcDecodable)]
pub struct Conf {
    pub group_size: usize,
    pub threshold: Value,
}

pub trait Apply {
    fn apply<'r>(&'r self, conf: &'r Conf) -> Application<'r>;
}

impl<'network> Apply for Network<'network> {
    fn apply<'r>(&'r self, conf: &'r Conf) -> Application<'r> {
        Application::new(self, conf)
    }
}

struct ValuesGroup {
    pub sum: Value,
    pub node: usize,
}

pub struct Application<'r> {
    conf: &'r Conf,
    network: &'r Network<'r>,
}

impl<'r> Application<'r> {
    pub fn new(network: &'r Network<'r>, conf: &'r Conf) -> Self {
        Application {network: network, conf: conf}
    }

    pub fn perform(&self, values: &[Value]) -> Vec<Value> {
        use std::ops::{AddAssign, Deref, DerefMut};
        use std::sync::{Arc, Mutex};
        use self::rayon::prelude::*;
        assert!(values.len() >= self.network.inputs.len());
        let group_size = self.conf.group_size as Value;
        let result = Arc::new(Mutex::new(self.network.outputs.iter()
            .map(|&x| (x, 0.0)).collect::<HashMap<usize, Value>>()));
        self.network.inputs.par_iter().zip(values)
            .map(|(&node, value)| {
                self.perform_one(ValuesGroup {sum: value * group_size, node: node})
            })
            .for_each(|groups| {
                for group in groups {
                    let mut guarded = result.lock().unwrap();
                    guarded.deref_mut().get_mut(&group.node).unwrap().add_assign(group.sum);
                }
            });
        let guarded = result.lock().unwrap();
        let mut values = guarded.deref().into_iter().collect::<Vec<_>>();
        values.sort_by_key(|&(group, _)| group);
        values.into_iter()
            .map(|(_, value)| value / group_size as Value)
            .collect::<Vec<Value>>()
    }

    fn perform_one(&self, group: ValuesGroup) -> Vec<ValuesGroup> {
        if self.network.outputs.contains(&group.node) {
            vec![group]
        } else if group.sum > self.conf.threshold {
            let row = self.network.weights.row(group.node);
            let nodes = row.iter()
                .enumerate()
                .filter(|&(_, &w)| w.abs() > 0.0)
                .map(|(n, &w)| (n, w))
                .collect::<Vec<(usize, Value)>>();
            let new_sum = group.sum / nodes.len() as Value;
            nodes.iter()
                .map(|&(node, weight)| {
                    self.perform_one(ValuesGroup {sum: new_sum * weight, node: node})
                })
                .flat_map(|x| x.into_iter())
                .collect::<Vec<_>>()
        } else {
            vec![]
        }
    }
}

#[test]
fn test_apply_network_contains_one_arc_with_positive_weight_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let weight = 0.4;
    let weights_values = [
        0.0, weight,
        0.0, 0.0,
    ];
    let inputs = [0].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [1].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(2, &weights_values);
    let nodes = (0..2).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1, threshold: 1e-3};
    let input = 0.6;
    assert_eq!(&network.apply(&conf).perform(&[input])[..], &[input * weight]);
}

#[test]
fn test_apply_network_contains_one_arc_with_negative_weight_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let weight = -0.4;
    let weights_values = [
        0.0, weight,
        0.0, 0.0,
    ];
    let inputs = [0].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [1].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(2, &weights_values);
    let nodes = (0..2).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1, threshold: 1e-3};
    let input = 0.6;
    assert_eq!(&network.apply(&conf).perform(&[input])[..], &[input * weight]);
}

#[test]
fn test_apply_network_with_two_arcs_and_two_inputs_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let w13 = 0.4;
    let w23 = 0.2;
    let weights_values = [
        0.0, 0.0, w13,
        0.0, 0.0, w23,
        0.0, 0.0, 0.0,
    ];
    let inputs = [0, 1].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [2].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(3, &weights_values);
    let nodes = (0..3).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1, threshold: 1e-3};
    let i1 = 0.6;
    let i2 = 0.7;
    assert_eq!(&network.apply(&conf).perform(&[i1, i2])[..], &[i1 * w13 + i2 * w23]);
}

#[test]
fn test_apply_network_with_two_arcs_and_two_outputs_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let w12 = 0.4;
    let w13 = 0.2;
    let weights_values = [
        0.0, w12, w13,
        0.0, 0.0, 0.0,
        0.0, 0.0, 0.0,
    ];
    let inputs = [0].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [1, 2].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(3, &weights_values);
    let nodes = (0..3).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1, threshold: 1e-3};
    let input = 0.6;
    assert_eq!(&network.apply(&conf).perform(&[input])[..],
               &[input * w12 / 2.0, input * w13 / 2.0]);
}

#[test]
fn test_apply_network_with_two_arcs_and_one_middle_node_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let w12 = 0.4;
    let w23 = 0.2;
    let weights_values = [
        0.0, w12, 0.0,
        0.0, 0.0, w23,
        0.0, 0.0, 0.0,
    ];
    let inputs = [0].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [2].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(3, &weights_values);
    let nodes = (0..3).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1, threshold: 1e-3};
    let input = 0.6;
    assert_eq!(&network.apply(&conf).perform(&[input])[..], &[input * w12 * w23]);
}

#[test]
fn test_apply_network_with_two_arcs_and_self_add_arced_input_node_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let w11 = 0.2;
    let w12 = 0.4;
    let weights_values = [
        w11, w12,
        0.0, 0.0,
    ];
    let inputs = [0].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [1].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(2, &weights_values);
    let nodes = (0..2).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1000, threshold: 1e-8};
    let input = 0.6;
    let actual = network.apply(&conf).perform(&[input]);
    let expected = [input * w12 * (1.0 + w11 / (2.0 - w11)) / 2.0];
    assert_eq!(actual.len(), expected.len());
    assert!((actual[0] - expected[0]).abs() <= 1e-8);
}

#[test]
fn test_apply_network_without_arcs_should_succeed() {
    use std::collections::{BTreeSet, HashMap, HashSet};
    use super::common::Node;
    use super::matrix::Matrix;
    let weights_values = [
        0.0, 0.0,
        0.0, 0.0,
    ];
    let inputs = [0].iter().cloned().collect::<BTreeSet<usize>>();
    let outputs = [1].iter().cloned().collect::<HashSet<usize>>();
    let weights = Matrix::new(2, &weights_values);
    let nodes = (0..2).map(|x| (x, Node(x))).collect::<HashMap<usize, Node>>();
    let network = Network {inputs: &inputs, outputs: &outputs, weights: weights, nodes: &nodes};
    let conf = Conf {group_size: 1000, threshold: 1e-8};
    assert_eq!(&network.apply(&conf).perform(&[1.0]), &[0.0]);
}
<|endoftext|>


<commit_before>use bytes::BufMut;
use futures_core::ready;
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::io::{AsyncRead, ReadBuf};

/// Try to read data from an `AsyncRead` into an implementer of the [`Buf`] trait.
///
/// [`Buf`]: bytes::Buf
///
/// # Example
///
/// ```
/// use bytes::{Bytes, BytesMut};
/// use tokio::stream;
/// use tokio::io::Result;
/// use tokio_util::io::{StreamReader, poll_read_buf};
/// use futures::future::poll_fn;
/// use std::pin::Pin;
/// # #[tokio::main]
/// # async fn main() -> std::io::Result<()> {
///
/// // Create a reader from an iterator. This particular reader will always be
/// // ready.
/// let mut read = StreamReader::new(stream::iter(vec![Result::Ok(Bytes::from_static(&[0, 1, 2, 3]))]));
///
/// let mut buf = BytesMut::new();
/// let mut reads = 0;
///
/// loop {
///     reads += 1;
///     let n = poll_fn(|cx| poll_read_buf(Pin::new(&mut read), cx, &mut buf)).await?;
///
///     if n == 0 {
///         break;
///     }
/// }
///
/// // one or more reads might be necessary.
/// assert!(reads >= 1);
/// assert_eq!(&buf[..], &[0, 1, 2, 3]);
/// # Ok(())
/// # }
/// ```
pub fn poll_read_buf<R, B>(
    read: Pin<&mut R>,
    cx: &mut Context<'_>,
    buf: &mut B,
) -> Poll<io::Result<usize>>
where
    R: AsyncRead,
    B: BufMut,
{
    if !buf.has_remaining_mut() {
        return Poll::Ready(Ok(0));
    }

    let n = {
        let mut buf = ReadBuf::uninit(buf.bytes_mut());
        ready!(read.poll_read(cx, &mut buf)?);
        buf.filled().len()
    };

    // Safety: This is guaranteed to be the number of initialized (and read)
    // bytes due to the invariants provided by `ReadBuf::filled`.
    unsafe {
        buf.advance_mut(n);
    }

    Poll::Ready(Ok(n))
}
<commit_msg>util: prevent read buffer from being swapped during a read_poll (#2993)<commit_after>use bytes::BufMut;
use futures_core::ready;
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::io::{AsyncRead, ReadBuf};

/// Try to read data from an `AsyncRead` into an implementer of the [`Buf`] trait.
///
/// [`Buf`]: bytes::Buf
///
/// # Example
///
/// ```
/// use bytes::{Bytes, BytesMut};
/// use tokio::stream;
/// use tokio::io::Result;
/// use tokio_util::io::{StreamReader, poll_read_buf};
/// use futures::future::poll_fn;
/// use std::pin::Pin;
/// # #[tokio::main]
/// # async fn main() -> std::io::Result<()> {
///
/// // Create a reader from an iterator. This particular reader will always be
/// // ready.
/// let mut read = StreamReader::new(stream::iter(vec![Result::Ok(Bytes::from_static(&[0, 1, 2, 3]))]));
///
/// let mut buf = BytesMut::new();
/// let mut reads = 0;
///
/// loop {
///     reads += 1;
///     let n = poll_fn(|cx| poll_read_buf(Pin::new(&mut read), cx, &mut buf)).await?;
///
///     if n == 0 {
///         break;
///     }
/// }
///
/// // one or more reads might be necessary.
/// assert!(reads >= 1);
/// assert_eq!(&buf[..], &[0, 1, 2, 3]);
/// # Ok(())
/// # }
/// ```
pub fn poll_read_buf<R, B>(
    read: Pin<&mut R>,
    cx: &mut Context<'_>,
    buf: &mut B,
) -> Poll<io::Result<usize>>
where
    R: AsyncRead,
    B: BufMut,
{
    if !buf.has_remaining_mut() {
        return Poll::Ready(Ok(0));
    }

    let n = {
        let mut buf = ReadBuf::uninit(buf.bytes_mut());
        let before = buf.filled().as_ptr();

        ready!(read.poll_read(cx, &mut buf)?);

        // This prevents a malicious read implementation from swapping out the
        // buffer being read, which would allow `filled` to be advanced without
        // actually initializing the provided buffer.
        //
        // We avoid this by asserting that the `ReadBuf` instance wraps the same
        // memory address both before and after the poll. Which will panic in
        // case its swapped.
        //
        // See https://github.com/tokio-rs/tokio/issues/2827 for more info.
        assert! {
            std::ptr::eq(before, buf.filled().as_ptr()),
            "Read buffer must not be changed during a read poll. \
            See https://github.com/tokio-rs/tokio/issues/2827 for more info."
        };

        buf.filled().len()
    };

    // Safety: This is guaranteed to be the number of initialized (and read)
    // bytes due to the invariants provided by `ReadBuf::filled`.
    unsafe {
        buf.advance_mut(n);
    }

    Poll::Ready(Ok(n))
}
<|endoftext|>


<commit_before>#[derive(Copy, Clone)]
pub enum Color {
    Black      = 0,
    Blue       = 1,
    Green      = 2,
    Cyan       = 3,
    Red        = 4,
    Pink       = 5,
    Brown      = 6,
    LightGray  = 7,
    DarkGray   = 8,
    LightBlue  = 9,
    LightGreen = 10,
    LightCyan  = 11,
    LightRed   = 12,
    LightPink  = 13,
    Yellow     = 14,
    White      = 15,
}

use machine;

use core::prelude::*;

pub const ROWS: usize = 25;
pub const COLS: usize = 80;

fn set_vga_u8(offset: usize, val: u8) {
    unsafe {
        let ptr = (0xb8000 + offset) as *mut u8;
        *ptr = val;
    }
}

fn set_vga_u16(offset: usize, val: u16) {
    unsafe {
        let ptr = (0xb8000 + (offset * 2)) as *mut u16;
        *ptr = val;
    }
}

pub fn write_char(row: usize, col: usize, letter: char) {
    let code = (letter as u32) as u8;
    let offset = (row * COLS + col) * 2;
    set_vga_u8(offset, code);
}

fn encode_color(foregnd: Color, backgnd: Color) -> u8 {
    let fcode = foregnd as u8;
    let bcode = backgnd as u8;
    fcode | (bcode << 4)
}

pub fn set_color(row: usize, col: usize, foregnd: Color, backgnd: Color) {
    let code = encode_color(foregnd, backgnd);
    let offset = (row * COLS + col) * 2 + 1;
    set_vga_u8(offset, code);
}

pub fn write_char_with_color(row: usize, col: usize, letter: char,
                             foregnd: Color, backgnd: Color) {
    let char_code = (letter as u32) as u16;
    let color_code = encode_color(foregnd, backgnd) as u16;
    let offset = (row * COLS) + col;
    let code = (char_code & 0xFF) | (color_code << 8);
    set_vga_u16(offset, code);
}

pub fn write_string(row: usize, col: usize, string: &str) {
    for (i, chr) in string.chars().enumerate() {
        write_char(row, col + i, chr);
    }
}

pub fn paint_color(row: usize, col: usize, len: usize,
                   foregnd: Color, backgnd: Color) {
    for i in 0..len {
        set_color(row, col + i, foregnd, backgnd);
    }
}

pub fn write_string_with_color(row: usize, col: usize, string: &str,
                               foregnd: Color, backgnd: Color) {
    for (i, chr) in string.chars().enumerate() {
        write_char_with_color(row, col + i, chr, foregnd, backgnd);
    }
}

pub fn move_cursor(row: usize, col: usize) {
    const VGA_CMD: u16 = 0x3d4;
    const VGA_DATA: u16 = 0x3d5;
    let cursor_offset = (row * COLS + col) as u16;
    let lsb = (cursor_offset & 0xFF) as u8;
    let msb = (cursor_offset >> 8) as u8;

    machine::outb(VGA_CMD, 0x0f);
    machine::outb(VGA_DATA, lsb);
    machine::outb(VGA_CMD, 0x0e);
    machine::outb(VGA_DATA, msb);
}
<commit_msg>Munchkin VGA stuff<commit_after>#[derive(Copy, Clone)]
pub enum Color {
    Black      = 0,
    Blue       = 1,
    Green      = 2,
    Cyan       = 3,
    Red        = 4,
    Pink       = 5,
    Brown      = 6,
    LightGray  = 7,
    DarkGray   = 8,
    LightBlue  = 9,
    LightGreen = 10,
    LightCyan  = 11,
    LightRed   = 12,
    LightPink  = 13,
    Yellow     = 14,
    White      = 15,
}

use machine;

use core::prelude::*;

pub const ROWS: usize = 25;
pub const COLS: usize = 80;

// TODO: Re-enable this once something pulls in bounds checking
// static mut vga_mem: *mut [u8; ROWS * COLS * 2] = 0xb8000 as *mut [u8; ROWS * COLS * 2];
// static mut vga_mem_long: *mut [u16; ROWS * COLS] = 0xb8000 as *mut [u16; ROWS * COLS];

fn set_vga_u8(offset: usize, val: u8) {
    unsafe {
        *(0xb8000 as *mut u8).offset(offset as isize) = val;
    }
}

fn set_vga_u16(offset: usize, val: u16) {
    unsafe {
        *(0xb8000 as *mut u16).offset(offset as isize) = val;
    }
}

pub fn write_char(row: usize, col: usize, letter: char) {
    let code = (letter as u32) as u8;
    let offset = (row * COLS + col) * 2;
    set_vga_u8(offset, code);
}

fn encode_color(foregnd: Color, backgnd: Color) -> u8 {
    let fcode = foregnd as u8;
    let bcode = backgnd as u8;
    fcode | (bcode << 4)
}

pub fn set_color(row: usize, col: usize, foregnd: Color, backgnd: Color) {
    let code = encode_color(foregnd, backgnd);
    let offset = (row * COLS + col) * 2 + 1;
    set_vga_u8(offset, code);
}

pub fn write_char_with_color(row: usize, col: usize, letter: char,
                             foregnd: Color, backgnd: Color) {
    let char_code = (letter as u32) as u16;
    let color_code = encode_color(foregnd, backgnd) as u16;
    let offset = (row * COLS) + col;
    let code = (char_code & 0xFF) | (color_code << 8);
    set_vga_u16(offset, code);
}

pub fn write_string(row: usize, col: usize, string: &str) {
    for (i, chr) in string.chars().enumerate() {
        write_char(row, col + i, chr);
    }
}

pub fn paint_color(row: usize, col: usize, len: usize,
                   foregnd: Color, backgnd: Color) {
    for i in 0..len {
        set_color(row, col + i, foregnd, backgnd);
    }
}

pub fn write_string_with_color(row: usize, col: usize, string: &str,
                               foregnd: Color, backgnd: Color) {
    for (i, chr) in string.chars().enumerate() {
        write_char_with_color(row, col + i, chr, foregnd, backgnd);
    }
}

pub fn move_cursor(row: usize, col: usize) {
    const VGA_CMD: u16 = 0x3d4;
    const VGA_DATA: u16 = 0x3d5;
    let cursor_offset = (row * COLS + col) as u16;
    let lsb = (cursor_offset & 0xFF) as u8;
    let msb = (cursor_offset >> 8) as u8;

    machine::outb(VGA_CMD, 0x0f);
    machine::outb(VGA_DATA, lsb);
    machine::outb(VGA_CMD, 0x0e);
    machine::outb(VGA_DATA, msb);
}
<|endoftext|>


<commit_before>
/// An iterator that produces only the `T` values as long as the
/// inner iterator produces `Ok(T)`.
///
/// Used by [`process_results`](crate::process_results), see its docs
/// for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Debug)]
pub struct ProcessResults<'a, I, E: 'a> {
    error: &'a mut Result<(), E>,
    iter: I,
}

impl<'a, I, T, E> Iterator for ProcessResults<'a, I, E>
    where I: Iterator<Item = Result<T, E>>
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        match self.iter.next() {
            Some(Ok(x)) => Some(x),
            Some(Err(e)) => {
                *self.error = Err(e);
                None
            }
            None => None,
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, self.iter.size_hint().1)
    }
}

/// “Lift” a function of the values of an iterator so that it can process
/// an iterator of `Result` values instead.
///
/// `iterable` is an iterator or iterable with `Result<T, E>` elements, where
/// `T` is the value type and `E` the error type.
///
/// `processor` is a closure that receives an adapted version of the iterable
/// as the only argument — the adapted iterator produces elements of type `T`,
/// as long as the original iterator produces `Ok` values.
///
/// If the original iterable produces an error at any point, the adapted
/// iterator ends and the `process_results` function will return the
/// error iself.
///
/// Otherwise, the return value from the closure is returned wrapped
/// inside `Ok`.
///
/// # Example
///
/// ```
/// use itertools::process_results;
///
/// type R = Result<i32, &'static str>;
///
/// let first_values: Vec<R> = vec![Ok(1), Ok(0), Ok(3)];
/// let second_values: Vec<R> = vec![Ok(2), Ok(1), Err("overflow")];
///
/// // “Lift” the iterator .max() method to work on the values in Results using process_results
///
/// let first_max = process_results(first_values, |iter| iter.max().unwrap_or(0));
/// let second_max = process_results(second_values, |iter| iter.max().unwrap_or(0));
///
/// assert_eq!(first_max, Ok(3));
/// assert!(second_max.is_err());
/// ```
pub fn process_results<I, F, T, E, R>(iterable: I, processor: F) -> Result<R, E>
    where I: IntoIterator<Item = Result<T, E>>,
          F: FnOnce(ProcessResults<I::IntoIter, E>) -> R
{
    let iter = iterable.into_iter();
    let mut error = Ok(());

    let result = processor(ProcessResults { error: &mut error, iter });

    error.map(|_| result)
}
<commit_msg>Specialize ProcessResults::fold<commit_after>
/// An iterator that produces only the `T` values as long as the
/// inner iterator produces `Ok(T)`.
///
/// Used by [`process_results`](crate::process_results), see its docs
/// for more information.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
#[derive(Debug)]
pub struct ProcessResults<'a, I, E: 'a> {
    error: &'a mut Result<(), E>,
    iter: I,
}

impl<'a, I, T, E> Iterator for ProcessResults<'a, I, E>
    where I: Iterator<Item = Result<T, E>>
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        match self.iter.next() {
            Some(Ok(x)) => Some(x),
            Some(Err(e)) => {
                *self.error = Err(e);
                None
            }
            None => None,
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (0, self.iter.size_hint().1)
    }

    fn fold<B, F>(mut self, init: B, mut f: F) -> B
    where
        Self: Sized,
        F: FnMut(B, Self::Item) -> B,
    {
        let error = self.error;
        self.iter
            .try_fold(init, |acc, opt| match opt {
                Ok(x) => Ok(f(acc, x)),
                Err(e) => {
                    *error = Err(e);
                    Err(acc)
                }
            })
            .unwrap_or_else(|e| e)
    }
}

/// “Lift” a function of the values of an iterator so that it can process
/// an iterator of `Result` values instead.
///
/// `iterable` is an iterator or iterable with `Result<T, E>` elements, where
/// `T` is the value type and `E` the error type.
///
/// `processor` is a closure that receives an adapted version of the iterable
/// as the only argument — the adapted iterator produces elements of type `T`,
/// as long as the original iterator produces `Ok` values.
///
/// If the original iterable produces an error at any point, the adapted
/// iterator ends and the `process_results` function will return the
/// error iself.
///
/// Otherwise, the return value from the closure is returned wrapped
/// inside `Ok`.
///
/// # Example
///
/// ```
/// use itertools::process_results;
///
/// type R = Result<i32, &'static str>;
///
/// let first_values: Vec<R> = vec![Ok(1), Ok(0), Ok(3)];
/// let second_values: Vec<R> = vec![Ok(2), Ok(1), Err("overflow")];
///
/// // “Lift” the iterator .max() method to work on the values in Results using process_results
///
/// let first_max = process_results(first_values, |iter| iter.max().unwrap_or(0));
/// let second_max = process_results(second_values, |iter| iter.max().unwrap_or(0));
///
/// assert_eq!(first_max, Ok(3));
/// assert!(second_max.is_err());
/// ```
pub fn process_results<I, F, T, E, R>(iterable: I, processor: F) -> Result<R, E>
    where I: IntoIterator<Item = Result<T, E>>,
          F: FnOnce(ProcessResults<I::IntoIter, E>) -> R
{
    let iter = iterable.into_iter();
    let mut error = Ok(());

    let result = processor(ProcessResults { error: &mut error, iter });

    error.map(|_| result)
}
<|endoftext|>


<commit_before>// http://rosettacode.org/wiki/Tree_traversal

#![feature(box_syntax, box_patterns)]

use std::collections::VecDeque;

#[derive(Debug)]
struct TreeNode<T> {
    value: T,
    left: Option<Box<TreeNode<T>>>,
    right: Option<Box<TreeNode<T>>>,
}

enum TraversalMethod {
    PreOrder,
    InOrder,
    PostOrder,
    LevelOrder,
}

impl<T> TreeNode<T> {
    pub fn new(arr: &[[i8; 3]]) -> TreeNode<i8> {

        let l = match arr[0][1] {
            -1 => None,
            i @ _ => Some(Box::new(TreeNode::<i8>::new(&arr[(i - arr[0][0]) as usize..]))),
        };
        let r = match arr[0][2] {
            -1 => None,
            i @ _ => Some(Box::new(TreeNode::<i8>::new(&arr[(i - arr[0][0]) as usize..]))),
        };

        TreeNode {
            value: arr[0][0],
            left: l,
            right: r,
        }
    }

    pub fn traverse(&self, tr: &TraversalMethod) -> Vec<&TreeNode<T>> {
        match tr {
            &TraversalMethod::PreOrder => self.iterative_preorder(),
            &TraversalMethod::InOrder => self.iterative_inorder(),
            &TraversalMethod::PostOrder => self.iterative_postorder(),
            &TraversalMethod::LevelOrder => self.iterative_levelorder(),
        }
    }

    fn iterative_preorder(&self) -> Vec<&TreeNode<T>> {
        let mut stack: Vec<&TreeNode<T>> = Vec::new();
        let mut res: Vec<&TreeNode<T>> = Vec::new();

        stack.push(self);
        while !stack.is_empty() {
            let node = stack.pop().unwrap();
            res.push(node);
            match node.right {
                None => {}
                Some(box ref n) => stack.push(n),
            }
            match node.left {
                None => {}
                Some(box ref n) => stack.push(n),
            }
        }
        res
    }

    // Leftmost to rightmost
    fn iterative_inorder(&self) -> Vec<&TreeNode<T>> {
        let mut stack: Vec<&TreeNode<T>> = Vec::new();
        let mut res: Vec<&TreeNode<T>> = Vec::new();
        let mut p = self;

        loop {
            // Stack parents and right children while left-descending
            loop {
                match p.right {
                    None => {}
                    Some(box ref n) => stack.push(n),
                }
                stack.push(p);
                match p.left {
                    None => break,
                    Some(box ref n) => p = n,
                }
            }
            // Visit the nodes with no right child
            p = stack.pop().unwrap();
            while !stack.is_empty() && p.right.is_none() {
                res.push(p);
                p = stack.pop().unwrap();
            }
            // First node that can potentially have a right child:
            res.push(p);
            if stack.is_empty() {
                break;
            } else {
                p = stack.pop().unwrap();
            }
        }
        res
    }

    // Left-to-right postorder is same sequence as right-to-left preorder, reversed
    fn iterative_postorder(&self) -> Vec<&TreeNode<T>> {
        let mut stack: Vec<&TreeNode<T>> = Vec::new();
        let mut res: Vec<&TreeNode<T>> = Vec::new();

        stack.push(self);
        while !stack.is_empty() {
            let node = stack.pop().unwrap();
            res.push(node);
            match node.left {
                None => {}
                Some(box ref n) => stack.push(n),
            }
            match node.right {
                None => {}
                Some(box ref n) => stack.push(n),
            }
        }
        let rev_iter = res.iter().rev();
        let mut rev: Vec<&TreeNode<T>> = Vec::new();
        for elem in rev_iter {
            rev.push(elem);
        }
        rev
    }

    fn iterative_levelorder(&self) -> Vec<&TreeNode<T>> {
        let mut queue: VecDeque<&TreeNode<T>> = VecDeque::new();
        let mut res: Vec<&TreeNode<T>> = Vec::new();

        queue.push_back(self);
        while !queue.is_empty() {
            let node = queue.pop_front().unwrap();
            res.push(node);
            match node.left {
                None => {}
                Some(box ref n) => queue.push_back(n),
            }
            match node.right {
                None => {}
                Some(box ref n) => queue.push_back(n),
            }
        }
        res
    }
}

fn main() {
    // Array representation of task tree
    let arr_tree = [[1, 2, 3],
                    [2, 4, 5],
                    [3, 6, -1],
                    [4, 7, -1],
                    [5, -1, -1],
                    [6, 8, 9],
                    [7, -1, -1],
                    [8, -1, -1],
                    [9, -1, -1]];

    let root = TreeNode::<i8>::new(&arr_tree);

    let method_labels = [(TraversalMethod::PreOrder, "pre-order:"),
                         (TraversalMethod::InOrder, "in-order:"),
                         (TraversalMethod::PostOrder, "post-order:"),
                         (TraversalMethod::LevelOrder, "level-order:")];

    for method_label in &method_labels {
        print!("{}\t", method_label.1);
        for n in root.traverse(&method_label.0) {
            print!(" {}", n.value);
        }
        print!("\n");
    }
}

#[cfg(test)]
mod tests {
    use super::{TreeNode, TraversalMethod};

    macro_rules! trav_values {
        ($x:expr) => ($x.iter().map(|n| n.value).collect(););
    }

    #[test]
    fn test_traversals() {
        let arr_tree = [[1, 2, 3],
                        [2, 4, 5],
                        [3, 6, -1],
                        [4, 7, -1],
                        [5, -1, -1],
                        [6, 8, 9],
                        [7, -1, -1],
                        [8, -1, -1],
                        [9, -1, -1]];
        let root = TreeNode::<i8>::new(&arr_tree);

        let mut res: Vec<i8>;
        res = trav_values!(root.traverse(&TraversalMethod::PreOrder));
        assert_eq!(res.as_slice(), &[1, 2, 4, 7, 5, 3, 6, 8, 9]);
        res = trav_values!(root.traverse(&TraversalMethod::InOrder));
        assert_eq!(res.as_slice(), &[7, 4, 2, 5, 1, 8, 6, 9, 3]);
        res = trav_values!(root.traverse(&TraversalMethod::PostOrder));
        assert_eq!(res.as_slice(), &[7, 4, 5, 2, 8, 9, 6, 3, 1]);
        res = trav_values!(root.traverse(&TraversalMethod::LevelOrder));
        assert_eq!(res.as_slice(), &[1, 2, 3, 4, 5, 6, 7, 8, 9]);
    }
}
<commit_msg>allow enum variant names with the same postfix<commit_after>// http://rosettacode.org/wiki/Tree_traversal

#![feature(box_syntax, box_patterns)]

use std::collections::VecDeque;

#[derive(Debug)]
struct TreeNode<T> {
    value: T,
    left: Option<Box<TreeNode<T>>>,
    right: Option<Box<TreeNode<T>>>,
}

#[cfg_attr(feature = "clippy", allow(enum_variant_names))]
enum TraversalMethod {
    PreOrder,
    InOrder,
    PostOrder,
    LevelOrder,
}

impl<T> TreeNode<T> {
    pub fn new(arr: &[[i8; 3]]) -> TreeNode<i8> {

        let l = match arr[0][1] {
            -1 => None,
            i @ _ => Some(Box::new(TreeNode::<i8>::new(&arr[(i - arr[0][0]) as usize..]))),
        };
        let r = match arr[0][2] {
            -1 => None,
            i @ _ => Some(Box::new(TreeNode::<i8>::new(&arr[(i - arr[0][0]) as usize..]))),
        };

        TreeNode {
            value: arr[0][0],
            left: l,
            right: r,
        }
    }

    pub fn traverse(&self, tr: &TraversalMethod) -> Vec<&TreeNode<T>> {
        match tr {
            &TraversalMethod::PreOrder => self.iterative_preorder(),
            &TraversalMethod::InOrder => self.iterative_inorder(),
            &TraversalMethod::PostOrder => self.iterative_postorder(),
            &TraversalMethod::LevelOrder => self.iterative_levelorder(),
        }
    }

    fn iterative_preorder(&self) -> Vec<&TreeNode<T>> {
        let mut stack: Vec<&TreeNode<T>> = Vec::new();
        let mut res: Vec<&TreeNode<T>> = Vec::new();

        stack.push(self);
        while !stack.is_empty() {
            let node = stack.pop().unwrap();
            res.push(node);
            match node.right {
                None => {}
                Some(box ref n) => stack.push(n),
            }
            match node.left {
                None => {}
                Some(box ref n) => stack.push(n),
            }
        }
        res
    }

    // Leftmost to rightmost
    fn iterative_inorder(&self) -> Vec<&TreeNode<T>> {
        let mut stack: Vec<&TreeNode<T>> = Vec::new();
        let mut res: Vec<&TreeNode<T>> = Vec::new();
        let mut p = self;

        loop {
            // Stack parents and right children while left-descending
            loop {
                match p.right {
                    None => {}
                    Some(box ref n) => stack.push(n),
                }
                stack.push(p);
                match p.left {
                    None => break,
                    Some(box ref n) => p = n,
                }
            }
            // Visit the nodes with no right child
            p = stack.pop().unwrap();
            while !stack.is_empty() && p.right.is_none() {
                res.push(p);
                p = stack.pop().unwrap();
            }
            // First node that can potentially have a right child:
            res.push(p);
            if stack.is_empty() {
                break;
            } else {
                p = stack.pop().unwrap();
            }
        }
        res
    }

    // Left-to-right postorder is same sequence as right-to-left preorder, reversed
    fn iterative_postorder(&self) -> Vec<&TreeNode<T>> {
        let mut stack: Vec<&TreeNode<T>> = Vec::new();
        let mut res: Vec<&TreeNode<T>> = Vec::new();

        stack.push(self);
        while !stack.is_empty() {
            let node = stack.pop().unwrap();
            res.push(node);
            match node.left {
                None => {}
                Some(box ref n) => stack.push(n),
            }
            match node.right {
                None => {}
                Some(box ref n) => stack.push(n),
            }
        }
        let rev_iter = res.iter().rev();
        let mut rev: Vec<&TreeNode<T>> = Vec::new();
        for elem in rev_iter {
            rev.push(elem);
        }
        rev
    }

    fn iterative_levelorder(&self) -> Vec<&TreeNode<T>> {
        let mut queue: VecDeque<&TreeNode<T>> = VecDeque::new();
        let mut res: Vec<&TreeNode<T>> = Vec::new();

        queue.push_back(self);
        while !queue.is_empty() {
            let node = queue.pop_front().unwrap();
            res.push(node);
            match node.left {
                None => {}
                Some(box ref n) => queue.push_back(n),
            }
            match node.right {
                None => {}
                Some(box ref n) => queue.push_back(n),
            }
        }
        res
    }
}

fn main() {
    // Array representation of task tree
    let arr_tree = [[1, 2, 3],
                    [2, 4, 5],
                    [3, 6, -1],
                    [4, 7, -1],
                    [5, -1, -1],
                    [6, 8, 9],
                    [7, -1, -1],
                    [8, -1, -1],
                    [9, -1, -1]];

    let root = TreeNode::<i8>::new(&arr_tree);

    let method_labels = [(TraversalMethod::PreOrder, "pre-order:"),
                         (TraversalMethod::InOrder, "in-order:"),
                         (TraversalMethod::PostOrder, "post-order:"),
                         (TraversalMethod::LevelOrder, "level-order:")];

    for method_label in &method_labels {
        print!("{}\t", method_label.1);
        for n in root.traverse(&method_label.0) {
            print!(" {}", n.value);
        }
        print!("\n");
    }
}

#[cfg(test)]
mod tests {
    use super::{TreeNode, TraversalMethod};

    macro_rules! trav_values {
        ($x:expr) => ($x.iter().map(|n| n.value).collect(););
    }

    #[test]
    fn test_traversals() {
        let arr_tree = [[1, 2, 3],
                        [2, 4, 5],
                        [3, 6, -1],
                        [4, 7, -1],
                        [5, -1, -1],
                        [6, 8, 9],
                        [7, -1, -1],
                        [8, -1, -1],
                        [9, -1, -1]];
        let root = TreeNode::<i8>::new(&arr_tree);

        let mut res: Vec<i8>;
        res = trav_values!(root.traverse(&TraversalMethod::PreOrder));
        assert_eq!(res.as_slice(), &[1, 2, 4, 7, 5, 3, 6, 8, 9]);
        res = trav_values!(root.traverse(&TraversalMethod::InOrder));
        assert_eq!(res.as_slice(), &[7, 4, 2, 5, 1, 8, 6, 9, 3]);
        res = trav_values!(root.traverse(&TraversalMethod::PostOrder));
        assert_eq!(res.as_slice(), &[7, 4, 5, 2, 8, 9, 6, 3, 1]);
        res = trav_values!(root.traverse(&TraversalMethod::LevelOrder));
        assert_eq!(res.as_slice(), &[1, 2, 3, 4, 5, 6, 7, 8, 9]);
    }
}
<|endoftext|>


<commit_before>macro_rules! skip_bytes (
  ($input: expr, $length: expr, $offset: expr) => (
    {
      match take!($input, $length) {
        IResult::Done(i, bytes)   => {
          let head        = bytes[0] << $offset;
          let tail        = &bytes[1..];
          let is_all_zero = tail.iter().all(|byte| *byte == 0);

          if head == 0 && is_all_zero {
            IResult::Done(i, bytes)
          } else {
            IResult::Error(Err::Position(ErrorCode::Digit as u32, $input))
          }
        }
        IResult::Error(error)     => IResult::Error(error),
        IResult::Incomplete(need) => IResult::Incomplete(need),
      }
    }
  );
);
<commit_msg>Use the `$crate` inside `skip_bytes`<commit_after>macro_rules! skip_bytes (
  ($input: expr, $length: expr, $offset: expr) => (
    {
      match take!($input, $length) {
        $crate::nom::IResult::Done(i, bytes)   => {
          let head        = bytes[0] << $offset;
          let tail        = &bytes[1..];
          let is_all_zero = tail.iter().all(|byte| *byte == 0);

          if head == 0 && is_all_zero {
            $crate::nom::IResult::Done(i, bytes)
          } else {
            $crate::nom::IResult::Error($crate::nom::Err::Position(
              $crate::nom::ErrorCode::Digit as u32, $input))
          }
        }
        $crate::nom::IResult::Error(error)     =>
          $crate::nom::IResult::Error(error),
        $crate::nom::IResult::Incomplete(need) =>
          $crate::nom::IResult::Incomplete(need),
      }
    }
  );
);
<|endoftext|>


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

use std::{borrow::Cow, cell::Cell};

use enum_primitive_derive::Primitive;
use failure::{self, ensure, format_err};
use num_traits::{FromPrimitive, ToPrimitive};
use serde::{de::DeserializeOwned, Serialize};
use serde_derive::{Deserialize, Serialize};

use crate::{BinaryKey, BinaryValue};

use super::{IndexAccess, IndexAddress, View};

/// TODO Add documentation. [ECR-2820]
const INDEXES_POOL_NAME: &str = "__INDEXES_POOL__";
/// TODO Add documentation. [ECR-2820]
const INDEXES_POOL_LEN_NAME: &str = "INDEXES_POOL_LEN";

/// TODO Add documentation. [ECR-2820]
#[derive(Debug, Copy, Clone, PartialEq, Primitive, Serialize, Deserialize)]
pub enum IndexType {
    Map = 1,
    List = 2,
    Entry = 3,
    ValueSet = 4,
    KeySet = 5,
    SparseList = 6,
    ProofList = 7,
    ProofMap = 8,
    Unknown = 255,
}

impl BinaryValue for IndexType {
    fn to_bytes(&self) -> Vec<u8> {
        // `.unwrap()` is safe: IndexType is always in range 1..255
        vec![self.to_u8().unwrap()]
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        let bytes = bytes.as_ref();
        ensure!(
            bytes.len() == 1,
            "Wrong buffer size: actual {}, expected 1",
            bytes.len()
        );

        let value = bytes[0];
        Self::from_u8(value).ok_or_else(|| format_err!("Unknown value: {}", value))
    }
}

impl Default for IndexType {
    fn default() -> Self {
        IndexType::Unknown
    }
}

/// TODO Add documentation. [ECR-2820]
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct IndexMetadata<V> {
    index_type: IndexType,
    identifier: u64,
    state: V,
}

impl<V> BinaryValue for IndexMetadata<V>
where
    V: Serialize + DeserializeOwned,
{
    fn to_bytes(&self) -> Vec<u8> {
        bincode::serialize(self).unwrap()
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        bincode::deserialize(bytes.as_ref()).map_err(From::from)
    }
}

impl<V> IndexMetadata<V> {
    fn index_address(&self) -> IndexAddress {
        IndexAddress::new().append_bytes(&self.identifier)
    }
}

impl IndexAddress {
    fn index_name(&self) -> Vec<u8> {
        if let Some(bytes) = self.bytes() {
            concat_keys!(self.name(), bytes)
        } else {
            concat_keys!(self.name())
        }
    }
}

/// TODO Add documentation. [ECR-2820]
pub fn index_metadata<T, V>(
    index_access: T,
    index_address: &IndexAddress,
    index_type: IndexType,
) -> (IndexAddress, IndexState<T, V>)
where
    T: IndexAccess,
    V: BinaryValue + Copy + Serialize + DeserializeOwned + Default,
{
    let index_name = index_address.index_name();

    let mut pool = IndexesPool::new(index_access);
    let metadata = if let Some(metadata) = pool.index_metadata(&index_name) {
        assert_eq!(
            metadata.index_type, index_type,
            "Index type doesn't match specified"
        );
        metadata
    } else {
        pool.set_index_metadata(&index_name, index_type)
    };

    let index_address = metadata.index_address();
    let index_state = IndexState::new(index_access, index_name, metadata);
    (index_address, index_state)
}

/// TODO Add documentation. [ECR-2820]
struct IndexesPool<T: IndexAccess>(View<T>);

impl<T: IndexAccess> IndexesPool<T> {
    fn new(index_access: T) -> Self {
        let pool_address = IndexAddress::from(INDEXES_POOL_NAME);
        Self(View::new(index_access, pool_address))
    }

    fn index_metadata<V>(&self, index_name: &[u8]) -> Option<IndexMetadata<V>>
    where
        V: BinaryValue + Serialize + DeserializeOwned + Default + Copy,
    {
        self.0.get(index_name)
    }

    fn set_index_metadata<V>(
        &mut self,
        index_name: &[u8],
        index_type: IndexType,
    ) -> IndexMetadata<V>
    where
        V: BinaryValue + Serialize + DeserializeOwned + Default + Copy,
    {
        let mut pool_len = View::new(
            self.0.index_access,
            IndexAddress::from(INDEXES_POOL_LEN_NAME),
        );
        let len: u64 = pool_len.get(&()).unwrap_or_default();

        let metadata = IndexMetadata {
            index_type,
            identifier: len,
            state: V::default(),
        };

        self.0.put(index_name, metadata);
        pool_len.put(&(), len + 1);
        metadata
    }
}

/// TODO Add documentation. [ECR-2820]
pub struct IndexState<T, V>
where
    V: BinaryValue + Serialize + DeserializeOwned + Default + Copy,
    T: IndexAccess,
{
    index_access: T,
    index_name: Vec<u8>,
    cache: Cell<IndexMetadata<V>>,
}

impl<T, V> IndexState<T, V>
where
    V: BinaryValue + Serialize + DeserializeOwned + Default + Copy,
    T: IndexAccess,
{
    pub fn new(index_access: T, index_name: Vec<u8>, metadata: IndexMetadata<V>) -> Self {
        Self {
            index_access,
            index_name,
            cache: Cell::new(metadata),
        }
    }

    /// TODO Add documentation. [ECR-2820]
    pub fn get(&self) -> V {
        self.cache.get().state
    }

    /// TODO Add documentation. [ECR-2820]
    pub fn set(&mut self, state: V) {
        let mut cache = self.cache.get_mut();
        cache.state = state;
    }
}

impl<T, V> std::fmt::Debug for IndexState<T, V>
where
    T: IndexAccess,
    V: BinaryValue + Serialize + DeserializeOwned + Default + Copy,
{
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        f.debug_struct("IndexState").finish()
    }
}

impl<T, V> Drop for IndexState<T, V>
where
    V: BinaryValue + Serialize + DeserializeOwned + Default + Copy,
    T: IndexAccess,
{
    fn drop(&mut self) {
        View::new(self.index_access, IndexAddress::from(INDEXES_POOL_NAME))
            .put(&self.index_name, self.cache.get());
    }
}

#[cfg(test)]
mod tests {
    use std::borrow::Cow;

    use crate::BinaryValue;

    use super::IndexType;

    #[test]
    fn test_index_type_binary_value_correct() {
        let index_type = IndexType::ProofMap;
        let buf = index_type.to_bytes();
        assert_eq!(IndexType::from_bytes(Cow::Owned(buf)).unwrap(), index_type);
    }

    #[test]
    #[should_panic(expected = "Wrong buffer size: actual 2, expected 1")]
    fn test_index_type_binary_value_incorrect_buffer_len() {
        let buf = vec![1, 2];
        IndexType::from_bytes(Cow::Owned(buf)).unwrap();
    }

    #[test]
    #[should_panic(expected = "Unknown value: 127")]
    fn test_index_type_binary_value_incorrect_value() {
        let buf = vec![127];
        IndexType::from_bytes(Cow::Owned(buf)).unwrap();
    }
}
<commit_msg>Don't update value in destructor<commit_after>// Copyright 2018 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{borrow::Cow, cell::Cell};

use enum_primitive_derive::Primitive;
use failure::{self, ensure, format_err};
use num_traits::{FromPrimitive, ToPrimitive};
use serde::{de::DeserializeOwned, Serialize};
use serde_derive::{Deserialize, Serialize};

use crate::{BinaryKey, BinaryValue};

use super::{IndexAccess, IndexAddress, View};

/// TODO Add documentation. [ECR-2820]
const INDEXES_POOL_NAME: &str = "__INDEXES_POOL__";
/// TODO Add documentation. [ECR-2820]
const INDEXES_POOL_LEN_NAME: &str = "INDEXES_POOL_LEN";

/// TODO Add documentation. [ECR-2820]
#[derive(Debug, Copy, Clone, PartialEq, Primitive, Serialize, Deserialize)]
pub enum IndexType {
    Map = 1,
    List = 2,
    Entry = 3,
    ValueSet = 4,
    KeySet = 5,
    SparseList = 6,
    ProofList = 7,
    ProofMap = 8,
    Unknown = 255,
}

impl BinaryValue for IndexType {
    fn to_bytes(&self) -> Vec<u8> {
        // `.unwrap()` is safe: IndexType is always in range 1..255
        vec![self.to_u8().unwrap()]
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        let bytes = bytes.as_ref();
        ensure!(
            bytes.len() == 1,
            "Wrong buffer size: actual {}, expected 1",
            bytes.len()
        );

        let value = bytes[0];
        Self::from_u8(value).ok_or_else(|| format_err!("Unknown value: {}", value))
    }
}

impl Default for IndexType {
    fn default() -> Self {
        IndexType::Unknown
    }
}

/// TODO Add documentation. [ECR-2820]
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct IndexMetadata<V> {
    index_type: IndexType,
    identifier: u64,
    state: V,
}

impl<V> BinaryValue for IndexMetadata<V>
where
    V: Serialize + DeserializeOwned,
{
    fn to_bytes(&self) -> Vec<u8> {
        bincode::serialize(self).unwrap()
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        bincode::deserialize(bytes.as_ref()).map_err(From::from)
    }
}

impl<V> IndexMetadata<V> {
    fn index_address(&self) -> IndexAddress {
        IndexAddress::new().append_bytes(&self.identifier)
    }
}

impl IndexAddress {
    fn index_name(&self) -> Vec<u8> {
        if let Some(bytes) = self.bytes() {
            concat_keys!(self.name(), bytes)
        } else {
            concat_keys!(self.name())
        }
    }
}

/// TODO Add documentation. [ECR-2820]
pub fn index_metadata<T, V>(
    index_access: T,
    index_address: &IndexAddress,
    index_type: IndexType,
) -> (IndexAddress, IndexState<T, V>)
where
    T: IndexAccess,
    V: BinaryValue + Copy + Serialize + DeserializeOwned + Default,
{
    let index_name = index_address.index_name();

    let mut pool = IndexesPool::new(index_access);
    let metadata = if let Some(metadata) = pool.index_metadata(&index_name) {
        assert_eq!(
            metadata.index_type, index_type,
            "Index type doesn't match specified"
        );
        metadata
    } else {
        pool.set_index_metadata(&index_name, index_type)
    };

    let index_address = metadata.index_address();
    let index_state = IndexState::new(index_access, index_name, metadata);
    (index_address, index_state)
}

/// TODO Add documentation. [ECR-2820]
struct IndexesPool<T: IndexAccess>(View<T>);

impl<T: IndexAccess> IndexesPool<T> {
    fn new(index_access: T) -> Self {
        let pool_address = IndexAddress::from(INDEXES_POOL_NAME);
        Self(View::new(index_access, pool_address))
    }

    fn index_metadata<V>(&self, index_name: &[u8]) -> Option<IndexMetadata<V>>
    where
        V: BinaryValue + Serialize + DeserializeOwned + Default + Copy,
    {
        self.0.get(index_name)
    }

    fn set_index_metadata<V>(
        &mut self,
        index_name: &[u8],
        index_type: IndexType,
    ) -> IndexMetadata<V>
    where
        V: BinaryValue + Serialize + DeserializeOwned + Default + Copy,
    {
        let mut pool_len = View::new(
            self.0.index_access,
            IndexAddress::from(INDEXES_POOL_LEN_NAME),
        );
        let len: u64 = pool_len.get(&()).unwrap_or_default();

        let metadata = IndexMetadata {
            index_type,
            identifier: len,
            state: V::default(),
        };

        self.0.put(index_name, metadata);
        pool_len.put(&(), len + 1);
        metadata
    }
}

/// TODO Add documentation. [ECR-2820]
pub struct IndexState<T, V>
where
    V: BinaryValue + Serialize + DeserializeOwned + Default + Copy,
    T: IndexAccess,
{
    index_access: T,
    index_name: Vec<u8>,
    cache: Cell<IndexMetadata<V>>,
}

impl<T, V> IndexState<T, V>
where
    V: BinaryValue + Serialize + DeserializeOwned + Default + Copy,
    T: IndexAccess,
{
    pub fn new(index_access: T, index_name: Vec<u8>, metadata: IndexMetadata<V>) -> Self {
        Self {
            index_access,
            index_name,
            cache: Cell::new(metadata),
        }
    }

    /// TODO Add documentation. [ECR-2820]
    pub fn get(&self) -> V {
        self.cache.get().state
    }

    /// TODO Add documentation. [ECR-2820]
    pub fn set(&mut self, state: V) {
        let mut cache = self.cache.get_mut();
        cache.state = state;
        View::new(self.index_access, IndexAddress::from(INDEXES_POOL_NAME))
            .put(&self.index_name, *cache);
    }
}

impl<T, V> std::fmt::Debug for IndexState<T, V>
where
    T: IndexAccess,
    V: BinaryValue + Serialize + DeserializeOwned + Default + Copy,
{
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        f.debug_struct("IndexState").finish()
    }
}

#[cfg(test)]
mod tests {
    use std::borrow::Cow;

    use crate::BinaryValue;

    use super::IndexType;

    #[test]
    fn test_index_type_binary_value_correct() {
        let index_type = IndexType::ProofMap;
        let buf = index_type.to_bytes();
        assert_eq!(IndexType::from_bytes(Cow::Owned(buf)).unwrap(), index_type);
    }

    #[test]
    #[should_panic(expected = "Wrong buffer size: actual 2, expected 1")]
    fn test_index_type_binary_value_incorrect_buffer_len() {
        let buf = vec![1, 2];
        IndexType::from_bytes(Cow::Owned(buf)).unwrap();
    }

    #[test]
    #[should_panic(expected = "Unknown value: 127")]
    fn test_index_type_binary_value_incorrect_value() {
        let buf = vec![127];
        IndexType::from_bytes(Cow::Owned(buf)).unwrap();
    }
}
<|endoftext|>