<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;
//! use bear_lib_terminal::terminal::config::font;
//! use bear_lib_terminal::geometry::Size;
//! # assert!({let result =
//! terminal::set(font::true_type(font::Origin::Root, "UbuntuMono-R.ttf", Size::new(0, 12)));
//! # result}); assert!({let result =
//! terminal::set(font::bitmap(font::Origin::Offset('^'), "circumflex.png"));
//! # result}); assert!({let result =
//! terminal::set(font::bitmap(font::Origin::Offset('\u{E000}'), "tileset.png").size(Size::new(16, 16)).spacing(Size::new(2, 1)));
//! # result});
//! ```

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.size {
				None           => "".to_string(),
				Some(ref size) => format!(", size={}", size),
			},
			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"),
		}
	}
}
<commit_msg>Fix in the `Bitmap` documentation<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;
//! use bear_lib_terminal::terminal::config::font;
//! use bear_lib_terminal::geometry::Size;
//! # assert!({let result =
//! terminal::set(font::true_type(font::Origin::Root, "UbuntuMono-R.ttf", Size::new(0, 12)));
//! # result}); assert!({let result =
//! terminal::set(font::bitmap(font::Origin::Offset('^'), "circumflex.png"));
//! # result}); assert!({let result =
//! terminal::set(font::bitmap(font::Origin::Offset('\u{E000}'), "tileset.png").size(Size::new(16, 16)).spacing(Size::new(2, 1)));
//! # result});
//! ```

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 [`bitmap()`](fn.bitmap.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.size {
				None           => "".to_string(),
				Some(ref size) => format!(", size={}", size),
			},
			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 serde_json::{Value, from_str};
use serde_json::error::Result as R;
use serde_json::Serializer;
use serde::ser::Serialize;
use serde::ser::Serializer as Ser;

use std::collections::HashMap;
use std::io::stdout;

use super::super::parser::{FileHeaderParser, ParserError};
use super::super::file::{FileHeaderSpec, FileHeaderData};

struct JsonHeaderParser<'a> {
    spec: &'a FileHeaderSpec,
}

impl<'a> FileHeaderParser<'a> for JsonHeaderParser<'a> {

    fn new(spec: &'a FileHeaderSpec) -> JsonHeaderParser<'a> {
        JsonHeaderParser {
            spec: spec
        }
    }

    fn read(&self, string: Option<String>)
        -> Result<FileHeaderData, ParserError>
    {
        if string.is_some() {
            let s = string.unwrap();
            debug!("Deserializing: {}", s);
            let fromstr : R<Value> = from_str(&s[..]);
            if let Ok(content) = fromstr {
                Ok(visit_json(&content))
            } else {
                Err(ParserError::short("Unknown JSON parser error", s.clone(), 0))
            }
        } else {
            Ok(FileHeaderData::Null)
        }
    }

    fn write(&self, data: &FileHeaderData) -> Result<String, ParserError> {
        let mut ser = Serializer::pretty(stdout());
        data.serialize(&mut ser);
        Ok(String::from(""))
    }

}

// TODO: This function must be able to return a parser error
fn visit_json(v: &Value) -> FileHeaderData {
    match v {
        &Value::Null             => FileHeaderData::Null,
        &Value::Bool(b)          => FileHeaderData::Bool(b),
        &Value::I64(i)           => FileHeaderData::Integer(i),
        &Value::U64(u)           => FileHeaderData::UInteger(u),
        &Value::F64(f)           => FileHeaderData::Float(f),
        &Value::String(ref s)        => FileHeaderData::Text(s.clone()),
        &Value::Array(ref vec)       => {
            FileHeaderData::Array {
                values: Box::new(vec.clone().into_iter().map(|i| visit_json(v)).collect())
            }
        },
        &Value::Object(ref btree)    => {
            FileHeaderData::Map{
                keys: btree.clone().iter().map(|(k, v)|
                    FileHeaderData::Key {
                        name: k.clone(),
                        value: Box::new(visit_json(v)),
                    }
                ).collect()
            }
        }
    }
}

impl Serialize for FileHeaderData {

    fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error>
        where S: Ser
    {
        match self {
            &FileHeaderData::Null               => {
                let o : Option<bool> = None;
                o.serialize(ser)
            },
            &FileHeaderData::Bool(ref b)            => b.serialize(ser),
            &FileHeaderData::Integer(ref i)         => i.serialize(ser),
            &FileHeaderData::UInteger(ref u)        => u.serialize(ser),
            &FileHeaderData::Float(ref f)           => f.serialize(ser),
            &FileHeaderData::Text(ref s)            => (&s[..]).serialize(ser),
            &FileHeaderData::Array{values: ref vs}  => vs.serialize(ser),
            &FileHeaderData::Map{keys: ref ks}      => ks.serialize(ser),
            &FileHeaderData::Key{name: ref n, value: ref v}   => {
                let mut hm = HashMap::new();
                hm.insert(n, v);
                hm.serialize(ser)
            }
        }
    }

}
<commit_msg>Fix Bug: Pass iterator value, not currently parsed value<commit_after>use serde_json::{Value, from_str};
use serde_json::error::Result as R;
use serde_json::Serializer;
use serde::ser::Serialize;
use serde::ser::Serializer as Ser;

use std::collections::HashMap;
use std::io::stdout;

use super::super::parser::{FileHeaderParser, ParserError};
use super::super::file::{FileHeaderSpec, FileHeaderData};

struct JsonHeaderParser<'a> {
    spec: &'a FileHeaderSpec,
}

impl<'a> FileHeaderParser<'a> for JsonHeaderParser<'a> {

    fn new(spec: &'a FileHeaderSpec) -> JsonHeaderParser<'a> {
        JsonHeaderParser {
            spec: spec
        }
    }

    fn read(&self, string: Option<String>)
        -> Result<FileHeaderData, ParserError>
    {
        if string.is_some() {
            let s = string.unwrap();
            debug!("Deserializing: {}", s);
            let fromstr : R<Value> = from_str(&s[..]);
            if let Ok(content) = fromstr {
                Ok(visit_json(&content))
            } else {
                Err(ParserError::short("Unknown JSON parser error", s.clone(), 0))
            }
        } else {
            Ok(FileHeaderData::Null)
        }
    }

    fn write(&self, data: &FileHeaderData) -> Result<String, ParserError> {
        let mut ser = Serializer::pretty(stdout());
        data.serialize(&mut ser);
        Ok(String::from(""))
    }

}

// TODO: This function must be able to return a parser error
fn visit_json(v: &Value) -> FileHeaderData {
    match v {
        &Value::Null             => FileHeaderData::Null,
        &Value::Bool(b)          => FileHeaderData::Bool(b),
        &Value::I64(i)           => FileHeaderData::Integer(i),
        &Value::U64(u)           => FileHeaderData::UInteger(u),
        &Value::F64(f)           => FileHeaderData::Float(f),
        &Value::String(ref s)        => FileHeaderData::Text(s.clone()),
        &Value::Array(ref vec)       => {
            FileHeaderData::Array {
                values: Box::new(vec.clone().into_iter().map(|i| visit_json(&i)).collect())
            }
        },
        &Value::Object(ref btree)    => {
            FileHeaderData::Map{
                keys: btree.clone().iter().map(|(k, v)|
                    FileHeaderData::Key {
                        name: k.clone(),
                        value: Box::new(visit_json(v)),
                    }
                ).collect()
            }
        }
    }
}

impl Serialize for FileHeaderData {

    fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error>
        where S: Ser
    {
        match self {
            &FileHeaderData::Null               => {
                let o : Option<bool> = None;
                o.serialize(ser)
            },
            &FileHeaderData::Bool(ref b)            => b.serialize(ser),
            &FileHeaderData::Integer(ref i)         => i.serialize(ser),
            &FileHeaderData::UInteger(ref u)        => u.serialize(ser),
            &FileHeaderData::Float(ref f)           => f.serialize(ser),
            &FileHeaderData::Text(ref s)            => (&s[..]).serialize(ser),
            &FileHeaderData::Array{values: ref vs}  => vs.serialize(ser),
            &FileHeaderData::Map{keys: ref ks}      => ks.serialize(ser),
            &FileHeaderData::Key{name: ref n, value: ref v}   => {
                let mut hm = HashMap::new();
                hm.insert(n, v);
                hm.serialize(ser)
            }
        }
    }

}
<|endoftext|>


<commit_before>// * This file is part of the uutils coreutils package.
// *
// * (c) 2020 nicoo <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

extern crate rand;

use smallvec::SmallVec;
use std::cell::RefCell;
use std::fmt;

use crate::numeric::{gcd, Arithmetic, Montgomery};
use crate::{miller_rabin, rho, table};

type Exponent = u8;

#[derive(Clone, Debug)]
struct Decomposition(SmallVec<[(u64, Exponent); NUM_FACTORS_INLINE]>);

// The number of factors to inline directly into a `Decomposition` object.
// As a consequence of the Erdős–Kac theorem, the average number of prime
//  factors of integers < 10²⁵ ≃ 2⁸³ is 4, so we can use that value.
const NUM_FACTORS_INLINE: usize = 4;

impl Decomposition {
    fn one() -> Decomposition {
        Decomposition(SmallVec::new())
    }

    fn add(&mut self, factor: u64, exp: Exponent) {
        debug_assert!(exp > 0);
        // Assert the factor doesn't already exist in the Decomposition object
        debug_assert_eq!(self.0.iter_mut().find(|(f, _)| *f == factor), None);

        self.0.push((factor, exp))
    }

    fn is_one(&self) -> bool {
        self.0.is_empty()
    }

    fn pop(&mut self) -> Option<(u64, Exponent)> {
        self.0.pop()
    }

    fn product(&self) -> u64 {
        self.0
            .iter()
            .fold(1, |acc, (p, exp)| acc * p.pow(*exp as u32))
    }

    fn get(&self, p: u64) -> Option<&(u64, u8)> {
        self.0.iter().find(|(q, _)| *q == p)
    }
}

impl PartialEq for Decomposition {
    fn eq(&self, other: &Decomposition) -> bool {
        for p in &self.0 {
            if other.get(p.0) != Some(p) {
                return false;
            }
        }

        for p in &other.0 {
            if self.get(p.0) != Some(p) {
                return false;
            }
        }

        true
    }
}
impl Eq for Decomposition {}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Factors(RefCell<Decomposition>);

impl Factors {
    pub fn one() -> Factors {
        Factors(RefCell::new(Decomposition::one()))
    }

    pub fn add(&mut self, prime: u64, exp: Exponent) {
        debug_assert!(miller_rabin::is_prime(prime));
        self.0.borrow_mut().add(prime, exp)
    }

    #[cfg(test)]
    pub fn push(&mut self, prime: u64) {
        self.add(prime, 1)
    }

    fn product(&self) -> u64 {
        self.0.borrow().product()
    }
}

impl fmt::Display for Factors {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let v = &mut (self.0).borrow_mut().0;
        v.sort_unstable();

        for (p, exp) in v.iter() {
            for _ in 0..*exp {
                write!(f, " {}", p)?
            }
        }

        Ok(())
    }
}

fn _find_factor<A: Arithmetic + miller_rabin::Basis>(num: u64) -> Option<u64> {
    use miller_rabin::Result::*;

    let n = A::new(num);
    match miller_rabin::test::<A>(n) {
        Prime => None,
        Composite(d) => Some(d),
        Pseudoprime => Some(rho::find_divisor::<A>(n)),
    }
}

fn find_factor(num: u64) -> Option<u64> {
    if num < (1 << 32) {
        _find_factor::<Montgomery<u32>>(num)
    } else {
        _find_factor::<Montgomery<u64>>(num)
    }
}

pub fn factor(num: u64) -> Factors {
    let mut factors = Factors::one();

    if num < 2 {
        return factors;
    }

    let mut n = num;
    let n_zeros = num.trailing_zeros();
    if n_zeros > 0 {
        factors.add(2, n_zeros as Exponent);
        n >>= n_zeros;
    }
    debug_assert_eq!(num, n * factors.product());

    if n == 1 {
        return factors;
    }

    table::factor(&mut n, &mut factors);
    debug_assert_eq!(num, n * factors.product());

    if n == 1 {
        return factors;
    }

    let mut dec = Decomposition::one();
    dec.add(n, 1);

    while !dec.is_one() {
        // Check correctness invariant
        debug_assert_eq!(num, factors.product() * dec.product());

        let (factor, exp) = dec.pop().unwrap();

        if let Some(divisor) = find_factor(factor) {
            let mut gcd_queue = Decomposition::one();

            let quotient = factor / divisor;
            let mut trivial_gcd = quotient == divisor;
            if trivial_gcd {
                gcd_queue.add(divisor, exp + 1);
            } else {
                gcd_queue.add(divisor, exp);
                gcd_queue.add(quotient, exp);
            }

            while !trivial_gcd {
                debug_assert_eq!(factor, gcd_queue.product());

                let mut tmp = Decomposition::one();
                trivial_gcd = true;
                for i in 0..gcd_queue.0.len() - 1 {
                    let (mut a, exp_a) = gcd_queue.0[i];
                    let (mut b, exp_b) = gcd_queue.0[i + 1];

                    if a == 1 {
                        continue;
                    }

                    let g = gcd(a, b);
                    if g != 1 {
                        trivial_gcd = false;
                        a /= g;
                        b /= g;
                    }
                    if a != 1 {
                        tmp.add(a, exp_a);
                    }
                    if g != 1 {
                        tmp.add(g, exp_a + exp_b);
                    }

                    if i + 1 != gcd_queue.0.len() - 1 {
                        gcd_queue.0[i + 1].0 = b;
                    } else if b != 1 {
                        tmp.add(b, exp_b);
                    }
                }
                gcd_queue = tmp;
            }

            debug_assert_eq!(factor, gcd_queue.product());
            dec.0.extend(gcd_queue.0);
        } else {
            // factor is prime
            factors.add(factor, exp);
        }
    }

    factors
}

#[cfg(test)]
mod tests {
    use super::{factor, Factors};
    use quickcheck::quickcheck;

    #[test]
    fn factor_correctly_recombines_prior_test_failures() {
        let prior_failures = [
            // * integers with duplicate factors (ie, N.pow(M))
            4566769_u64, // == 2137.pow(2)
            2044854919485649_u64,
            18446739546814299361_u64,
            18446738440860217487_u64,
            18446736729316206481_u64,
        ];
        assert!(prior_failures.iter().all(|i| factor(*i).product() == *i));
    }

    #[test]
    fn factor_recombines_small() {
        assert!((1..10_000)
            .map(|i| 2 * i + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_small_squares() {
        // factor(18446736729316206481) == 4294966441 ** 2 ; causes debug_assert fault for repeated decomposition factor in add()
        // ToDO: explain/combine with factor_18446736729316206481 and factor_18446739546814299361 tests
        assert!((1..10_000)
            .map(|i| (2 * i + 1) * (2 * i + 1))
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_overflowing() {
        assert!((0..250)
            .map(|i| 2 * i + 2u64.pow(32) + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_strong_pseudoprime() {
        // This is a strong pseudoprime (wrt. miller_rabin::BASIS)
        //  and triggered a bug in rho::factor's codepath handling
        //  miller_rabbin::Result::Composite
        let pseudoprime = 17179869183;
        for _ in 0..20 {
            // Repeat the test 20 times, as it only fails some fraction
            // of the time.
            assert!(factor(pseudoprime).product() == pseudoprime);
        }
    }

    quickcheck! {
        fn factor_recombines(i: u64) -> bool {
            i == 0 || factor(i).product() == i
        }

        fn recombines_factors(f: Factors) -> bool {
            assert_eq!(factor(f.product()), f);
            true
        }
    }
}

#[cfg(test)]
impl quickcheck::Arbitrary for Factors {
    fn arbitrary<G: quickcheck::Gen>(gen: &mut G) -> Self {
        use rand::Rng;
        let mut f = Factors::one();
        let mut g = 1u64;
        let mut n = u64::MAX;

        // Adam Kalai's algorithm for generating uniformly-distributed
        // integers and their factorisation.
        //
        // See Generating Random Factored Numbers, Easily, J. Cryptology (2003)
        'attempt: loop {
            while n > 1 {
                n = gen.gen_range(1, n);
                if miller_rabin::is_prime(n) {
                    if let Some(h) = g.checked_mul(n) {
                        f.push(n);
                        g = h;
                    } else {
                        // We are overflowing u64, retry
                        continue 'attempt;
                    }
                }
            }

            return f;
        }
    }
}
<commit_msg>perf/factor ~ tune number of stack inlined decomposition values (~1% time improvement)<commit_after>// * This file is part of the uutils coreutils package.
// *
// * (c) 2020 nicoo <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

extern crate rand;

use smallvec::SmallVec;
use std::cell::RefCell;
use std::fmt;

use crate::numeric::{gcd, Arithmetic, Montgomery};
use crate::{miller_rabin, rho, table};

type Exponent = u8;

#[derive(Clone, Debug)]
struct Decomposition(SmallVec<[(u64, Exponent); NUM_FACTORS_INLINE]>);

// The number of factors to inline directly into a `Decomposition` object.
// As a consequence of the Erdős–Kac theorem, the average number of prime factors
// of integers < 10²⁵ ≃ 2⁸³ is 4, so we can use a slightly higher value.
const NUM_FACTORS_INLINE: usize = 5;

impl Decomposition {
    fn one() -> Decomposition {
        Decomposition(SmallVec::new())
    }

    fn add(&mut self, factor: u64, exp: Exponent) {
        debug_assert!(exp > 0);
        // Assert the factor doesn't already exist in the Decomposition object
        debug_assert_eq!(self.0.iter_mut().find(|(f, _)| *f == factor), None);

        self.0.push((factor, exp))
    }

    fn is_one(&self) -> bool {
        self.0.is_empty()
    }

    fn pop(&mut self) -> Option<(u64, Exponent)> {
        self.0.pop()
    }

    fn product(&self) -> u64 {
        self.0
            .iter()
            .fold(1, |acc, (p, exp)| acc * p.pow(*exp as u32))
    }

    fn get(&self, p: u64) -> Option<&(u64, u8)> {
        self.0.iter().find(|(q, _)| *q == p)
    }
}

impl PartialEq for Decomposition {
    fn eq(&self, other: &Decomposition) -> bool {
        for p in &self.0 {
            if other.get(p.0) != Some(p) {
                return false;
            }
        }

        for p in &other.0 {
            if self.get(p.0) != Some(p) {
                return false;
            }
        }

        true
    }
}
impl Eq for Decomposition {}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Factors(RefCell<Decomposition>);

impl Factors {
    pub fn one() -> Factors {
        Factors(RefCell::new(Decomposition::one()))
    }

    pub fn add(&mut self, prime: u64, exp: Exponent) {
        debug_assert!(miller_rabin::is_prime(prime));
        self.0.borrow_mut().add(prime, exp)
    }

    #[cfg(test)]
    pub fn push(&mut self, prime: u64) {
        self.add(prime, 1)
    }

    fn product(&self) -> u64 {
        self.0.borrow().product()
    }
}

impl fmt::Display for Factors {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let v = &mut (self.0).borrow_mut().0;
        v.sort_unstable();

        for (p, exp) in v.iter() {
            for _ in 0..*exp {
                write!(f, " {}", p)?
            }
        }

        Ok(())
    }
}

fn _find_factor<A: Arithmetic + miller_rabin::Basis>(num: u64) -> Option<u64> {
    use miller_rabin::Result::*;

    let n = A::new(num);
    match miller_rabin::test::<A>(n) {
        Prime => None,
        Composite(d) => Some(d),
        Pseudoprime => Some(rho::find_divisor::<A>(n)),
    }
}

fn find_factor(num: u64) -> Option<u64> {
    if num < (1 << 32) {
        _find_factor::<Montgomery<u32>>(num)
    } else {
        _find_factor::<Montgomery<u64>>(num)
    }
}

pub fn factor(num: u64) -> Factors {
    let mut factors = Factors::one();

    if num < 2 {
        return factors;
    }

    let mut n = num;
    let n_zeros = num.trailing_zeros();
    if n_zeros > 0 {
        factors.add(2, n_zeros as Exponent);
        n >>= n_zeros;
    }
    debug_assert_eq!(num, n * factors.product());

    if n == 1 {
        return factors;
    }

    table::factor(&mut n, &mut factors);
    debug_assert_eq!(num, n * factors.product());

    if n == 1 {
        return factors;
    }

    let mut dec = Decomposition::one();
    dec.add(n, 1);

    while !dec.is_one() {
        // Check correctness invariant
        debug_assert_eq!(num, factors.product() * dec.product());

        let (factor, exp) = dec.pop().unwrap();

        if let Some(divisor) = find_factor(factor) {
            let mut gcd_queue = Decomposition::one();

            let quotient = factor / divisor;
            let mut trivial_gcd = quotient == divisor;
            if trivial_gcd {
                gcd_queue.add(divisor, exp + 1);
            } else {
                gcd_queue.add(divisor, exp);
                gcd_queue.add(quotient, exp);
            }

            while !trivial_gcd {
                debug_assert_eq!(factor, gcd_queue.product());

                let mut tmp = Decomposition::one();
                trivial_gcd = true;
                for i in 0..gcd_queue.0.len() - 1 {
                    let (mut a, exp_a) = gcd_queue.0[i];
                    let (mut b, exp_b) = gcd_queue.0[i + 1];

                    if a == 1 {
                        continue;
                    }

                    let g = gcd(a, b);
                    if g != 1 {
                        trivial_gcd = false;
                        a /= g;
                        b /= g;
                    }
                    if a != 1 {
                        tmp.add(a, exp_a);
                    }
                    if g != 1 {
                        tmp.add(g, exp_a + exp_b);
                    }

                    if i + 1 != gcd_queue.0.len() - 1 {
                        gcd_queue.0[i + 1].0 = b;
                    } else if b != 1 {
                        tmp.add(b, exp_b);
                    }
                }
                gcd_queue = tmp;
            }

            debug_assert_eq!(factor, gcd_queue.product());
            dec.0.extend(gcd_queue.0);
        } else {
            // factor is prime
            factors.add(factor, exp);
        }
    }

    factors
}

#[cfg(test)]
mod tests {
    use super::{factor, Factors};
    use quickcheck::quickcheck;

    #[test]
    fn factor_correctly_recombines_prior_test_failures() {
        let prior_failures = [
            // * integers with duplicate factors (ie, N.pow(M))
            4566769_u64, // == 2137.pow(2)
            2044854919485649_u64,
            18446739546814299361_u64,
            18446738440860217487_u64,
            18446736729316206481_u64,
        ];
        assert!(prior_failures.iter().all(|i| factor(*i).product() == *i));
    }

    #[test]
    fn factor_recombines_small() {
        assert!((1..10_000)
            .map(|i| 2 * i + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_small_squares() {
        // factor(18446736729316206481) == 4294966441 ** 2 ; causes debug_assert fault for repeated decomposition factor in add()
        // ToDO: explain/combine with factor_18446736729316206481 and factor_18446739546814299361 tests
        assert!((1..10_000)
            .map(|i| (2 * i + 1) * (2 * i + 1))
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_overflowing() {
        assert!((0..250)
            .map(|i| 2 * i + 2u64.pow(32) + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_strong_pseudoprime() {
        // This is a strong pseudoprime (wrt. miller_rabin::BASIS)
        //  and triggered a bug in rho::factor's codepath handling
        //  miller_rabbin::Result::Composite
        let pseudoprime = 17179869183;
        for _ in 0..20 {
            // Repeat the test 20 times, as it only fails some fraction
            // of the time.
            assert!(factor(pseudoprime).product() == pseudoprime);
        }
    }

    quickcheck! {
        fn factor_recombines(i: u64) -> bool {
            i == 0 || factor(i).product() == i
        }

        fn recombines_factors(f: Factors) -> bool {
            assert_eq!(factor(f.product()), f);
            true
        }
    }
}

#[cfg(test)]
impl quickcheck::Arbitrary for Factors {
    fn arbitrary<G: quickcheck::Gen>(gen: &mut G) -> Self {
        use rand::Rng;
        let mut f = Factors::one();
        let mut g = 1u64;
        let mut n = u64::MAX;

        // Adam Kalai's algorithm for generating uniformly-distributed
        // integers and their factorisation.
        //
        // See Generating Random Factored Numbers, Easily, J. Cryptology (2003)
        'attempt: loop {
            while n > 1 {
                n = gen.gen_range(1, n);
                if miller_rabin::is_prime(n) {
                    if let Some(h) = g.checked_mul(n) {
                        f.push(n);
                        g = h;
                    } else {
                        // We are overflowing u64, retry
                        continue 'attempt;
                    }
                }
            }

            return f;
        }
    }
}
<|endoftext|>


<commit_before>// * This file is part of the uutils coreutils package.
// *
// * (c) 2020 nicoo <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

extern crate rand;

use smallvec::SmallVec;
use std::cell::RefCell;
use std::fmt;

use crate::numeric::{gcd, Arithmetic, Montgomery};
use crate::{miller_rabin, rho, table};

type Exponent = u8;

#[derive(Clone, Debug)]
struct Decomposition(SmallVec<[(u64, Exponent); NUM_FACTORS_INLINE]>);

// The number of factors to inline directly into a `Decomposition` object.
// As a consequence of the Erdős–Kac theorem, the average number of prime
//  factors of integers < 10²⁵ ≃ 2⁸³ is 4, so we can use that value.
const NUM_FACTORS_INLINE: usize = 4;

impl Decomposition {
    fn one() -> Decomposition {
        Decomposition(SmallVec::new())
    }

    fn add(&mut self, factor: u64, exp: Exponent) {
        debug_assert!(exp > 0);
        // Assert the factor doesn't already exist in the Decomposition object
        debug_assert_eq!(self.0.iter_mut().find(|(f, _)| *f == factor), None);

        self.0.push((factor, exp))
    }

    fn is_one(&self) -> bool {
        self.0.is_empty()
    }

    fn pop(&mut self) -> Option<(u64, Exponent)> {
        self.0.pop()
    }

    fn product(&self) -> u64 {
        self.0
            .iter()
            .fold(1, |acc, (p, exp)| acc * p.pow(*exp as u32))
    }

    fn get(&self, p: u64) -> Option<&(u64, u8)> {
        self.0.iter().find(|(q, _)| *q == p)
    }
}

impl PartialEq for Decomposition {
    fn eq(&self, other: &Decomposition) -> bool {
        for p in &self.0 {
            if other.get(p.0) != Some(p) {
                return false;
            }
        }

        for p in &other.0 {
            if self.get(p.0) != Some(p) {
                return false;
            }
        }

        true
    }
}
impl Eq for Decomposition {}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Factors(RefCell<Decomposition>);

impl Factors {
    pub fn one() -> Factors {
        Factors(RefCell::new(Decomposition::one()))
    }

    pub fn add(&mut self, prime: u64, exp: Exponent) {
        debug_assert!(miller_rabin::is_prime(prime));
        self.0.borrow_mut().add(prime, exp)
    }

    #[cfg(test)]
    pub fn push(&mut self, prime: u64) {
        self.add(prime, 1)
    }

    fn product(&self) -> u64 {
        self.0.borrow().product()
    }
}

impl fmt::Display for Factors {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let v = &mut (self.0).borrow_mut().0;
        v.sort_unstable();

        for (p, exp) in v.iter() {
            for _ in 0..*exp {
                write!(f, " {}", p)?
            }
        }

        Ok(())
    }
}

fn _find_factor<A: Arithmetic + miller_rabin::Basis>(num: u64) -> Option<u64> {
    use miller_rabin::Result::*;

    let n = A::new(num);
    match miller_rabin::test::<A>(n) {
        Prime => None,
        Composite(d) => Some(d),
        Pseudoprime => Some(rho::find_divisor::<A>(n)),
    }
}

fn find_factor(num: u64) -> Option<u64> {
    if num < (1 << 32) {
        _find_factor::<Montgomery<u32>>(num)
    } else {
        _find_factor::<Montgomery<u64>>(num)
    }
}

pub fn factor(num: u64) -> Factors {
    let mut factors = Factors::one();

    if num < 2 {
        return factors;
    }

    let mut n = num;
    let z = num.trailing_zeros();
    if z > 0 {
        factors.add(2, z as Exponent);
        n >>= z;
    }
    debug_assert_eq!(num, n * factors.product());

    if n == 1 {
        return factors;
    }

    table::factor(&mut n, &mut factors);
    debug_assert_eq!(num, n * factors.product());

    if n == 1 {
        return factors;
    }

    let mut dec = Decomposition::one();
    dec.add(n, 1);

    while !dec.is_one() {
        // Check correctness invariant
        debug_assert_eq!(num, factors.product() * dec.product());

        let (f, e) = dec.pop().unwrap();

        if let Some(d) = find_factor(f) {
            let mut gcd_queue = Decomposition::one();
            gcd_queue.add(d, e);
            gcd_queue.add(f / d, e);

            let mut non_trivial_gcd = true;
            while non_trivial_gcd {
                debug_assert_eq!(f, gcd_queue.product());

                let mut tmp = Decomposition::one();
                non_trivial_gcd = false;
                for i in 0..gcd_queue.0.len() - 1 {
                    let (mut a, e_a) = gcd_queue.0[i];
                    let (mut b, e_b) = gcd_queue.0[i + 1];

                    if a == 1 {
                        continue;
                    }

                    let g = gcd(a, b);
                    if g != 1 {
                        non_trivial_gcd = true;
                        a /= g;
                        b /= g;
                    }
                    if a != 1 {
                        tmp.add(a, e_a);
                    }
                    if g != 1 {
                        tmp.add(g, e_a + e_b);
                    }

                    if i + 1 != gcd_queue.0.len() - 1 {
                        gcd_queue.0[i + 1].0 = b;
                    } else if b != 1 {
                        tmp.add(b, e_b);
                    }
                }
                gcd_queue = tmp;
            }

            debug_assert_eq!(f, gcd_queue.product());
            dec.0.extend(gcd_queue.0);
        } else {
            // f is prime
            factors.add(f, e);
        }
    }

    factors
}

#[cfg(test)]
mod tests {
    use super::{factor, Factors};
    use quickcheck::quickcheck;

    #[test]
    fn factor_recombines_small() {
        assert!((1..10_000)
            .map(|i| 2 * i + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_overflowing() {
        assert!((0..250)
            .map(|i| 2 * i + 2u64.pow(32) + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_strong_pseudoprime() {
        // This is a strong pseudoprime (wrt. miller_rabin::BASIS)
        //  and triggered a bug in rho::factor's codepath handling
        //  miller_rabbin::Result::Composite
        let pseudoprime = 17179869183;
        for _ in 0..20 {
            // Repeat the test 20 times, as it only fails some fraction
            // of the time.
            assert!(factor(pseudoprime).product() == pseudoprime);
        }
    }

    quickcheck! {
        fn factor_recombines(i: u64) -> bool {
            i == 0 || factor(i).product() == i
        }

        fn recombines_factors(f: Factors) -> bool {
            assert_eq!(factor(f.product()), f);
            true
        }
    }
}

#[cfg(test)]
impl quickcheck::Arbitrary for Factors {
    fn arbitrary<G: quickcheck::Gen>(gen: &mut G) -> Self {
        use rand::Rng;
        let mut f = Factors::one();
        let mut g = 1u64;
        let mut n = u64::MAX;

        // Adam Kalai's algorithm for generating uniformly-distributed
        // integers and their factorisation.
        //
        // See Generating Random Factored Numbers, Easily, J. Cryptology (2003)
        'attempt: loop {
            while n > 1 {
                n = gen.gen_range(1, n);
                if miller_rabin::is_prime(n) {
                    if let Some(h) = g.checked_mul(n) {
                        f.push(n);
                        g = h;
                    } else {
                        // We are overflowing u64, retry
                        continue 'attempt;
                    }
                }
            }

            return f;
        }
    }
}
<commit_msg>factor/refactor ~ fix `cargo clippy` complaints (allow many_single_char_names)<commit_after>// * This file is part of the uutils coreutils package.
// *
// * (c) 2020 nicoo <nicoo@debian.org>
// *
// * For the full copyright and license information, please view the LICENSE file
// * that was distributed with this source code.

extern crate rand;

use smallvec::SmallVec;
use std::cell::RefCell;
use std::fmt;

use crate::numeric::{gcd, Arithmetic, Montgomery};
use crate::{miller_rabin, rho, table};

type Exponent = u8;

#[derive(Clone, Debug)]
struct Decomposition(SmallVec<[(u64, Exponent); NUM_FACTORS_INLINE]>);

// The number of factors to inline directly into a `Decomposition` object.
// As a consequence of the Erdős–Kac theorem, the average number of prime
//  factors of integers < 10²⁵ ≃ 2⁸³ is 4, so we can use that value.
const NUM_FACTORS_INLINE: usize = 4;

impl Decomposition {
    fn one() -> Decomposition {
        Decomposition(SmallVec::new())
    }

    fn add(&mut self, factor: u64, exp: Exponent) {
        debug_assert!(exp > 0);
        // Assert the factor doesn't already exist in the Decomposition object
        debug_assert_eq!(self.0.iter_mut().find(|(f, _)| *f == factor), None);

        self.0.push((factor, exp))
    }

    fn is_one(&self) -> bool {
        self.0.is_empty()
    }

    fn pop(&mut self) -> Option<(u64, Exponent)> {
        self.0.pop()
    }

    fn product(&self) -> u64 {
        self.0
            .iter()
            .fold(1, |acc, (p, exp)| acc * p.pow(*exp as u32))
    }

    fn get(&self, p: u64) -> Option<&(u64, u8)> {
        self.0.iter().find(|(q, _)| *q == p)
    }
}

impl PartialEq for Decomposition {
    fn eq(&self, other: &Decomposition) -> bool {
        for p in &self.0 {
            if other.get(p.0) != Some(p) {
                return false;
            }
        }

        for p in &other.0 {
            if self.get(p.0) != Some(p) {
                return false;
            }
        }

        true
    }
}
impl Eq for Decomposition {}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Factors(RefCell<Decomposition>);

impl Factors {
    pub fn one() -> Factors {
        Factors(RefCell::new(Decomposition::one()))
    }

    pub fn add(&mut self, prime: u64, exp: Exponent) {
        debug_assert!(miller_rabin::is_prime(prime));
        self.0.borrow_mut().add(prime, exp)
    }

    #[cfg(test)]
    pub fn push(&mut self, prime: u64) {
        self.add(prime, 1)
    }

    fn product(&self) -> u64 {
        self.0.borrow().product()
    }
}

impl fmt::Display for Factors {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let v = &mut (self.0).borrow_mut().0;
        v.sort_unstable();

        for (p, exp) in v.iter() {
            for _ in 0..*exp {
                write!(f, " {}", p)?
            }
        }

        Ok(())
    }
}

fn _find_factor<A: Arithmetic + miller_rabin::Basis>(num: u64) -> Option<u64> {
    use miller_rabin::Result::*;

    let n = A::new(num);
    match miller_rabin::test::<A>(n) {
        Prime => None,
        Composite(d) => Some(d),
        Pseudoprime => Some(rho::find_divisor::<A>(n)),
    }
}

fn find_factor(num: u64) -> Option<u64> {
    if num < (1 << 32) {
        _find_factor::<Montgomery<u32>>(num)
    } else {
        _find_factor::<Montgomery<u64>>(num)
    }
}

pub fn factor(num: u64) -> Factors {
    let mut factors = Factors::one();

    if num < 2 {
        return factors;
    }

    let mut n = num;
    let n_zeros = num.trailing_zeros();
    if n_zeros > 0 {
        factors.add(2, n_zeros as Exponent);
        n >>= n_zeros;
    }
    debug_assert_eq!(num, n * factors.product());

    if n == 1 {
        return factors;
    }

    table::factor(&mut n, &mut factors);
    debug_assert_eq!(num, n * factors.product());

    if n == 1 {
        return factors;
    }

    let mut dec = Decomposition::one();
    dec.add(n, 1);

    while !dec.is_one() {
        // Check correctness invariant
        debug_assert_eq!(num, factors.product() * dec.product());

        let (factor, exp) = dec.pop().unwrap();

        if let Some(divisor) = find_factor(factor) {
            let mut gcd_queue = Decomposition::one();
            gcd_queue.add(divisor, exp);
            gcd_queue.add(factor / divisor, exp);

            let mut non_trivial_gcd = true;
            while non_trivial_gcd {
                debug_assert_eq!(factor, gcd_queue.product());

                let mut tmp = Decomposition::one();
                non_trivial_gcd = false;
                for i in 0..gcd_queue.0.len() - 1 {
                    let (mut a, exp_a) = gcd_queue.0[i];
                    let (mut b, exp_b) = gcd_queue.0[i + 1];

                    if a == 1 {
                        continue;
                    }

                    let g = gcd(a, b);
                    if g != 1 {
                        non_trivial_gcd = true;
                        a /= g;
                        b /= g;
                    }
                    if a != 1 {
                        tmp.add(a, exp_a);
                    }
                    if g != 1 {
                        tmp.add(g, exp_a + exp_b);
                    }

                    if i + 1 != gcd_queue.0.len() - 1 {
                        gcd_queue.0[i + 1].0 = b;
                    } else if b != 1 {
                        tmp.add(b, exp_b);
                    }
                }
                gcd_queue = tmp;
            }

            debug_assert_eq!(factor, gcd_queue.product());
            dec.0.extend(gcd_queue.0);
        } else {
            // factor is prime
            factors.add(factor, exp);
        }
    }

    factors
}

#[cfg(test)]
mod tests {
    use super::{factor, Factors};
    use quickcheck::quickcheck;

    #[test]
    fn factor_recombines_small() {
        assert!((1..10_000)
            .map(|i| 2 * i + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_overflowing() {
        assert!((0..250)
            .map(|i| 2 * i + 2u64.pow(32) + 1)
            .all(|i| factor(i).product() == i));
    }

    #[test]
    fn factor_recombines_strong_pseudoprime() {
        // This is a strong pseudoprime (wrt. miller_rabin::BASIS)
        //  and triggered a bug in rho::factor's codepath handling
        //  miller_rabbin::Result::Composite
        let pseudoprime = 17179869183;
        for _ in 0..20 {
            // Repeat the test 20 times, as it only fails some fraction
            // of the time.
            assert!(factor(pseudoprime).product() == pseudoprime);
        }
    }

    quickcheck! {
        fn factor_recombines(i: u64) -> bool {
            i == 0 || factor(i).product() == i
        }

        fn recombines_factors(f: Factors) -> bool {
            assert_eq!(factor(f.product()), f);
            true
        }
    }
}

#[cfg(test)]
impl quickcheck::Arbitrary for Factors {
    fn arbitrary<G: quickcheck::Gen>(gen: &mut G) -> Self {
        use rand::Rng;
        let mut f = Factors::one();
        let mut g = 1u64;
        let mut n = u64::MAX;

        // Adam Kalai's algorithm for generating uniformly-distributed
        // integers and their factorisation.
        //
        // See Generating Random Factored Numbers, Easily, J. Cryptology (2003)
        'attempt: loop {
            while n > 1 {
                n = gen.gen_range(1, n);
                if miller_rabin::is_prime(n) {
                    if let Some(h) = g.checked_mul(n) {
                        f.push(n);
                        g = h;
                    } else {
                        // We are overflowing u64, retry
                        continue 'attempt;
                    }
                }
            }

            return f;
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
// spell-checker:ignore (change!) each's
// spell-checker:ignore (ToDO) LONGHELP FORMATSTRING templating parameterizing formatstr

use clap::{crate_version, App, Arg};
use uucore::InvalidEncodingHandling;

mod cli;
mod memo;
mod tokenize;

const VERSION: &str = "version";
const HELP: &str = "help";
static LONGHELP_LEAD: &str = "printf

 USAGE: printf FORMATSTRING [ARGUMENT]...

 basic anonymous string templating:

 prints format string at least once, repeating as long as there are remaining arguments
 output prints escaped literals in the format string as character literals
 output replaces anonymous fields with the next unused argument, formatted according to the field.

Options:
    --help              display this help and exit
    --version           output version information and exit

";
static LONGHELP_BODY: &str = "
  Prints the , replacing escaped character sequences with character literals
    and substitution field sequences with passed arguments

 literally, with the exception of the below
    escaped character sequences, and the substitution sequences described further down.

  ESCAPE SEQUENCES

  The following escape sequences, organized here in alphabetical order,
  will print the corresponding character literal:

  \"   double quote

  \\\\    backslash

  \\a  alert (BEL)

  \\b  backspace

  \\c  End-of-Input

  \\e  escape

  \\f  form feed

  \\n  new line

  \\r  carriage return

  \\t  horizontal tab

  \\v  vertical tab

  \\NNN byte with value expressed in octal value NNN (1 to 3 digits)
        values greater than 256 will be treated

  \\xHH byte with value expressed in hexadecimal value NN (1 to 2 digits)

  \\uHHHH Unicode (IEC 10646) character with value expressed in hexadecimal value HHHH (4 digits)

  \\uHHHH Unicode character with value expressed in hexadecimal value HHHH (8 digits)

  %% a single %

  SUBSTITUTIONS

  SUBSTITUTION QUICK REFERENCE

  Fields

  %s - string
  %b - string parsed for literals
    second parameter is max length

  %c - char
    no second parameter

  %i or %d - 64-bit integer
  %u - 64 bit unsigned integer
  %x or %X - 64-bit unsigned integer as hex
  %o - 64-bit unsigned integer as octal
    second parameter is min-width, integer
     output below that width is padded with leading zeroes

  %f or %F - decimal floating point value
  %e or %E - scientific notation floating point value
  %g or %G - shorter of specially interpreted decimal or SciNote floating point value.
    second parameter is
      -max places after decimal point for floating point output
      -max number of significant digits for scientific notation output

  parameterizing fields

  examples:

  printf '%4.3i' 7
  has a first parameter of 4
     and a second parameter of 3
  will result in ' 007'

  printf '%.1s' abcde
  has no first parameter
     and a second parameter of 1
  will result in 'a'

  printf '%4c' q
  has a first parameter of 4
     and no second parameter
  will result in  '   q'

  The first parameter of a field is the minimum width to pad the output to
   if the output is less than this absolute value of this width,
   it will be padded with leading spaces, or, if the argument is negative,
   with trailing spaces. the default is zero.

  The second parameter of a field is particular to the output field type.
   defaults can be found in the full substitution help below

  special prefixes to numeric arguments
    0 (e.g. 010) - interpret argument as octal (integer output fields only)
    0x (e.g. 0xABC) - interpret argument as hex (numeric output fields only)
    \' (e.g. \'a) - interpret argument as a character constant

  HOW TO USE SUBSTITUTIONS

  Substitutions are used to pass additional argument(s) into the FORMAT string, to be formatted a
  particular way. E.g.

      printf 'the letter %X comes before the letter %X' 10 11

  will print

     'the letter A comes before the letter B'

  because the substitution field %X means
  'take an integer argument and write it as a hexadecimal number'

  Passing more arguments than are in the format string will cause the format string to be
   repeated for the remaining substitutions

     printf 'it is %i F in %s \n' 22 Portland 25 Boston 27 New York

  will print

     'it is 22 F in Portland
      it is 25 F in Boston
      it is 27 F in Boston
     '
  If a format string is printed but there are less arguments remaining
   than there are substitution fields, substitution fields without
   an argument will default to empty strings, or for numeric fields
   the value 0

  AVAILABLE SUBSTITUTIONS

  This program, like GNU coreutils printf,
  interprets a modified subset of the POSIX C printf spec,
  a quick reference to substitutions is below.

   STRING SUBSTITUTIONS
    All string fields have a 'max width' parameter
    %.3s means 'print no more than three characters of the original input'

   %s - string

   %b - escaped string - the string will be checked for any escaped literals from
         the escaped literal list above, and translate them to literal characters.
         e.g. \\n will be transformed into a newline character.

        One special rule about %b mode is that octal literals are interpreted differently
        In arguments passed by %b, pass octal-interpreted literals must be in the form of \\0NNN
        instead of \\NNN. (Although, for legacy reasons, octal literals in the form of \\NNN will
        still be interpreted and not throw a warning, you will have problems if you use this for a
        literal whose code begins with zero, as it will be viewed as in \\0NNN form.)

   CHAR SUBSTITUTIONS
    The character field does not have a secondary parameter.

   %c - a single character

   INTEGER SUBSTITUTIONS
    All integer fields have a 'pad with zero' parameter
    %.4i means an integer which if it is less than 4 digits in length,
    is padded with leading zeros until it is 4 digits in length.

   %d or %i - 64-bit integer

   %u - 64 bit unsigned integer

   %x or %X - 64 bit unsigned integer printed in Hexadecimal (base 16)
            %X instead of %x means to use uppercase letters for 'a' through 'f'

   %o - 64 bit unsigned integer printed in octal (base 8)

   FLOATING POINT SUBSTITUTIONS

    All floating point fields have a 'max decimal places / max significant digits' parameter
    %.10f means a decimal floating point with 7 decimal places past 0
    %.10e means a scientific notation number with 10 significant digits
    %.10g means the same behavior for decimal and Sci. Note, respectively, and provides the shorter
          of each's output.

    Like with GNU coreutils, the value after the decimal point is these outputs is parsed as a
    double first before being rendered to text. For both implementations do not expect meaningful
    precision past the 18th decimal place. When using a number of decimal places that is 18 or
    higher, you can expect variation in output between GNU coreutils printf and this printf at the
    18th decimal place of +/- 1

   %f - floating point value presented in decimal, truncated and displayed to 6 decimal places by
        default. There is not past-double behavior parity with Coreutils printf, values are not
        estimated or adjusted beyond input values.

   %e or %E - floating point value presented in scientific notation
            7 significant digits by default
            %E means use to use uppercase E for the mantissa.

   %g or %G - floating point value presented in the shorter of decimal and scientific notation
            behaves differently from %f and %E, please see posix printf spec for full details,
            some examples of different behavior:

            Sci Note has 6 significant digits by default
            Trailing zeroes are removed
            Instead of being truncated, digit after last is rounded

   Like other behavior in this utility, the design choices of floating point
    behavior in this utility is selected to reproduce in exact
    the behavior of GNU coreutils' printf from an inputs and outputs standpoint.

  USING PARAMETERS
   Most substitution fields can be parameterized using up to 2 numbers that can
   be passed to the field, between the % sign and the field letter.

   The 1st parameter always indicates the minimum width of output, it is useful for creating
     columnar output. Any output that would be less than this minimum width is padded with
     leading spaces
   The 2nd parameter is proceeded by a dot.
   You do not have to use parameters

  SPECIAL FORMS OF INPUT
   For numeric input, the following additional forms of input are accepted besides decimal:

    Octal (only with integer): if the argument begins with a 0 the proceeding characters
      will be interpreted as octal (base 8) for integer fields

    Hexadecimal: if the argument begins with 0x the proceeding characters will be interpreted
      will be interpreted as hex (base 16) for any numeric fields
      for float fields, hexadecimal input results in a precision
      limit (in converting input past the decimal point) of 10^-15

    Character Constant: if the argument begins with a single quote character, the first byte
      of the next character will be interpreted as an 8-bit unsigned integer. If there are
      additional bytes, they will throw an error (unless the environment variable POSIXLY_CORRECT
      is set)

WRITTEN BY :
  Nathan E. Ross, et al. for the uutils project

MORE INFO :
  https://github.com/uutils/coreutils

COPYRIGHT :
  Copyright 2015 uutils project.
  Licensed under the MIT License, please see LICENSE file for details

";

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args
        .collect_str(InvalidEncodingHandling::Ignore)
        .accept_any();

    if args.len() <= 1 {
        println!(
            "{0}: missing operand\nTry '{1} --help' for more information.",
            uucore::util_name(),
            uucore::execution_phrase()
        );
        return 1;
    }
    let formatstr = &args[1];

    if formatstr == "--help" {
        print!("{} {}", LONGHELP_LEAD, LONGHELP_BODY);
    } else if formatstr == "--version" {
        println!("{} {}", uucore::util_name(), crate_version!());
    } else {
        let printf_args = &args[2..];
        memo::Memo::run_all(formatstr, printf_args);
    }
    0
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(uucore::util_name())
        .arg(Arg::with_name(VERSION).long(VERSION))
        .arg(Arg::with_name(HELP).long(HELP))
}
<commit_msg>printf: return UResult from uumain() function<commit_after>#![allow(dead_code)]
// spell-checker:ignore (change!) each's
// spell-checker:ignore (ToDO) LONGHELP FORMATSTRING templating parameterizing formatstr

use clap::{crate_version, App, Arg};
use uucore::error::{UResult, UUsageError};
use uucore::InvalidEncodingHandling;

mod cli;
mod memo;
mod tokenize;

const VERSION: &str = "version";
const HELP: &str = "help";
static LONGHELP_LEAD: &str = "printf

 USAGE: printf FORMATSTRING [ARGUMENT]...

 basic anonymous string templating:

 prints format string at least once, repeating as long as there are remaining arguments
 output prints escaped literals in the format string as character literals
 output replaces anonymous fields with the next unused argument, formatted according to the field.

Options:
    --help              display this help and exit
    --version           output version information and exit

";
static LONGHELP_BODY: &str = "
  Prints the , replacing escaped character sequences with character literals
    and substitution field sequences with passed arguments

 literally, with the exception of the below
    escaped character sequences, and the substitution sequences described further down.

  ESCAPE SEQUENCES

  The following escape sequences, organized here in alphabetical order,
  will print the corresponding character literal:

  \"   double quote

  \\\\    backslash

  \\a  alert (BEL)

  \\b  backspace

  \\c  End-of-Input

  \\e  escape

  \\f  form feed

  \\n  new line

  \\r  carriage return

  \\t  horizontal tab

  \\v  vertical tab

  \\NNN byte with value expressed in octal value NNN (1 to 3 digits)
        values greater than 256 will be treated

  \\xHH byte with value expressed in hexadecimal value NN (1 to 2 digits)

  \\uHHHH Unicode (IEC 10646) character with value expressed in hexadecimal value HHHH (4 digits)

  \\uHHHH Unicode character with value expressed in hexadecimal value HHHH (8 digits)

  %% a single %

  SUBSTITUTIONS

  SUBSTITUTION QUICK REFERENCE

  Fields

  %s - string
  %b - string parsed for literals
    second parameter is max length

  %c - char
    no second parameter

  %i or %d - 64-bit integer
  %u - 64 bit unsigned integer
  %x or %X - 64-bit unsigned integer as hex
  %o - 64-bit unsigned integer as octal
    second parameter is min-width, integer
     output below that width is padded with leading zeroes

  %f or %F - decimal floating point value
  %e or %E - scientific notation floating point value
  %g or %G - shorter of specially interpreted decimal or SciNote floating point value.
    second parameter is
      -max places after decimal point for floating point output
      -max number of significant digits for scientific notation output

  parameterizing fields

  examples:

  printf '%4.3i' 7
  has a first parameter of 4
     and a second parameter of 3
  will result in ' 007'

  printf '%.1s' abcde
  has no first parameter
     and a second parameter of 1
  will result in 'a'

  printf '%4c' q
  has a first parameter of 4
     and no second parameter
  will result in  '   q'

  The first parameter of a field is the minimum width to pad the output to
   if the output is less than this absolute value of this width,
   it will be padded with leading spaces, or, if the argument is negative,
   with trailing spaces. the default is zero.

  The second parameter of a field is particular to the output field type.
   defaults can be found in the full substitution help below

  special prefixes to numeric arguments
    0 (e.g. 010) - interpret argument as octal (integer output fields only)
    0x (e.g. 0xABC) - interpret argument as hex (numeric output fields only)
    \' (e.g. \'a) - interpret argument as a character constant

  HOW TO USE SUBSTITUTIONS

  Substitutions are used to pass additional argument(s) into the FORMAT string, to be formatted a
  particular way. E.g.

      printf 'the letter %X comes before the letter %X' 10 11

  will print

     'the letter A comes before the letter B'

  because the substitution field %X means
  'take an integer argument and write it as a hexadecimal number'

  Passing more arguments than are in the format string will cause the format string to be
   repeated for the remaining substitutions

     printf 'it is %i F in %s \n' 22 Portland 25 Boston 27 New York

  will print

     'it is 22 F in Portland
      it is 25 F in Boston
      it is 27 F in Boston
     '
  If a format string is printed but there are less arguments remaining
   than there are substitution fields, substitution fields without
   an argument will default to empty strings, or for numeric fields
   the value 0

  AVAILABLE SUBSTITUTIONS

  This program, like GNU coreutils printf,
  interprets a modified subset of the POSIX C printf spec,
  a quick reference to substitutions is below.

   STRING SUBSTITUTIONS
    All string fields have a 'max width' parameter
    %.3s means 'print no more than three characters of the original input'

   %s - string

   %b - escaped string - the string will be checked for any escaped literals from
         the escaped literal list above, and translate them to literal characters.
         e.g. \\n will be transformed into a newline character.

        One special rule about %b mode is that octal literals are interpreted differently
        In arguments passed by %b, pass octal-interpreted literals must be in the form of \\0NNN
        instead of \\NNN. (Although, for legacy reasons, octal literals in the form of \\NNN will
        still be interpreted and not throw a warning, you will have problems if you use this for a
        literal whose code begins with zero, as it will be viewed as in \\0NNN form.)

   CHAR SUBSTITUTIONS
    The character field does not have a secondary parameter.

   %c - a single character

   INTEGER SUBSTITUTIONS
    All integer fields have a 'pad with zero' parameter
    %.4i means an integer which if it is less than 4 digits in length,
    is padded with leading zeros until it is 4 digits in length.

   %d or %i - 64-bit integer

   %u - 64 bit unsigned integer

   %x or %X - 64 bit unsigned integer printed in Hexadecimal (base 16)
            %X instead of %x means to use uppercase letters for 'a' through 'f'

   %o - 64 bit unsigned integer printed in octal (base 8)

   FLOATING POINT SUBSTITUTIONS

    All floating point fields have a 'max decimal places / max significant digits' parameter
    %.10f means a decimal floating point with 7 decimal places past 0
    %.10e means a scientific notation number with 10 significant digits
    %.10g means the same behavior for decimal and Sci. Note, respectively, and provides the shorter
          of each's output.

    Like with GNU coreutils, the value after the decimal point is these outputs is parsed as a
    double first before being rendered to text. For both implementations do not expect meaningful
    precision past the 18th decimal place. When using a number of decimal places that is 18 or
    higher, you can expect variation in output between GNU coreutils printf and this printf at the
    18th decimal place of +/- 1

   %f - floating point value presented in decimal, truncated and displayed to 6 decimal places by
        default. There is not past-double behavior parity with Coreutils printf, values are not
        estimated or adjusted beyond input values.

   %e or %E - floating point value presented in scientific notation
            7 significant digits by default
            %E means use to use uppercase E for the mantissa.

   %g or %G - floating point value presented in the shorter of decimal and scientific notation
            behaves differently from %f and %E, please see posix printf spec for full details,
            some examples of different behavior:

            Sci Note has 6 significant digits by default
            Trailing zeroes are removed
            Instead of being truncated, digit after last is rounded

   Like other behavior in this utility, the design choices of floating point
    behavior in this utility is selected to reproduce in exact
    the behavior of GNU coreutils' printf from an inputs and outputs standpoint.

  USING PARAMETERS
   Most substitution fields can be parameterized using up to 2 numbers that can
   be passed to the field, between the % sign and the field letter.

   The 1st parameter always indicates the minimum width of output, it is useful for creating
     columnar output. Any output that would be less than this minimum width is padded with
     leading spaces
   The 2nd parameter is proceeded by a dot.
   You do not have to use parameters

  SPECIAL FORMS OF INPUT
   For numeric input, the following additional forms of input are accepted besides decimal:

    Octal (only with integer): if the argument begins with a 0 the proceeding characters
      will be interpreted as octal (base 8) for integer fields

    Hexadecimal: if the argument begins with 0x the proceeding characters will be interpreted
      will be interpreted as hex (base 16) for any numeric fields
      for float fields, hexadecimal input results in a precision
      limit (in converting input past the decimal point) of 10^-15

    Character Constant: if the argument begins with a single quote character, the first byte
      of the next character will be interpreted as an 8-bit unsigned integer. If there are
      additional bytes, they will throw an error (unless the environment variable POSIXLY_CORRECT
      is set)

WRITTEN BY :
  Nathan E. Ross, et al. for the uutils project

MORE INFO :
  https://github.com/uutils/coreutils

COPYRIGHT :
  Copyright 2015 uutils project.
  Licensed under the MIT License, please see LICENSE file for details

";

#[uucore_procs::gen_uumain]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let args = args
        .collect_str(InvalidEncodingHandling::Ignore)
        .accept_any();

    if args.len() <= 1 {
        return Err(UUsageError::new(1, "missing operand"));
    }
    let formatstr = &args[1];

    if formatstr == "--help" {
        print!("{} {}", LONGHELP_LEAD, LONGHELP_BODY);
    } else if formatstr == "--version" {
        println!("{} {}", uucore::util_name(), crate_version!());
    } else {
        let printf_args = &args[2..];
        memo::Memo::run_all(formatstr, printf_args);
    }
    Ok(())
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(uucore::util_name())
        .arg(Arg::with_name(VERSION).long(VERSION))
        .arg(Arg::with_name(HELP).long(HELP))
}
<|endoftext|>


<commit_before>use chrono::*;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use std::fmt;
use timeclock::direction::Direction;

static DATETIMEFMT: &'static str = "%Y-%m-%dT%H:%M:%S%z";

fn fmt_datetime(time: DateTime<FixedOffset>) -> String {
    let dr = time.format(DATETIMEFMT);
    format!("{}", dr)
}

fn parse_datetime(s: &str) -> ParseResult<DateTime<FixedOffset>> {
    DateTime::parse_from_str(s, DATETIMEFMT)
}

#[derive(Clone,Debug,PartialEq)]
pub struct TimeEntry {
    pub dir: Direction,
    pub time: DateTime<FixedOffset>,
    pub memo: String,
}

impl TimeEntry {
    pub fn new(dir: Direction,
               time: DateTime<FixedOffset>,
               memo: &str)
               -> Self {
        TimeEntry {
            dir: dir,
            time: time,
            memo: memo.to_owned(),
        }
    }
}

impl Encodable for TimeEntry {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_struct("TimeEntry", 3, |s| {
            try!(s.emit_struct_field("dir", 0, |s| self.dir.encode(s)));
            try!(s.emit_struct_field("time", 1, |s| {
                return s.emit_str(fmt_datetime(self.time).as_ref());
            }));
            try!(s.emit_struct_field("memo", 2, |s| self.memo.encode(s)));
            Ok(())
        })
    }
}

impl Decodable for TimeEntry {
    fn decode<D: Decoder>(d: &mut D) -> Result<TimeEntry, D::Error> {
        d.read_struct("TimeEntry", 0, |d| {
            Ok(TimeEntry {
                dir: try!(d.read_struct_field("dir", 0, |d|
                        Decodable::decode(d))),
                time: {
                    let a_str: String = try!(d.read_struct_field("time", 0,
                            |d| d.read_str()));
                    let es = format!("Can't parse {}", a_str);
                    let dt = parse_datetime(&a_str);
                    match dt {
                        Ok(d) => d,
                        Err(_) => return Err(d.error(&es)),
                    }
                },
                memo: try!(d.read_struct_field("memo", 0, |d|
                        Decodable::decode(d))),
            })
        })
    }
}

impl fmt::Display for TimeEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let time = self.time.format("%F %I:%M %P");
        f.write_fmt(format_args!("{:3} {} {}", self.dir, time, self.memo))
    }
}

#[derive(Debug,PartialEq)]
pub struct TimeEntryPair {
    start: TimeEntry,
    end: TimeEntry,
}

impl TimeEntryPair {
    pub fn new(s: TimeEntry, e: TimeEntry) -> Self {
        TimeEntryPair { start: s, end: e }
    }

    pub fn start(&self) -> &TimeEntry {
        &self.start
    }

    pub fn end(&self) -> &TimeEntry {
        &self.end
    }
}

#[cfg(test)]
mod tests {
    use csv;
    use std::io::Cursor;
    use super::*;
    use timeclock::direction::Direction;
    use timeclock::now;
    use timeclock::timeentry::{fmt_datetime, parse_datetime};

    #[test]
    fn timeentry_constructor_test() {
        let time = now();
        let te = TimeEntry::new(Direction::In, time, "Memo");
        assert_eq!(te.dir, Direction::In);
        assert_eq!(te.time, time);
        assert_eq!(te.memo, "Memo");
    }

    #[test]
    fn encode_timeentry_test() {
        let mut wtr = csv::Writer::from_memory();
        let timenow = now();
        let expected = format!("In,{},test memo\n", fmt_datetime(timenow));
        let _ = wtr.encode(TimeEntry {
            dir: Direction::In,
            time: timenow,
            memo: "test memo".to_owned(),
        });
        assert!(wtr.as_string() == expected);
    }

    #[test]
    fn decode_timeentry_test() {
        let timestr = "2017-01-05T14:04:16-0600";
        let expected_time = parse_datetime(timestr).unwrap();
        let memo = "test memo";
        let s = format!("In,{0:},{1:}\nOut,{0:},{1:}\n", timestr, memo);
        let vs = s.as_bytes();
        let buff = Cursor::new(vs);
        let mut rdr = csv::Reader::from_reader(buff).has_headers(false);
        let records =
            rdr.decode().collect::<csv::Result<Vec<TimeEntry>>>().unwrap();

        assert!(records[0].dir == Direction::In);
        assert!(records[1].dir == Direction::Out);
        assert!(records[0].time == expected_time);
        assert!(records[1].time == expected_time);
        assert!(records[0].memo == memo);
        assert!(records[1].memo == memo);
        assert!(records.len() == 2);
    }
}<commit_msg>Complete test coverage in timeentry<commit_after>use chrono::*;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use std::fmt;
use timeclock::direction::Direction;

static DATETIMEFMT: &'static str = "%Y-%m-%dT%H:%M:%S%z";

fn fmt_datetime(time: DateTime<FixedOffset>) -> String {
    let dr = time.format(DATETIMEFMT);
    format!("{}", dr)
}

fn parse_datetime(s: &str) -> ParseResult<DateTime<FixedOffset>> {
    DateTime::parse_from_str(s, DATETIMEFMT)
}

#[derive(Clone,Debug,PartialEq)]
pub struct TimeEntry {
    pub dir: Direction,
    pub time: DateTime<FixedOffset>,
    pub memo: String,
}

impl TimeEntry {
    pub fn new(dir: Direction,
               time: DateTime<FixedOffset>,
               memo: &str)
               -> Self {
        TimeEntry {
            dir: dir,
            time: time,
            memo: memo.to_owned(),
        }
    }
}

impl Encodable for TimeEntry {
    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
        s.emit_struct("TimeEntry", 3, |s| {
            try!(s.emit_struct_field("dir", 0, |s| self.dir.encode(s)));
            try!(s.emit_struct_field("time", 1, |s| {
                return s.emit_str(fmt_datetime(self.time).as_ref());
            }));
            try!(s.emit_struct_field("memo", 2, |s| self.memo.encode(s)));
            Ok(())
        })
    }
}

impl Decodable for TimeEntry {
    fn decode<D: Decoder>(d: &mut D) -> Result<TimeEntry, D::Error> {
        d.read_struct("TimeEntry", 0, |d| {
            Ok(TimeEntry {
                dir: try!(d.read_struct_field("dir", 0, |d|
                        Decodable::decode(d))),
                time: {
                    let a_str: String = try!(d.read_struct_field("time", 0,
                            |d| d.read_str()));
                    let dt = parse_datetime(&a_str);
                    match dt {
                        Ok(d) => d,
                        Err(e) => return Err(d.error(&format!("{}", e))),
                    }
                },
                memo: try!(d.read_struct_field("memo", 0, |d|
                        Decodable::decode(d))),
            })
        })
    }
}

impl fmt::Display for TimeEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let time = self.time.format("%F %I:%M %P");
        f.write_fmt(format_args!("{:3} {} {}", self.dir, time, self.memo))
    }
}

#[derive(Debug,PartialEq)]
pub struct TimeEntryPair {
    start: TimeEntry,
    end: TimeEntry,
}

impl TimeEntryPair {
    pub fn new(s: TimeEntry, e: TimeEntry) -> Self {
        TimeEntryPair { start: s, end: e }
    }

    pub fn start(&self) -> &TimeEntry {
        &self.start
    }

    pub fn end(&self) -> &TimeEntry {
        &self.end
    }
}

#[cfg(test)]
mod tests {
    use chrono::*;
    use csv;
    use std::io::Cursor;
    use super::*;
    use timeclock::Direction;

    fn time_helper() -> DateTime<FixedOffset> {
        DateTime::parse_from_rfc3339("2017-01-05T14:04:16-06:00").unwrap()
    }

    #[test]
    fn timeentry_encode_test() {
        let mut wtr = csv::Writer::from_memory();
        let time = DateTime::parse_from_rfc3339("2017-01-05T14:04:16-06:00")
            .unwrap();
        let _ = wtr.encode(TimeEntry::new(Direction::In, time, "Test"));
        assert_eq!(wtr.as_string(), "In,2017-01-05T14:04:16-0600,Test\n");
    }

    #[test]
    fn timeentry_decode_test() {
        let time = DateTime::parse_from_rfc3339("2017-01-05T14:04:16-06:00")
            .unwrap();
        let s = format!("In,2017-01-05T14:04:16-0600,Test\n");
        let buff = Cursor::new(s.as_bytes());
        let mut rdr = csv::Reader::from_reader(buff).has_headers(false);
        let records =
            rdr.decode().collect::<csv::Result<Vec<TimeEntry>>>().unwrap();

        assert_eq!(records[0].dir, Direction::In);
        assert_eq!(records[0].time, time);
        assert_eq!(records[0].memo, "Test");
        assert_eq!(records.len(), 1);
    }

    #[test]
    fn timeentry_decode_bad_date_test() {
        let s = format!("In,sfggfh,Test\n");
        let buff = Cursor::new(s.as_bytes());
        let mut rdr = csv::Reader::from_reader(buff).has_headers(false);
        let records = rdr.decode().collect::<csv::Result<Vec<TimeEntry>>>();

        assert!(records.is_err());
    }

    #[test]
    fn timeentry_print_test() {
        let time = DateTime::parse_from_rfc3339("2017-01-05T14:04:16-06:00")
            .unwrap();
        let te = TimeEntry::new(Direction::In, time, "Test");
        let display = format!("{}", te);
        assert_eq!(display, "In  2017-01-05 02:04 pm Test");
        let debug = format!("{:?}", te);
        assert_eq!(debug,
                   "TimeEntry { dir: In, time: 2017-01-05T14:04:16-06:00, memo: \"Test\" }");
    }

    #[test]
    fn timeentrypair_test() {
        let time = time_helper();
        let te_a = TimeEntry::new(Direction::In, time, "Test");
        let te_b = TimeEntry::new(Direction::Out, time, "Test");
        let tep = TimeEntryPair::new(te_a.clone(), te_b.clone());
        assert_eq!(tep.start(), &te_a);
        assert_eq!(tep.end(), &te_b);
    }
}
<|endoftext|>


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

//! Tidy checks for source code in this repository
//!
//! This program runs all of the various tidy checks for style, cleanliness,
//! etc. This is run by default on `make check` and as part of the auto
//! builders.

extern crate regex;

use std::env;
use std::fs;
use std::io::{self, Write};
use std::path::{PathBuf, Path};
use std::process;

macro_rules! t {
    ($e:expr, $p:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed on {} with {}", stringify!($e), ($p).display(), e),
    });

    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

macro_rules! tidy_error {
    ($bad:expr, $fmt:expr, $($arg:tt)*) => ({
        use std::io::Write;
        *$bad = true;
        write!(::std::io::stderr(), "tidy error: ").expect("could not write to stderr");
        writeln!(::std::io::stderr(), $fmt, $($arg)*).expect("could not write to stderr");
    });
}

mod bins;
mod style;
mod errors;
mod features;
mod cargo;
mod pal;
mod deps;
mod unstable_book;

fn main() {
    let path = env::args_os().skip(1).next().expect("need an argument");
    let path = PathBuf::from(path);

    let args: Vec<String> = env::args().skip(1).collect();

    let mut bad = false;
    bins::check(&path, &mut bad);
    style::check(&path, &mut bad);
    errors::check(&path, &mut bad);
    cargo::check(&path, &mut bad);
    features::check(&path, &mut bad);
    pal::check(&path, &mut bad);
    unstable_book::check(&path, &mut bad);
    if !args.iter().any(|s| *s == "--no-vendor") {
        deps::check(&path, &mut bad);
    }

    if bad {
        writeln!(io::stderr(), "some tidy checks failed").expect("could not write to stderr");
        process::exit(1);
    }
}

fn filter_dirs(path: &Path) -> bool {
    let skip = [
        "src/jemalloc",
        "src/llvm",
        "src/libbacktrace",
        "src/compiler-rt",
        "src/rustllvm",
        "src/rust-installer",
        "src/liblibc",
        "src/vendor",
    ];
    skip.iter().any(|p| path.ends_with(p))
}

fn walk_many(paths: &[&Path], skip: &mut FnMut(&Path) -> bool, f: &mut FnMut(&Path)) {
    for path in paths {
        walk(path, skip, f);
    }
}

fn walk(path: &Path, skip: &mut FnMut(&Path) -> bool, f: &mut FnMut(&Path)) {
    for entry in t!(fs::read_dir(path), path) {
        let entry = t!(entry);
        let kind = t!(entry.file_type());
        let path = entry.path();
        if kind.is_dir() {
            if !skip(&path) {
                walk(&path, skip, f);
            }
        } else {
            f(&path);
        }
    }
}
<commit_msg>Remove hoedown from tidy check<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Tidy checks for source code in this repository
//!
//! This program runs all of the various tidy checks for style, cleanliness,
//! etc. This is run by default on `make check` and as part of the auto
//! builders.

extern crate regex;

use std::env;
use std::fs;
use std::io::{self, Write};
use std::path::{PathBuf, Path};
use std::process;

macro_rules! t {
    ($e:expr, $p:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed on {} with {}", stringify!($e), ($p).display(), e),
    });

    ($e:expr) => (match $e {
        Ok(e) => e,
        Err(e) => panic!("{} failed with {}", stringify!($e), e),
    })
}

macro_rules! tidy_error {
    ($bad:expr, $fmt:expr, $($arg:tt)*) => ({
        use std::io::Write;
        *$bad = true;
        write!(::std::io::stderr(), "tidy error: ").expect("could not write to stderr");
        writeln!(::std::io::stderr(), $fmt, $($arg)*).expect("could not write to stderr");
    });
}

mod bins;
mod style;
mod errors;
mod features;
mod cargo;
mod pal;
mod deps;
mod unstable_book;

fn main() {
    let path = env::args_os().skip(1).next().expect("need an argument");
    let path = PathBuf::from(path);

    let args: Vec<String> = env::args().skip(1).collect();

    let mut bad = false;
    bins::check(&path, &mut bad);
    style::check(&path, &mut bad);
    errors::check(&path, &mut bad);
    cargo::check(&path, &mut bad);
    features::check(&path, &mut bad);
    pal::check(&path, &mut bad);
    unstable_book::check(&path, &mut bad);
    if !args.iter().any(|s| *s == "--no-vendor") {
        deps::check(&path, &mut bad);
    }

    if bad {
        writeln!(io::stderr(), "some tidy checks failed").expect("could not write to stderr");
        process::exit(1);
    }
}

fn filter_dirs(path: &Path) -> bool {
    let skip = [
        "src/jemalloc",
        "src/llvm",
        "src/libbacktrace",
        "src/compiler-rt",
        "src/rustllvm",
        "src/rust-installer",
        "src/liblibc",
        "src/vendor",
        "src/rt/hoedown",
    ];
    skip.iter().any(|p| path.ends_with(p))
}

fn walk_many(paths: &[&Path], skip: &mut FnMut(&Path) -> bool, f: &mut FnMut(&Path)) {
    for path in paths {
        walk(path, skip, f);
    }
}

fn walk(path: &Path, skip: &mut FnMut(&Path) -> bool, f: &mut FnMut(&Path)) {
    for entry in t!(fs::read_dir(path), path) {
        let entry = t!(entry);
        let kind = t!(entry.file_type());
        let path = entry.path();
        if kind.is_dir() {
            if !skip(&path) {
                walk(&path, skip, f);
            }
        } else {
            f(&path);
        }
    }
}
<|endoftext|>