<commit_before>#[macro_use]
extern crate lazy_static;
extern crate regex;

use std::collections::{HashMap, HashSet};
use std::io::Read;
use std::fs::File;

use regex::Regex;

lazy_static! {
    static ref WORDS: HashMap<String, usize> = {
        let mut f = File::open("data/big.txt").unwrap();
        let mut s = String::new();
        f.read_to_string(&mut s).unwrap();

        // Count occurrences of words found in `big.txt`
        let mut words = HashMap::new();

        for word in Regex::new(r"\W+").unwrap().split(&s) {
            let count = words.entry(word.to_lowercase()).or_insert(0);
            *count += 1;
        }

        return words;
    };
}

/// Most probable spelling correction for `word`.
pub fn correction(word: &str) -> String {
    if word == "" {
        return String::from("");
    }

    let mut best_match = String::from(word);
    let mut best_score = 0;

    for candidate in candidates(word) {
        if let Some(score) = WORDS.get(&candidate) {
            if *score > best_score {
                best_score = *score;
                best_match = candidate;
            }
        }
    }

    return best_match;
}

/// Generate possible spelling corrections for `word`.
fn candidates(word: &str) -> HashSet<String> {
    let mut word_set = HashSet::new();
    word_set.insert(String::from(word));

    if WORDS.contains_key(word) {
        return word_set;
    } else if let Some(single_edits) = known(edits(word)) {
        return single_edits;
    } else if let Some(double_edits) = known(edits2(word)) {
        return double_edits;
    }

    return word_set;
}

/// The subset of `words` that appear in the dictionary of WORDS
fn known(words: HashSet<String>) -> Option<HashSet<String>> {
    let mut known_words = HashSet::new();

    for word in words {
        if WORDS.contains_key(&word) {
            known_words.insert(word);
        }
    }

    match known_words.is_empty() {
        false => return Some(known_words),
        true => return None,
    }
}

/// All edits that are one edit away from `word`.
fn edits(word: &str) -> HashSet<String> {
    // String containing lowercase letters in alphabetical order
    let letters = String::from_utf8((97..123).collect()).unwrap();

    // Construct vector of split variants of `word`
    // cat -> [("", "cat"), ("c", "at"), ("ca", "t")]
    let splits: Vec<_> = (0..word.len()).map(|i| (&word[..i], &word[i..])).collect();

    // Iterate through different edit permutations
    let mut all_edits = HashSet::new();

    for (left, right) in splits {
        // Deletions
        let mut deletion = String::from(left);
        deletion = deletion + &right[1..];
        all_edits.insert(deletion);

        // Transpositions
        if right.len() > 1 {
            let mut transposition = String::from(left);
            let middle: &String = &right[..2].chars().rev().collect();
            transposition = transposition + middle + &right[2..];
            all_edits.insert(transposition);
        }

        for letter in letters.chars() {
            // Replacements
            let mut replacement = String::from(left);
            replacement.push(letter);
            replacement = replacement + &right[1..];
            all_edits.insert(replacement);

            // Insertions
            let mut insertion = String::from(left);
            insertion.push(letter);
            insertion = insertion + right;
            all_edits.insert(insertion);
        }
    }

    // End-of-word insertions (appends?)
    for letter in letters.chars() {
        let mut insertion = String::from(word);
        insertion.push(letter);
        all_edits.insert(insertion);
    }

    return all_edits;
}

/// All edits that are two edits away from `word`
fn edits2(word: &str) -> HashSet<String> {
    let mut all_edits = HashSet::new();

    for single_edits in edits(word) {
        for edit in edits(&single_edits) {
            all_edits.insert(edit);
        }
    }

    return all_edits;
}

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

    #[test]
    fn edit_count() {
        // Words of length n > 1 will have:
        // - n deletions
        // - n-1 transpositions
        // - 26n replacements
        // - 26(n+1) insertions
        // = 54n + 25 total edits

        // Use a punctuation-based test word to ensure unique edits
        let test_word = "!@#$%^&*()";

        for i in 1..(test_word.len() + 1) {
            assert_eq!(edits(&test_word[..i]).len(), 54*i + 25);
        }
    }

    #[test]
    fn possible_candidates() {
        let candidates = candidates("ct");
        assert!(candidates.contains("cat"));
        assert!(candidates.contains("cot"));
        assert!(candidates.contains("cut"));
        assert!(!candidates.contains("czt"));
    }
}
<commit_msg>Rename `edits2` function to `double_edits`<commit_after>#[macro_use]
extern crate lazy_static;
extern crate regex;

use std::collections::{HashMap, HashSet};
use std::io::Read;
use std::fs::File;

use regex::Regex;

lazy_static! {
    static ref WORDS: HashMap<String, usize> = {
        let mut f = File::open("data/big.txt").unwrap();
        let mut s = String::new();
        f.read_to_string(&mut s).unwrap();

        // Count occurrences of words found in `big.txt`
        let mut words = HashMap::new();

        for word in Regex::new(r"\W+").unwrap().split(&s) {
            let count = words.entry(word.to_lowercase()).or_insert(0);
            *count += 1;
        }

        return words;
    };
}

/// Most probable spelling correction for `word`.
pub fn correction(word: &str) -> String {
    if word == "" {
        return String::from("");
    }

    let mut best_match = String::from(word);
    let mut best_score = 0;

    for candidate in candidates(word) {
        if let Some(score) = WORDS.get(&candidate) {
            if *score > best_score {
                best_score = *score;
                best_match = candidate;
            }
        }
    }

    return best_match;
}

/// Generate possible spelling corrections for `word`.
fn candidates(word: &str) -> HashSet<String> {
    let mut word_set = HashSet::new();
    word_set.insert(String::from(word));

    if WORDS.contains_key(word) {
        return word_set;
    } else if let Some(single_edits) = known(edits(word)) {
        return single_edits;
    } else if let Some(double_edits) = known(double_edits(word)) {
        return double_edits;
    }

    return word_set;
}

/// The subset of `words` that appear in the dictionary of WORDS
fn known(words: HashSet<String>) -> Option<HashSet<String>> {
    let mut known_words = HashSet::new();

    for word in words {
        if WORDS.contains_key(&word) {
            known_words.insert(word);
        }
    }

    match known_words.is_empty() {
        false => return Some(known_words),
        true => return None,
    }
}

/// All edits that are one edit away from `word`.
fn edits(word: &str) -> HashSet<String> {
    // String containing lowercase letters in alphabetical order
    let letters = String::from_utf8((97..123).collect()).unwrap();

    // Construct vector of split variants of `word`
    // cat -> [("", "cat"), ("c", "at"), ("ca", "t")]
    let splits: Vec<_> = (0..word.len()).map(|i| (&word[..i], &word[i..])).collect();

    // Iterate through different edit permutations
    let mut all_edits = HashSet::new();

    for (left, right) in splits {
        // Deletions
        let mut deletion = String::from(left);
        deletion = deletion + &right[1..];
        all_edits.insert(deletion);

        // Transpositions
        if right.len() > 1 {
            let mut transposition = String::from(left);
            let middle: &String = &right[..2].chars().rev().collect();
            transposition = transposition + middle + &right[2..];
            all_edits.insert(transposition);
        }

        for letter in letters.chars() {
            // Replacements
            let mut replacement = String::from(left);
            replacement.push(letter);
            replacement = replacement + &right[1..];
            all_edits.insert(replacement);

            // Insertions
            let mut insertion = String::from(left);
            insertion.push(letter);
            insertion = insertion + right;
            all_edits.insert(insertion);
        }
    }

    // End-of-word insertions (appends?)
    for letter in letters.chars() {
        let mut insertion = String::from(word);
        insertion.push(letter);
        all_edits.insert(insertion);
    }

    return all_edits;
}

/// All edits that are two edits away from `word`
fn double_edits(word: &str) -> HashSet<String> {
    let mut all_edits = HashSet::new();

    for single_edit in edits(word) {
        for double_edit in edits(&single_edit) {
            all_edits.insert(double_edit);
        }
    }

    return all_edits;
}

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

    #[test]
    fn edit_count() {
        // Words of length n > 1 will have:
        // - n deletions
        // - n-1 transpositions
        // - 26n replacements
        // - 26(n+1) insertions
        // = 54n + 25 total edits

        // Use a punctuation-based test word to ensure unique edits
        let test_word = "!@#$%^&*()";

        for i in 1..(test_word.len() + 1) {
            assert_eq!(edits(&test_word[..i]).len(), 54*i + 25);
        }
    }

    #[test]
    fn possible_candidates() {
        let candidates = candidates("ct");
        assert!(candidates.contains("cat"));
        assert!(candidates.contains("cot"));
        assert!(candidates.contains("cut"));
        assert!(!candidates.contains("czt"));
    }
}
<|endoftext|>


<commit_before>//! A brush for generative fine art.

mod gpu;
mod noise_traits;
mod raster;
mod render;

pub mod canvas;
pub mod forms;
pub mod paint;
pub mod path;
pub mod shaders;
pub mod transforms;
pub mod uniforms;

/// Exhuastive set of imports for painting.
pub mod prelude {
    pub use self::{
        canvas::*,
        forms::*,
        paint::*,
        path::*,
        shaders::*,
        transforms::*,
        uniforms::*,
    };
    pub use super::*;
    pub use euclid::{self, Rect};
    pub use noise::{self, *};
    pub use noise_traits::*;
    pub use rayon::{self, prelude::*};

    pub use palette::{
        self,
        encoding::Srgb,
        Alpha,
        Blend,
        ComponentWise,
        Hue,
        IntoColor,
        LinSrgb,
        LinSrgba,
        Saturate,
        *,
    };
    pub use rand::{self, rngs::StdRng, Rng, SeedableRng};
    pub use structopt::StructOpt;

    pub use std::f32::consts::PI;
}

pub use self::{
    gpu::{Gpu, Shader},
    render::Context,
    shaders::ShaderProgram,
};

use self::{gpu::*, prelude::*, raster::Method};
use euclid::{Point3D, Size2D, UnknownUnit, Vector2D, Vector3D};
use failure::Error;
use lyon_path::math::Point;
use render::*;
use std::{path::PathBuf, time::Duration};

/// A two dimensional point.
pub type P2 = Point;

/// A three dimensional point.
pub type P3 = Point3D<f32, UnknownUnit>;

/// A two dimensional vector.
pub type V2 = Vector2D<f32, UnknownUnit>;

/// A three dimensional vector.
pub type V3 = Vector3D<f32, UnknownUnit>;

/// A two dimensional size.
pub type S2 = Size2D<f32, UnknownUnit>;

/// An angle.
pub type Angle = euclid::Angle<f32>;

/// A compiled GLSL program.
pub type Program = glium::program::Program;

/// A value or an error.
pub type Result<T> = std::result::Result<T, Error>;

/// Command line options for a painting run.
///
/// Construct with `Options::from_args()` to run the CLI.
#[derive(StructOpt, Debug, Clone)]
#[structopt(name = "valora")]
pub struct Options {
    #[structopt(flatten)]
    pub world: World,

    /// In brainstorm mode:
    ///
    ///   * When rendering a limited number of frames to screen, the preview will not close.
    ///
    ///   * When rendering to file, every frame will be rendered with a different seed.
    #[structopt(short = "b", long = "brainstorm")]
    pub brainstorm: bool,

    /// The number of frames to delay saving to file. For example, if delay=100,
    /// 100 frames will be rendered silently and then the 101st and those after it
    /// will be saved to file.
    #[structopt(short = "d", long = "delay", default_value = "0")]
    pub delay: usize,

    /// Prefix of output path. Output is <prefix>/<seed>/<frame_number>.png
    #[structopt(short = "o", long = "output", parse(from_os_str))]
    pub output: Option<PathBuf>,
}

/// The world in which the painting takes place.
#[derive(StructOpt, Debug, Copy, Clone)]
#[structopt(name = "world")]
pub struct World {
    /// The RNG seed for this painting.
    #[structopt(short = "e", long = "seed", default_value = "0")]
    pub seed: u64,

    /// The width in coordinate space of the painting.
    ///
    /// Coordinate space may differ from output space. If width is 500 but scale is 10, the painting
    /// will have a coordinate space width of 500, but the final output will have a width of 5000 pixels.
    #[structopt(short = "w", long = "width", default_value = "512")]
    pub width: f32,
    /// The height in coordinate space of the painting.
    ///
    /// Coordinate space may differ from output space. If height is 500 but scale is 10, the painting
    /// will have a coordinate space height of 500, but the final output will have a height of 5000 pixels.
    #[structopt(short = "h", long = "height", default_value = "650")]
    pub height: f32,

    /// The scale of the output.
    ///
    /// The final output space is (width*scale)x(height*scale). This value is useful for painting
    /// and doing work at one quickly rendering resolution, and later exporting at a much higher
    /// resolution while preserving the composition exactly.
    ///
    /// This value may be needed when writing shaders or using other raster graphics, to adjust them
    /// for the real output size. Vector painting such as with paths should not need to consider this.
    #[structopt(short = "s", long = "scale", default_value = "1.0")]
    pub scale: f32,

    /// The total number of frames in this painting.
    #[structopt(short = "f", long = "frames")]
    pub frames: Option<usize>,

    /// The number of frames (to try) to render per second.
    #[structopt(short = "r", long = "frames_per_second", default_value = "24")]
    pub framerate: usize,
}

impl World {
    /// Normalizes coordinates into the range [0, 1] by dividing them by the coordinate space dimensions.
    pub fn normalize(&self, p: P2) -> P2 { P2::new(p.x / self.width, p.y / self.height) }

    /// Returns the center of the coordinate space.
    pub fn center(&self) -> P2 { P2::new(self.width / 2.0, self.height / 2.0) }
}

/// Draws a rectangle path covering the entire canvas.
impl Paint for World {
    fn paint(&self, comp: &mut Canvas) {
        comp.line_to(P2::new(0.0, 0.0));
        comp.line_to(P2::new(self.width, 0.0));
        comp.line_to(P2::new(self.width, self.height));
        comp.line_to(P2::new(0.0, self.height));
        comp.line_to(P2::new(0.0, 0.0));
    }
}

/// A trait for types which paint canvases.
pub trait Artist: Sized {
    /// Constructs the artist.
    ///
    /// This would be a place to compile any GLSL or construct any expensive
    /// resources needed across the whole composition.
    fn setup(gpu: Gpu, world: World, rng: &mut StdRng) -> Result<Self>;

    /// Paints a single frame.
    fn paint(&mut self, ctx: Context, canvas: &mut Canvas);
}

/// Run an artist defined by raw functions.
///
/// Takes a function that produces the function that should paint each frame.
pub fn run_fn<F>(options: Options, f: impl Fn(Gpu, World, &mut StdRng) -> Result<F>) -> Result<()>
where
    F: FnMut(Context, &mut Canvas),
{
    let (output_width, output_height) = (
        (options.world.width as f32 * options.world.scale) as u32,
        (options.world.height as f32 * options.world.scale) as u32,
    );

    let number_width = options
        .world
        .frames
        .unwrap_or(0)
        .to_string()
        .chars()
        .count();

    let (gpu, mut strategy) = if let Some(base_path) = options.output.clone() {
        let (gpu, _) = Gpu::new()?;
        let buffer = gpu.build_texture(output_width, output_height)?;

        (
            gpu,
            RenderStrategy::File {
                buffer,
                output_path: move |frame_number: usize, seed: u64| {
                    let mut base_path = base_path.clone();
                    std::fs::create_dir_all(&base_path)
                        .expect(&format!("To create save directory {:?}", base_path));
                    base_path.push(format!(
                        "{}_{number:>0width$}.png",
                        seed,
                        number = frame_number,
                        width = number_width
                    ));
                    base_path
                },
            },
        )
    } else {
        let (gpu, events_loop, (screen_width, screen_height)) =
            Gpu::with_window(output_width, output_height)?;
        let buffer = gpu.build_texture(screen_width, screen_height)?;

        let wait = Duration::from_secs_f64(1. / options.world.framerate as f64);
        let gpu_clone = gpu.clone();

        let texture_glsl = include_str!("shaders/texture.frag");
        let texture_program = gpu.compile_glsl(texture_glsl)?;

        (
            gpu,
            RenderStrategy::Screen {
                events_loop,
                wait,
                buffer,
                texture_program,
                get_frame: move || {
                    gpu_clone
                        .get_frame()
                        .expect("To get frame from windowed gpu")
                },
            },
        )
    };

    let mut current_seed = options.world.seed;
    let mut render_count = 0;
    loop {
        let mut rng = StdRng::seed_from_u64(current_seed);
        let mut paint_fn = f(gpu.clone(), options.world, &mut rng)?;

        let mut renderer = Renderer {
            strategy: &mut strategy,
            gpu: &gpu,
            options: Options {
                world: World {
                    seed: current_seed,
                    frames: match (options.brainstorm, options.output.as_ref()) {
                        (true, Some(_)) => Some(1),
                        _ => options.world.frames,
                    },
                    ..options.world
                },
                ..options.clone()
            },
            rng: &mut rng,
            output_width: output_width,
            output_height: output_height,
        };

        let report = renderer.render_frames(|ctx, canvas| paint_fn(ctx, canvas))?;

        if let Some(rebuild) = report.rebuild {
            match rebuild {
                Rebuild::NewSeed(new_seed) => {
                    current_seed = new_seed;
                }
            }
        } else if options.brainstorm
            && options.output.is_some()
            && render_count < options.world.frames.unwrap_or(usize::max_value())
        {
            current_seed += 1;
        } else if report.explicit_quit || !options.brainstorm || options.output.is_some() {
            break;
        }

        render_count += 1;
    }

    Ok(())
}

/// Run an artist.
pub fn run<A: Artist>(options: Options) -> Result<()> {
    run_fn(options, |gpu, world, rng| {
        let mut artist = A::setup(gpu, world, rng)?;
        Ok(move |ctx: Context, canvas: &mut Canvas| artist.paint(ctx, canvas))
    })
}
<commit_msg>create output dir on init instead of every frame<commit_after>//! A brush for generative fine art.

mod gpu;
mod noise_traits;
mod raster;
mod render;

pub mod canvas;
pub mod forms;
pub mod paint;
pub mod path;
pub mod shaders;
pub mod transforms;
pub mod uniforms;

/// Exhuastive set of imports for painting.
pub mod prelude {
    pub use self::{
        canvas::*,
        forms::*,
        paint::*,
        path::*,
        shaders::*,
        transforms::*,
        uniforms::*,
    };
    pub use super::*;
    pub use euclid::{self, Rect};
    pub use noise::{self, *};
    pub use noise_traits::*;
    pub use rayon::{self, prelude::*};

    pub use palette::{
        self,
        encoding::Srgb,
        Alpha,
        Blend,
        ComponentWise,
        Hue,
        IntoColor,
        LinSrgb,
        LinSrgba,
        Saturate,
        *,
    };
    pub use rand::{self, rngs::StdRng, Rng, SeedableRng};
    pub use structopt::StructOpt;

    pub use std::f32::consts::PI;
}

pub use self::{
    gpu::{Gpu, Shader},
    render::Context,
    shaders::ShaderProgram,
};

use self::{gpu::*, prelude::*, raster::Method};
use euclid::{Point3D, Size2D, UnknownUnit, Vector2D, Vector3D};
use failure::Error;
use lyon_path::math::Point;
use render::*;
use std::{path::PathBuf, time::Duration};

/// A two dimensional point.
pub type P2 = Point;

/// A three dimensional point.
pub type P3 = Point3D<f32, UnknownUnit>;

/// A two dimensional vector.
pub type V2 = Vector2D<f32, UnknownUnit>;

/// A three dimensional vector.
pub type V3 = Vector3D<f32, UnknownUnit>;

/// A two dimensional size.
pub type S2 = Size2D<f32, UnknownUnit>;

/// An angle.
pub type Angle = euclid::Angle<f32>;

/// A compiled GLSL program.
pub type Program = glium::program::Program;

/// A value or an error.
pub type Result<T> = std::result::Result<T, Error>;

/// Command line options for a painting run.
///
/// Construct with `Options::from_args()` to run the CLI.
#[derive(StructOpt, Debug, Clone)]
#[structopt(name = "valora")]
pub struct Options {
    #[structopt(flatten)]
    pub world: World,

    /// In brainstorm mode:
    ///
    ///   * When rendering a limited number of frames to screen, the preview will not close.
    ///
    ///   * When rendering to file, every frame will be rendered with a different seed.
    #[structopt(short = "b", long = "brainstorm")]
    pub brainstorm: bool,

    /// The number of frames to delay saving to file. For example, if delay=100,
    /// 100 frames will be rendered silently and then the 101st and those after it
    /// will be saved to file.
    #[structopt(short = "d", long = "delay", default_value = "0")]
    pub delay: usize,

    /// Prefix of output path. Output is <prefix>/<seed>/<frame_number>.png
    #[structopt(short = "o", long = "output", parse(from_os_str))]
    pub output: Option<PathBuf>,
}

/// The world in which the painting takes place.
#[derive(StructOpt, Debug, Copy, Clone)]
#[structopt(name = "world")]
pub struct World {
    /// The RNG seed for this painting.
    #[structopt(short = "e", long = "seed", default_value = "0")]
    pub seed: u64,

    /// The width in coordinate space of the painting.
    ///
    /// Coordinate space may differ from output space. If width is 500 but scale is 10, the painting
    /// will have a coordinate space width of 500, but the final output will have a width of 5000 pixels.
    #[structopt(short = "w", long = "width", default_value = "512")]
    pub width: f32,
    /// The height in coordinate space of the painting.
    ///
    /// Coordinate space may differ from output space. If height is 500 but scale is 10, the painting
    /// will have a coordinate space height of 500, but the final output will have a height of 5000 pixels.
    #[structopt(short = "h", long = "height", default_value = "650")]
    pub height: f32,

    /// The scale of the output.
    ///
    /// The final output space is (width*scale)x(height*scale). This value is useful for painting
    /// and doing work at one quickly rendering resolution, and later exporting at a much higher
    /// resolution while preserving the composition exactly.
    ///
    /// This value may be needed when writing shaders or using other raster graphics, to adjust them
    /// for the real output size. Vector painting such as with paths should not need to consider this.
    #[structopt(short = "s", long = "scale", default_value = "1.0")]
    pub scale: f32,

    /// The total number of frames in this painting.
    #[structopt(short = "f", long = "frames")]
    pub frames: Option<usize>,

    /// The number of frames (to try) to render per second.
    #[structopt(short = "r", long = "frames_per_second", default_value = "24")]
    pub framerate: usize,
}

impl World {
    /// Normalizes coordinates into the range [0, 1] by dividing them by the coordinate space dimensions.
    pub fn normalize(&self, p: P2) -> P2 { P2::new(p.x / self.width, p.y / self.height) }

    /// Returns the center of the coordinate space.
    pub fn center(&self) -> P2 { P2::new(self.width / 2.0, self.height / 2.0) }
}

/// Draws a rectangle path covering the entire canvas.
impl Paint for World {
    fn paint(&self, comp: &mut Canvas) {
        comp.line_to(P2::new(0.0, 0.0));
        comp.line_to(P2::new(self.width, 0.0));
        comp.line_to(P2::new(self.width, self.height));
        comp.line_to(P2::new(0.0, self.height));
        comp.line_to(P2::new(0.0, 0.0));
    }
}

/// A trait for types which paint canvases.
pub trait Artist: Sized {
    /// Constructs the artist.
    ///
    /// This would be a place to compile any GLSL or construct any expensive
    /// resources needed across the whole composition.
    fn setup(gpu: Gpu, world: World, rng: &mut StdRng) -> Result<Self>;

    /// Paints a single frame.
    fn paint(&mut self, ctx: Context, canvas: &mut Canvas);
}

/// Run an artist defined by raw functions.
///
/// Takes a function that produces the function that should paint each frame.
pub fn run_fn<F>(options: Options, f: impl Fn(Gpu, World, &mut StdRng) -> Result<F>) -> Result<()>
where
    F: FnMut(Context, &mut Canvas),
{
    let (output_width, output_height) = (
        (options.world.width as f32 * options.world.scale) as u32,
        (options.world.height as f32 * options.world.scale) as u32,
    );

    let number_width = options
        .world
        .frames
        .unwrap_or(0)
        .to_string()
        .chars()
        .count();

    let (gpu, mut strategy) = if let Some(base_path) = options.output.clone() {
        let (gpu, _) = Gpu::new()?;
        let buffer = gpu.build_texture(output_width, output_height)?;

        std::fs::create_dir_all(&base_path)
            .expect(&format!("To create save directory {}", base_path.display()));

        (
            gpu,
            RenderStrategy::File {
                buffer,
                output_path: move |frame_number: usize, seed: u64| {
                    let mut base_path = base_path.clone();
                    base_path.push(format!(
                        "{}_{number:>0width$}.png",
                        seed,
                        number = frame_number,
                        width = number_width
                    ));
                    base_path
                },
            },
        )
    } else {
        let (gpu, events_loop, (screen_width, screen_height)) =
            Gpu::with_window(output_width, output_height)?;
        let buffer = gpu.build_texture(screen_width, screen_height)?;

        let wait = Duration::from_secs_f64(1. / options.world.framerate as f64);
        let gpu_clone = gpu.clone();

        let texture_glsl = include_str!("shaders/texture.frag");
        let texture_program = gpu.compile_glsl(texture_glsl)?;

        (
            gpu,
            RenderStrategy::Screen {
                events_loop,
                wait,
                buffer,
                texture_program,
                get_frame: move || {
                    gpu_clone
                        .get_frame()
                        .expect("To get frame from windowed gpu")
                },
            },
        )
    };

    let mut current_seed = options.world.seed;
    let mut render_count = 0;
    loop {
        let mut rng = StdRng::seed_from_u64(current_seed);
        let mut paint_fn = f(gpu.clone(), options.world, &mut rng)?;

        let mut renderer = Renderer {
            strategy: &mut strategy,
            gpu: &gpu,
            options: Options {
                world: World {
                    seed: current_seed,
                    frames: match (options.brainstorm, options.output.as_ref()) {
                        (true, Some(_)) => Some(1),
                        _ => options.world.frames,
                    },
                    ..options.world
                },
                ..options.clone()
            },
            rng: &mut rng,
            output_width: output_width,
            output_height: output_height,
        };

        let report = renderer.render_frames(|ctx, canvas| paint_fn(ctx, canvas))?;

        if let Some(rebuild) = report.rebuild {
            match rebuild {
                Rebuild::NewSeed(new_seed) => {
                    current_seed = new_seed;
                }
            }
        } else if options.brainstorm
            && options.output.is_some()
            && render_count < options.world.frames.unwrap_or(usize::max_value())
        {
            current_seed += 1;
        } else if report.explicit_quit || !options.brainstorm || options.output.is_some() {
            break;
        }

        render_count += 1;
    }

    Ok(())
}

/// Run an artist.
pub fn run<A: Artist>(options: Options) -> Result<()> {
    run_fn(options, |gpu, world, rng| {
        let mut artist = A::setup(gpu, world, rng)?;
        Ok(move |ctx: Context, canvas: &mut Canvas| artist.paint(ctx, canvas))
    })
}
<|endoftext|>


<commit_before>#![feature(phase)]

#[phase(plugin, link)]
extern crate conrod;
extern crate piston;
extern crate collections;
extern crate string_telephone;
extern crate opengl_graphics;
extern crate sdl2_game_window;

use opengl_graphics::{
    Gl,
    Texture,
};

use conrod::{
    UIContext,
};

use collections::str::{Slice, Owned};
use std::io::net::ip::{Ipv4Addr, SocketAddr};
use piston::{EventIterator, EventSettings, WindowSettings, graphics, Render};
use piston::graphics::{AddColor, Draw};
use string_telephone::{Client, ConnectionConfig, UserPacket, Command, PacketDisconnect, PacketConnect};
use sdl2_game_window::WindowSDL2;

fn deserializer(message: &Vec<u8>) -> String {
    match String::from_utf8_lossy(message.as_slice()) {
        Slice(slice) => slice.to_string(),
        Owned(item) => item
    }
}

fn serializer(packet: &String) -> Vec<u8> {
    packet.clone().into_bytes()
}

fn main() {
    let settings = ConnectionConfig {
        protocol_id: 88869,
        timeout_period: 10,
        packet_deserializer: deserializer,
        packet_serializer: serializer
    };

    let mut client = match Client::connect(SocketAddr {ip: Ipv4Addr(0, 0, 0, 0), port: 0}, SocketAddr {ip: Ipv4Addr(127, 0, 0, 1), port: 8869}, settings) {
        Ok(client) => {
            client
        },
        Err(e) => fail!("Failed to connect - {}", e)
    };

    let opengl = piston::shader_version::opengl::OpenGL_3_2;
    let mut window = WindowSDL2::new(
        opengl,
        WindowSettings {
            title: "SuperMegaTag".to_string(),
            size: [800, 600],
            fullscreen: false,
            exit_on_esc: true,
            samples: 0,
        }
    );

    let event_settings = EventSettings {
        updates_per_second: 120,
        max_frames_per_second: 60,
    };
    let ref mut gl = Gl::new(opengl);

    let mut uic = UIContext::new("Dense-Regular.otf");
    for e in EventIterator::new(&mut window, &event_settings) {
        match e {
            Render(args) => {
                gl.viewport(0, 0, args.width as i32, args.height as i32);

                let c = graphics::Context::abs(args.width as f64, args.height as f64);
                c.rgb(1.0, 1.0, 1.0).draw(gl);
            },
            _ => {},
        }
    }
}
<commit_msg>Started putting together server picker interface<commit_after>#![feature(phase)]

#[phase(plugin, link)]
extern crate conrod;
extern crate piston;
extern crate collections;
extern crate string_telephone;
extern crate opengl_graphics;
extern crate sdl2_game_window;

use opengl_graphics::{
    Gl,
    Texture,
};

use conrod::{
    UIContext,
    label,
    Color,
    Point,
    widget_matrix,
    Button,
    Callable,
    Colorable,
    Drawable,
    DropDownList,
    EnvelopeEditor,
    Frameable,
    Labelable,
    NumberDialer,
    Positionable,
    Slider,
    Shapeable,
    TextBox,
    Toggle,
    XYPad,
};

use collections::str::{Slice, Owned};
use std::io::net::ip::{Ipv4Addr, SocketAddr};
use piston::{EventIterator, EventSettings, WindowSettings, graphics, Render};
use piston::graphics::{AddColor, Draw};
use string_telephone::{Client, ConnectionConfig, UserPacket, Command, PacketDisconnect, PacketConnect};
use sdl2_game_window::WindowSDL2;

fn deserializer(message: &Vec<u8>) -> String {
    match String::from_utf8_lossy(message.as_slice()) {
        Slice(slice) => slice.to_string(),
        Owned(item) => item
    }
}

fn serializer(packet: &String) -> Vec<u8> {
    packet.clone().into_bytes()
}

fn main() {
    let settings = ConnectionConfig {
        protocol_id: 88869,
        timeout_period: 10,
        packet_deserializer: deserializer,
        packet_serializer: serializer
    };

    /*let mut client = match Client::connect(SocketAddr {ip: Ipv4Addr(0, 0, 0, 0), port: 0}, SocketAddr {ip: Ipv4Addr(127, 0, 0, 1), port: 8869}, settings) {
        Ok(client) => {
            client
        },
        Err(e) => fail!("Failed to connect - {}", e)
    };*/

    let opengl = piston::shader_version::opengl::OpenGL_3_2;
    let mut window = WindowSDL2::new(
        opengl,
        WindowSettings {
            title: "SuperMegaTag".to_string(),
            size: [800, 600],
            fullscreen: false,
            exit_on_esc: true,
            samples: 4,
        }
    );

    let event_settings = EventSettings {
        updates_per_second: 120,
        max_frames_per_second: 60,
    };
    let ref mut gl = Gl::new(opengl);

    let ref mut uic = UIContext::new("Dense-Regular.otf");

    let mut edit_ip = vec!["127".to_string(), "0".to_string(), "0".to_string(), "1".to_string()];

    for ref e in EventIterator::new(&mut window, &event_settings) {
        uic.handle_event(e);
        match e {
            &Render(args) => {
                gl.viewport(0, 0, args.width as i32, args.height as i32);

                let c = &graphics::Context::abs(args.width as f64, args.height as f64);
                c.rgb(1.0, 1.0, 1.0).draw(gl);
                label::draw(
                    gl,
                    uic,
                    Point::new(0f64, 0f64, 0f64), // Screen position.
                    48u32, // Font size.
                    Color::new(1.0, 0.0, 0.0, 1.0),
                    "Select a server"
                );

                widget_matrix::draw(
                    4, // cols.
                    1, // rows.
                    Point::new(300.0, 270.0, 0.0), // matrix position.
                    300.0, // width.
                    240.0, // height.
                    |num, col, row, pos, width, height| { // This is called for every widget.
                        // Now draw the widgets with the given callback.
                        uic.text_box(2 + num as u64, edit_ip.get_mut(num))
                            .font_size(24u32)
                            .dimensions(width, 36.0)
                            .position(pos.x, pos.y)
                            .frame(2.0, Color::black())
                            //.color(Color::new(1.0, 0.0, 0.0, 1.0))
                            .draw(gl);

                    }
                );

            },
            _ => {},
        }
    }
}
<|endoftext|>


<commit_before>// Run Clippy in a firejail Sandbox and parse its output

extern crate rustc_serialize;

use rustc_serialize::json::Json;

use std::process::{ Command, Output };
use std::path::Path;
use std::vec::Vec;
use std::{env, fs};

// Enum describing the State of the Clippy result,
// whether everything went fine or if warnings or
// errors were found – and if so, how many
pub enum ClippyResult {
    Success,
    WithWarnings(u32),
    WithErrors(u32, u32),
}

fn run_in_sandbox<F>(path: &Path, command: &Vec<&str>, logger: &F) -> Output
    where F: Fn(&str)
{

    // Build the `firejail` arguments, using the preinstalled `cargo`-profile
    // use the `--force` flag to make it run even though we are in a docker
    // environment. For that to work, our docker needs to be setup to run in
    // the `--privileged` mode.

    logger(&format!("Running: {}", command.join(" ")));

    let str_path = path.to_string_lossy().into_owned();
    let whitelist = format!("--whitelist={}", &str_path);
    let name = format!("--name={}", &str_path);

    let mut args = vec!["--profile=/etc/firejail/cargo.profile",
                        "--force",
                        "--quiet",
                        whitelist.as_str(),
                        name.as_str()

                        // Limit the resources each process is allowed to use to 75% of one CPU,
                        // for a maximum of 10 minutes soft (11min hard limit).
                        // Then add the command itself then run it
                        "timeout", "-k", "10m", "11m",
                        "cpulimit", "-l75", "--",

                        ];
    args.extend_from_slice(command);

    let output = Command::new("firejail")
                .args(&args)
                .current_dir(path)
                .output().unwrap_or_else( |e| {
                    logger(&format!("Running command failed :\n{}", &e));
                    panic!("failed to execute process: {}", &e);
              });

    // Log the content
    // and return the result
    logger(&format!("----- stdout:\n{}", &String::from_utf8(output.stdout.clone()).unwrap()));
    logger(&format!("----- stderr:\n{}", &String::from_utf8(output.stderr.clone()).unwrap()));

    // and return the result
    output
}

// ## Run
// Run clippy in the specified Path. We expect there to be a Cargo.toml file, checking for
// that should have happened already. While calculating the `ClippyResult`, inform about
// the current process via the `logger` function.
pub fn run<F>(path: &Path, logger: F) -> Result<ClippyResult, String>
    where F: Fn(&str)
{

    //  run rustc and cargo versions for easier debugging for the viewer
    run_in_sandbox(&path, &vec!["rustc", "--version"], &logger);
    run_in_sandbox(&path, &vec!["cargo", "--version"], &logger);

    logger("-------------------------------- Running Clippy");

    // Find the _local_ clippy we are shipping with the clippy-service
    // and append that to the cargo rustc process
    let libs_path = env::current_exe().unwrap();
    let libs_path = fs::canonicalize(libs_path).unwrap();
    let libs_path = libs_path.parent().unwrap();
    let libs_path = libs_path.join("deps");
    let libs_path = libs_path.to_str().unwrap().to_owned();

    let output = run_in_sandbox(&path, &vec![
                    // The command we want to run is `cargo rustc` with the extra compiler
                    // plugin for clippy which can be found at the library path passed after
                    // `-L`. Secondly we need rustc to report errors in the `json`-format (new
                    // nightly feature), so we can parse it later.
                    "cargo",
                    "rustc",
                    "--",
                    "-L",
                    libs_path.as_str(),
                    "-Zunstable-options",
                    "-Zextra-plugins=clippy",
                    "-Zno-trans",
                    "-lclippy",
                    "--error-format=json"], &logger);

    let stderr = String::from_utf8(output.stderr).unwrap();

    let mut warnings = 0;
    let mut errors = 0;
    // Next up, we need to parse the outpuf from stderr, where
    // clippy and the compiler might report errors to us. There is
    // one error per line, which is why we split it into lines. We
    // then use `filter_map` to find all those lines we can decode
    // from JSON
    let messages: Vec<String> = stderr.split('\n')
        .filter_map(|line| Json::from_str(&line).ok())
        .filter_map(|json| {
            // and then `filter_map` those into
            // the warnings and errors we care about,
            // while also updating the local count
            // of both.
            let obj = json.as_object().unwrap();
            match obj.get("level") {
                Some(&Json::String(ref level)) => {
                    if level == "warning" {
                        warnings += 1;
                    } else if level == "error" {
                        errors += 1;
                    }
                    Some(format!("{level}: {msg}", level = level,
                                 msg = obj.get("message").unwrap()))
                }
                _ => None,
            }
        })
        // The collect executes this iterative into
        // a vector of results. We can now log to the
        // viewer.
        .collect();

    logger(&format!("-----\nMessages identified:\n {}", messages.join("\n")));

    // Next parse the count of errors and warnings
    // and wrap that into the appropriate `ClippyResult`
    if output.status.success() {
        match (errors, warnings) {
            (0, 0) => Ok(ClippyResult::Success),
            (0, x) => Ok(ClippyResult::WithWarnings(x)),
            _ => Ok(ClippyResult::WithErrors(errors, warnings))
        }
    } else {
        Err("Running Clippy failed.".to_string())
    }
}
<commit_msg>missing comma<commit_after>// Run Clippy in a firejail Sandbox and parse its output

extern crate rustc_serialize;

use rustc_serialize::json::Json;

use std::process::{ Command, Output };
use std::path::Path;
use std::vec::Vec;
use std::{env, fs};

// Enum describing the State of the Clippy result,
// whether everything went fine or if warnings or
// errors were found – and if so, how many
pub enum ClippyResult {
    Success,
    WithWarnings(u32),
    WithErrors(u32, u32),
}

fn run_in_sandbox<F>(path: &Path, command: &Vec<&str>, logger: &F) -> Output
    where F: Fn(&str)
{

    // Build the `firejail` arguments, using the preinstalled `cargo`-profile
    // use the `--force` flag to make it run even though we are in a docker
    // environment. For that to work, our docker needs to be setup to run in
    // the `--privileged` mode.

    logger(&format!("Running: {}", command.join(" ")));

    let str_path = path.to_string_lossy().into_owned();
    let whitelist = format!("--whitelist={}", &str_path);
    let name = format!("--name={}", &str_path);

    let mut args = vec!["--profile=/etc/firejail/cargo.profile",
                        "--force",
                        "--quiet",
                        whitelist.as_str(),
                        name.as_str(),

                        // Limit the resources each process is allowed to use to 75% of one CPU,
                        // for a maximum of 10 minutes soft (11min hard limit).
                        // Then add the command itself then run it
                        "timeout", "-k", "10m", "11m",
                        "cpulimit", "-l75", "--",

                        ];
    args.extend_from_slice(command);

    let output = Command::new("firejail")
                .args(&args)
                .current_dir(path)
                .output().unwrap_or_else( |e| {
                    logger(&format!("Running command failed :\n{}", &e));
                    panic!("failed to execute process: {}", &e);
              });

    // Log the content
    // and return the result
    logger(&format!("----- stdout:\n{}", &String::from_utf8(output.stdout.clone()).unwrap()));
    logger(&format!("----- stderr:\n{}", &String::from_utf8(output.stderr.clone()).unwrap()));

    // and return the result
    output
}

// ## Run
// Run clippy in the specified Path. We expect there to be a Cargo.toml file, checking for
// that should have happened already. While calculating the `ClippyResult`, inform about
// the current process via the `logger` function.
pub fn run<F>(path: &Path, logger: F) -> Result<ClippyResult, String>
    where F: Fn(&str)
{

    //  run rustc and cargo versions for easier debugging for the viewer
    run_in_sandbox(&path, &vec!["rustc", "--version"], &logger);
    run_in_sandbox(&path, &vec!["cargo", "--version"], &logger);

    logger("-------------------------------- Running Clippy");

    // Find the _local_ clippy we are shipping with the clippy-service
    // and append that to the cargo rustc process
    let libs_path = env::current_exe().unwrap();
    let libs_path = fs::canonicalize(libs_path).unwrap();
    let libs_path = libs_path.parent().unwrap();
    let libs_path = libs_path.join("deps");
    let libs_path = libs_path.to_str().unwrap().to_owned();

    let output = run_in_sandbox(&path, &vec![
                    // The command we want to run is `cargo rustc` with the extra compiler
                    // plugin for clippy which can be found at the library path passed after
                    // `-L`. Secondly we need rustc to report errors in the `json`-format (new
                    // nightly feature), so we can parse it later.
                    "cargo",
                    "rustc",
                    "--",
                    "-L",
                    libs_path.as_str(),
                    "-Zunstable-options",
                    "-Zextra-plugins=clippy",
                    "-Zno-trans",
                    "-lclippy",
                    "--error-format=json"], &logger);

    let stderr = String::from_utf8(output.stderr).unwrap();

    let mut warnings = 0;
    let mut errors = 0;
    // Next up, we need to parse the outpuf from stderr, where
    // clippy and the compiler might report errors to us. There is
    // one error per line, which is why we split it into lines. We
    // then use `filter_map` to find all those lines we can decode
    // from JSON
    let messages: Vec<String> = stderr.split('\n')
        .filter_map(|line| Json::from_str(&line).ok())
        .filter_map(|json| {
            // and then `filter_map` those into
            // the warnings and errors we care about,
            // while also updating the local count
            // of both.
            let obj = json.as_object().unwrap();
            match obj.get("level") {
                Some(&Json::String(ref level)) => {
                    if level == "warning" {
                        warnings += 1;
                    } else if level == "error" {
                        errors += 1;
                    }
                    Some(format!("{level}: {msg}", level = level,
                                 msg = obj.get("message").unwrap()))
                }
                _ => None,
            }
        })
        // The collect executes this iterative into
        // a vector of results. We can now log to the
        // viewer.
        .collect();

    logger(&format!("-----\nMessages identified:\n {}", messages.join("\n")));

    // Next parse the count of errors and warnings
    // and wrap that into the appropriate `ClippyResult`
    if output.status.success() {
        match (errors, warnings) {
            (0, 0) => Ok(ClippyResult::Success),
            (0, x) => Ok(ClippyResult::WithWarnings(x)),
            _ => Ok(ClippyResult::WithErrors(errors, warnings))
        }
    } else {
        Err("Running Clippy failed.".to_string())
    }
}
<|endoftext|>


<commit_before>use nom::{alphanumeric, digit, eof, is_alphanumeric, line_ending, multispace};
use nom::{IResult, Err, ErrorKind, Needed};
use std::str;
use std::str::FromStr;

use column::{Column, FunctionExpression};
use keywords::sql_keyword;
use table::Table;

#[derive(Clone, Debug, Hash, PartialEq)]
pub enum Operator {
    Not,
    And,
    Or,
    Like,
    NotLike,
    Equal,
    NotEqual,
    Greater,
    GreaterOrEqual,
    Less,
    LessOrEqual,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum FieldExpression {
    All,
    Seq(Vec<Column>),
}

impl Default for FieldExpression {
    fn default() -> FieldExpression {
        FieldExpression::All
    }
}

#[inline]
pub fn is_sql_identifier(chr: u8) -> bool {
    // XXX(malte): dot should not be in here once we have proper alias handling
    is_alphanumeric(chr) || chr == '_' as u8
}

#[inline]
pub fn is_fp_number(chr: u8) -> bool {
    is_alphanumeric(chr) || chr == '.' as u8
}

/// Parses a floating point number (very badly).
named!(pub fp_number<&[u8], &[u8]>,
// f64::from_str(&format!("{}.{}", integral, fractional)).unwrap()
//      integral: map_res!(take_while1!(is_digit), str::from_utf8) ~
//      fractional: map_res!(take_while!(is_digit), str::from_utf8),
    take_while1!(is_fp_number)
);

named!(pub column_function<&[u8], FunctionExpression>,
    alt_complete!(
        chain!(
            caseless_tag!("count") ~
            columns: delimited!(tag!("("), field_expr, tag!(")")),
            || {
                FunctionExpression::Count(columns)
            }
        )
    |   chain!(
            caseless_tag!("sum") ~
            columns: delimited!(tag!("("), field_expr, tag!(")")),
            || {
                FunctionExpression::Sum(columns)
            }
        )
    |   chain!(
            caseless_tag!("avg") ~
            columns: delimited!(tag!("("), field_expr, tag!(")")),
            || {
                FunctionExpression::Avg(columns)
            }
        )
    |   chain!(
            caseless_tag!("max") ~
            columns: delimited!(tag!("("), field_expr, tag!(")")),
            || {
                FunctionExpression::Max(columns)
            }
        )
    |   chain!(
            caseless_tag!("min") ~
            columns: delimited!(tag!("("), field_expr, tag!(")")),
            || {
                FunctionExpression::Min(columns)
            }
        )
    |   chain!(
            caseless_tag!("group_concat") ~
            columns: delimited!(tag!("("), field_expr, tag!(")")),
            || {
                FunctionExpression::GroupConcat(columns)
            }
        )
    )
);

/// Parses a SQL column identifier in the table.column format
named!(pub column_identifier<&[u8], Column>,
    alt_complete!(
        chain!(
            function: column_function ~
            alias: opt!(chain!(
                multispace ~
                caseless_tag!("as") ~
                multispace ~
                alias: map_res!(sql_identifier, str::from_utf8),
                || { alias }
            )),
            || {
                Column {
                    name: match alias {
                        Some(a) => String::from(a),
                        None => String::from("anon_fn"),
                    },
                    table: None,
                    function: Some(function),
                }
            }
        )
        | chain!(
            table: opt!(
                chain!(
                    tbl_name: map_res!(sql_identifier, str::from_utf8) ~
                    tag!("."),
                    || { tbl_name }
                )
            ) ~
            column: map_res!(sql_identifier, str::from_utf8),
            || {
                Column {
                    name: String::from(column),
                    table: match table {
                        None => None,
                        Some(t) => Some(String::from(t)),
                    },
                    function: None,
                }
            }
        )
    )
);

/// Parses a SQL identifier (alphanumeric and "_").
named!(pub sql_identifier<&[u8], &[u8]>,
    alt_complete!(
          chain!(
                not!(peek!(sql_keyword)) ~
                ident: take_while1!(is_sql_identifier),
                || { ident }
          )
        | delimited!(tag!("`"), take_while1!(is_sql_identifier), tag!("`"))
        | delimited!(tag!("'"), take_while1!(is_sql_identifier), tag!("'"))
    )
);

/// Parse an unsigned integer.
named!(pub unsigned_number<&[u8], u64>,
    map_res!(
        map_res!(digit, str::from_utf8),
        FromStr::from_str
    )
);

/// Parse a terminator that ends a SQL statement.
named!(pub statement_terminator,
    delimited!(opt!(multispace),
               alt_complete!(tag!(";") | line_ending | eof),
               opt!(multispace)
    )
);

/// Parse binary comparison operators
named!(pub binary_comparison_operator<&[u8], Operator>,
    alt_complete!(
           map!(caseless_tag!("not_like"), |_| Operator::NotLike)
         | map!(caseless_tag!("like"), |_| Operator::Like)
         | map!(caseless_tag!("<>"), |_| Operator::NotEqual)
         | map!(caseless_tag!(">="), |_| Operator::GreaterOrEqual)
         | map!(caseless_tag!("<="), |_| Operator::LessOrEqual)
         | map!(caseless_tag!("="), |_| Operator::Equal)
         | map!(caseless_tag!("<"), |_| Operator::Less)
         | map!(caseless_tag!(">"), |_| Operator::Greater)
    )
);

/// Parse logical operators
named!(pub binary_logical_operator<&[u8], Operator>,
    alt_complete!(
           map!(caseless_tag!("and"), |_| Operator::And)
         | map!(caseless_tag!("or"), |_| Operator::Or)
    )
);

/// Parse unary comparison operators
named!(pub unary_comparison_operator<&[u8], &str>,
    map_res!(
        alt_complete!(
               tag_s!(b"ISNULL")
             | tag_s!(b"NOT")
             | tag_s!(b"-") // ??? (number neg)
        ),
        str::from_utf8
    )
);

/// Parse unary comparison operators
named!(pub unary_negation_operator<&[u8], Operator>,
    alt_complete!(
          map!(caseless_tag!("not"), |_| Operator::Not)
        | map!(caseless_tag!("!"), |_| Operator::Not)
    )
);

/// Parse rule for a comma-separated list.
named!(pub field_list<&[u8], Vec<Column> >,
       many0!(
           chain!(
               fieldname: column_identifier ~
               opt!(
                   complete!(chain!(
                       multispace? ~
                       tag!(",") ~
                       multispace?,
                       ||{}
                   ))
               ),
               || { fieldname }
           )
       )
);

/// Parse list of columns/fields.
/// XXX(malte): add support for named table notation
named!(pub field_expr<&[u8], FieldExpression>,
       alt_complete!(
           tag!("*") => { |_| FieldExpression::All }
         | map!(field_list, |v| FieldExpression::Seq(v))
       )
);

/// Parse list of table names.
/// XXX(malte): add support for aliases
named!(pub table_list<&[u8], Vec<Table> >,
       many0!(
           chain!(
               table: table_reference ~
               opt!(
                   complete!(chain!(
                       multispace? ~
                       tag!(",") ~
                       multispace?,
                       || {}
                   ))
               ),
               || { table }
           )
       )
);

/// Parse a list of values (e.g., for INSERT syntax).
/// XXX(malte): proper value type
named!(pub value_list<&[u8], Vec<&str> >,
       many0!(
           map_res!(
               chain!(
                   val: alt_complete!(
                         tag_s!(b"?")
                       | tag_s!(b"CURRENT_TIMESTAMP")
                       | delimited!(tag!("'"), alphanumeric, tag!("'"))
                       | fp_number
                   ) ~
                   opt!(
                       complete!(chain!(
                           multispace? ~
                           tag!(",") ~
                           multispace?,
                           ||{}
                       ))
                   ),
                   || { val }
               ),
               str::from_utf8
           )
       )
);

/// Parse a reference to a named table
/// XXX(malte): add support for schema.table notation
named!(pub table_reference<&[u8], Table>,
    chain!(
        table: map_res!(sql_identifier, str::from_utf8) ~
        alias: opt!(
            complete!(chain!(
                multispace ~
                caseless_tag!("as") ~
                multispace ~
                alias: map_res!(sql_identifier, str::from_utf8),
                || { String::from(alias) }
            ))
        ),
        || {
            Table {
                name: String::from(table),
                alias: alias,
            }
        }
    )
);

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

    #[test]
    fn sql_identifiers() {
        let id1 = b"foo";
        let id2 = b"f_o_o";
        let id3 = b"foo12";
        let id4 = b":fo oo";
        let id5 = b"primary ";
        let id6 = b"`primary`";

        assert!(sql_identifier(id1).is_done());
        assert!(sql_identifier(id2).is_done());
        assert!(sql_identifier(id3).is_done());
        assert!(sql_identifier(id4).is_err());
        assert!(sql_identifier(id5).is_err());
        assert!(sql_identifier(id6).is_done());
    }

    #[test]
    fn simple_column_function() {
        let qs = b"max(addr_id)";

        let res = column_identifier(qs);
        let expected_fields = FieldExpression::Seq(vec![Column::from("addr_id")]);
        let expected_fn = Some(FunctionExpression::Max(expected_fields));
        let expected = Column {
            name: String::from("anon_fn"),
            table: None,
            function: expected_fn,
        };
        assert_eq!(res.unwrap().1, expected);
    }
}
<commit_msg>Shared parsing rule for aliases<commit_after>use nom::{alphanumeric, digit, eof, is_alphanumeric, line_ending, multispace};
use nom::{IResult, Err, ErrorKind, Needed};
use std::str;
use std::str::FromStr;

use column::{Column, FunctionExpression};
use keywords::sql_keyword;
use table::Table;

#[derive(Clone, Debug, Hash, PartialEq)]
pub enum Operator {
    Not,
    And,
    Or,
    Like,
    NotLike,
    Equal,
    NotEqual,
    Greater,
    GreaterOrEqual,
    Less,
    LessOrEqual,
}

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum FieldExpression {
    All,
    Seq(Vec<Column>),
}

impl Default for FieldExpression {
    fn default() -> FieldExpression {
        FieldExpression::All
    }
}

#[inline]
pub fn is_sql_identifier(chr: u8) -> bool {
    // XXX(malte): dot should not be in here once we have proper alias handling
    is_alphanumeric(chr) || chr == '_' as u8
}

#[inline]
pub fn is_fp_number(chr: u8) -> bool {
    is_alphanumeric(chr) || chr == '.' as u8
}

/// Parses a floating point number (very badly).
named!(pub fp_number<&[u8], &[u8]>,
// f64::from_str(&format!("{}.{}", integral, fractional)).unwrap()
//      integral: map_res!(take_while1!(is_digit), str::from_utf8) ~
//      fractional: map_res!(take_while!(is_digit), str::from_utf8),
    take_while1!(is_fp_number)
);

named!(pub column_function<&[u8], FunctionExpression>,
    alt_complete!(
        chain!(
            caseless_tag!("count") ~
            columns: delimited!(tag!("("), field_expr, tag!(")")),
            || {
                FunctionExpression::Count(columns)
            }
        )
    |   chain!(
            caseless_tag!("sum") ~
            columns: delimited!(tag!("("), field_expr, tag!(")")),
            || {
                FunctionExpression::Sum(columns)
            }
        )
    |   chain!(
            caseless_tag!("avg") ~
            columns: delimited!(tag!("("), field_expr, tag!(")")),
            || {
                FunctionExpression::Avg(columns)
            }
        )
    |   chain!(
            caseless_tag!("max") ~
            columns: delimited!(tag!("("), field_expr, tag!(")")),
            || {
                FunctionExpression::Max(columns)
            }
        )
    |   chain!(
            caseless_tag!("min") ~
            columns: delimited!(tag!("("), field_expr, tag!(")")),
            || {
                FunctionExpression::Min(columns)
            }
        )
    |   chain!(
            caseless_tag!("group_concat") ~
            columns: delimited!(tag!("("), field_expr, tag!(")")),
            || {
                FunctionExpression::GroupConcat(columns)
            }
        )
    )
);

/// Parses a SQL column identifier in the table.column format
named!(pub column_identifier<&[u8], Column>,
    alt_complete!(
        chain!(
            function: column_function ~
            alias: opt!(as_alias),
            || {
                Column {
                    name: match alias {
                        Some(a) => String::from(a),
                        None => String::from("anon_fn"),
                    },
                    table: None,
                    function: Some(function),
                }
            }
        )
        | chain!(
            table: opt!(
                chain!(
                    tbl_name: map_res!(sql_identifier, str::from_utf8) ~
                    tag!("."),
                    || { tbl_name }
                )
            ) ~
            column: map_res!(sql_identifier, str::from_utf8),
            || {
                Column {
                    name: String::from(column),
                    table: match table {
                        None => None,
                        Some(t) => Some(String::from(t)),
                    },
                    function: None,
                }
            }
        )
    )
);

/// Parses a SQL identifier (alphanumeric and "_").
named!(pub sql_identifier<&[u8], &[u8]>,
    alt_complete!(
          chain!(
                not!(peek!(sql_keyword)) ~
                ident: take_while1!(is_sql_identifier),
                || { ident }
          )
        | delimited!(tag!("`"), take_while1!(is_sql_identifier), tag!("`"))
        | delimited!(tag!("'"), take_while1!(is_sql_identifier), tag!("'"))
    )
);

/// Parse an unsigned integer.
named!(pub unsigned_number<&[u8], u64>,
    map_res!(
        map_res!(digit, str::from_utf8),
        FromStr::from_str
    )
);

/// Parse a terminator that ends a SQL statement.
named!(pub statement_terminator,
    delimited!(opt!(multispace),
               alt_complete!(tag!(";") | line_ending | eof),
               opt!(multispace)
    )
);

/// Parse binary comparison operators
named!(pub binary_comparison_operator<&[u8], Operator>,
    alt_complete!(
           map!(caseless_tag!("not_like"), |_| Operator::NotLike)
         | map!(caseless_tag!("like"), |_| Operator::Like)
         | map!(caseless_tag!("<>"), |_| Operator::NotEqual)
         | map!(caseless_tag!(">="), |_| Operator::GreaterOrEqual)
         | map!(caseless_tag!("<="), |_| Operator::LessOrEqual)
         | map!(caseless_tag!("="), |_| Operator::Equal)
         | map!(caseless_tag!("<"), |_| Operator::Less)
         | map!(caseless_tag!(">"), |_| Operator::Greater)
    )
);

/// Parse logical operators
named!(pub binary_logical_operator<&[u8], Operator>,
    alt_complete!(
           map!(caseless_tag!("and"), |_| Operator::And)
         | map!(caseless_tag!("or"), |_| Operator::Or)
    )
);

/// Parse unary comparison operators
named!(pub unary_comparison_operator<&[u8], &str>,
    map_res!(
        alt_complete!(
               tag_s!(b"ISNULL")
             | tag_s!(b"NOT")
             | tag_s!(b"-") // ??? (number neg)
        ),
        str::from_utf8
    )
);

/// Parse unary comparison operators
named!(pub unary_negation_operator<&[u8], Operator>,
    alt_complete!(
          map!(caseless_tag!("not"), |_| Operator::Not)
        | map!(caseless_tag!("!"), |_| Operator::Not)
    )
);

/// Parse rule for AS-based aliases for SQL entities.
named!(pub as_alias<&[u8], &str>,
    complete!(
        chain!(
            multispace ~
            caseless_tag!("as") ~
            multispace ~
            alias: map_res!(sql_identifier, str::from_utf8),
            || { alias }
        )
    )
);

/// Parse rule for a comma-separated list.
named!(pub field_list<&[u8], Vec<Column> >,
       many0!(
           chain!(
               fieldname: column_identifier ~
               opt!(
                   complete!(chain!(
                       multispace? ~
                       tag!(",") ~
                       multispace?,
                       ||{}
                   ))
               ),
               || { fieldname }
           )
       )
);

/// Parse list of columns/fields.
/// XXX(malte): add support for named table notation
named!(pub field_expr<&[u8], FieldExpression>,
       alt_complete!(
           tag!("*") => { |_| FieldExpression::All }
         | map!(field_list, |v| FieldExpression::Seq(v))
       )
);

/// Parse list of table names.
/// XXX(malte): add support for aliases
named!(pub table_list<&[u8], Vec<Table> >,
       many0!(
           chain!(
               table: table_reference ~
               opt!(
                   complete!(chain!(
                       multispace? ~
                       tag!(",") ~
                       multispace?,
                       || {}
                   ))
               ),
               || { table }
           )
       )
);

/// Parse a list of values (e.g., for INSERT syntax).
/// XXX(malte): proper value type
named!(pub value_list<&[u8], Vec<&str> >,
       many0!(
           map_res!(
               chain!(
                   val: alt_complete!(
                         tag_s!(b"?")
                       | tag_s!(b"CURRENT_TIMESTAMP")
                       | delimited!(tag!("'"), alphanumeric, tag!("'"))
                       | fp_number
                   ) ~
                   opt!(
                       complete!(chain!(
                           multispace? ~
                           tag!(",") ~
                           multispace?,
                           ||{}
                       ))
                   ),
                   || { val }
               ),
               str::from_utf8
           )
       )
);

/// Parse a reference to a named table
/// XXX(malte): add support for schema.table notation
named!(pub table_reference<&[u8], Table>,
    chain!(
        table: map_res!(sql_identifier, str::from_utf8) ~
        alias: opt!(as_alias),
        || {
            Table {
                name: String::from(table),
                alias: match alias {
                    Some(a) => Some(String::from(a)),
                    None => None,
                }
            }
        }
    )
);

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

    #[test]
    fn sql_identifiers() {
        let id1 = b"foo";
        let id2 = b"f_o_o";
        let id3 = b"foo12";
        let id4 = b":fo oo";
        let id5 = b"primary ";
        let id6 = b"`primary`";

        assert!(sql_identifier(id1).is_done());
        assert!(sql_identifier(id2).is_done());
        assert!(sql_identifier(id3).is_done());
        assert!(sql_identifier(id4).is_err());
        assert!(sql_identifier(id5).is_err());
        assert!(sql_identifier(id6).is_done());
    }

    #[test]
    fn simple_column_function() {
        let qs = b"max(addr_id)";

        let res = column_identifier(qs);
        let expected_fields = FieldExpression::Seq(vec![Column::from("addr_id")]);
        let expected_fn = Some(FunctionExpression::Max(expected_fields));
        let expected = Column {
            name: String::from("anon_fn"),
            table: None,
            function: expected_fn,
        };
        assert_eq!(res.unwrap().1, expected);
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::fs;
use std::io::{Error as IoError, Read, Write};
use std::path::PathBuf;

use ansi_term::{Color, Style};
use app_dirs::{get_app_root, AppDataType};
use log::debug;
use serde_derive::{Deserialize, Serialize};
use toml;

use crate::error::TealdeerError::{self, ConfigError};

pub const CONFIG_FILE_NAME: &str = "config.toml";

fn default_underline() -> bool {
    false
}

fn default_bold() -> bool {
    false
}

#[serde(rename_all = "lowercase")]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
pub enum RawColor {
    Black,
    Red,
    Green,
    Yellow,
    Blue,
    Purple,
    Cyan,
    White,
}

impl From<RawColor> for Color {
    fn from(raw_color: RawColor) -> Self {
        match raw_color {
            RawColor::Black => Color::Black,
            RawColor::Red => Color::Red,
            RawColor::Green => Color::Green,
            RawColor::Yellow => Color::Yellow,
            RawColor::Blue => Color::Blue,
            RawColor::Purple => Color::Purple,
            RawColor::Cyan => Color::Cyan,
            RawColor::White => Color::White,
        }
    }
}

#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
struct RawStyle {
    pub foreground: Option<RawColor>,
    pub background: Option<RawColor>,
    #[serde(default = "default_underline")]
    pub underline: bool,
    #[serde(default = "default_bold")]
    pub bold: bool,
}

impl Default for RawStyle {
    fn default() -> Self {
        Self {
            foreground: None,
            background: None,
            underline: false,
            bold: false,
        }
    }
} // impl RawStyle

impl From<RawStyle> for Style {
    fn from(raw_style: RawStyle) -> Self {
        let mut style = Self::default();

        if let Some(foreground) = raw_style.foreground {
            style = style.fg(Color::from(foreground));
        }

        if let Some(background) = raw_style.background {
            style = style.on(Color::from(background));
        }

        if raw_style.underline {
            style = style.underline();
        }

        if raw_style.bold {
            style = style.bold();
        }

        style
    }
}

#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
struct RawStyleConfig {
    #[serde(default)]
    pub description: RawStyle,
    #[serde(default)]
    pub command_name: RawStyle,
    #[serde(default)]
    pub example_text: RawStyle,
    #[serde(default)]
    pub example_code: RawStyle,
    #[serde(default)]
    pub example_variable: RawStyle,
}

#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
struct RawDisplayConfig {
    #[serde(default)]
    pub use_pager: bool,
}

#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
struct RawConfig {
    #[serde(default)]
    style: RawStyleConfig,
    #[serde(default)]
    display: RawDisplayConfig,
}

impl RawConfig {
    fn new() -> Self {
        let mut raw_config = Self::default();

        // Set default config
        raw_config.style.example_text.foreground = Some(RawColor::Green);
        raw_config.style.command_name.foreground = Some(RawColor::Cyan);
        raw_config.style.example_code.foreground = Some(RawColor::Cyan);
        raw_config.style.example_variable.foreground = Some(RawColor::Cyan);
        raw_config.style.example_variable.underline = true;
        raw_config.display.use_pager = false;

        raw_config
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct StyleConfig {
    pub description: Style,
    pub command_name: Style,
    pub example_text: Style,
    pub example_code: Style,
    pub example_variable: Style,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct DisplayConfig {
    pub use_pager: bool,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Config {
    pub style: StyleConfig,
    pub display: DisplayConfig,
}

impl From<RawConfig> for Config {
    fn from(raw_config: RawConfig) -> Self {
        Self {
            style: StyleConfig {
                command_name: raw_config.style.command_name.into(),
                description: raw_config.style.description.into(),
                example_text: raw_config.style.example_text.into(),
                example_code: raw_config.style.example_code.into(),
                example_variable: raw_config.style.example_variable.into(),
            },
            display: DisplayConfig {
                use_pager: raw_config.display.use_pager,
            },
        }
    }
}

#[allow(clippy::needless_pass_by_value)]
fn map_io_err_to_config_err(e: IoError) -> TealdeerError {
    ConfigError(format!("Io Error: {}", e))
}

impl Config {
    pub fn load(enable_styles: bool) -> Result<Self, TealdeerError> {
        debug!("Loading config");

        // Determine path
        let config_file_path = get_config_path()
            .map_err(|e| ConfigError(format!("Could not determine config path: {}", e)))?;

        // Load raw config
        let raw_config: RawConfig = if config_file_path.exists() && config_file_path.is_file() {
            let mut config_file =
                fs::File::open(config_file_path).map_err(map_io_err_to_config_err)?;
            let mut contents = String::new();
            let _ = config_file
                .read_to_string(&mut contents)
                .map_err(map_io_err_to_config_err)?;
            toml::from_str(&contents)
                .map_err(|err| ConfigError(format!("Failed to parse config file: {}", err)))?
        } else {
            RawConfig::new()
        };

        // Convert to config
        let mut config = Self::from(raw_config);

        // Potentially override styles
        if !enable_styles {
            config.style = StyleConfig {
                command_name: Style::default(),
                description: Style::default(),
                example_text: Style::default(),
                example_code: Style::default(),
                example_variable: Style::default(),
            };
        }

        Ok(config)
    }
}

/// Return the path to the config directory.
///
/// The config dir path can be overridden using the `TEALDEER_CONFIG_DIR` env
/// variable. Otherwise, the user config directory is returned.
///
/// Note that this function does not verify whether the directory at that
/// loation exists, or is a directory.
pub fn get_config_dir() -> Result<PathBuf, TealdeerError> {
    // Allow overriding the config directory by setting the
    // $TEALDEER_CONFIG_DIR env variable.
    if let Ok(value) = env::var("TEALDEER_CONFIG_DIR") {
        return Ok(PathBuf::from(value));
    };

    // Otherwise, fall back to the user config directory.
    match get_app_root(AppDataType::UserConfig, &crate::APP_INFO) {
        Ok(dirs) => Ok(dirs),
        Err(_) => Err(ConfigError(
            "Could not determine the user config directory.".into(),
        )),
    }
}

/// Return the path to the config file.
///
/// Note that this function does not verify whether the file at that location
/// exists, or is a file.
pub fn get_config_path() -> Result<PathBuf, TealdeerError> {
    let config_dir = get_config_dir()?;
    let config_file_path = config_dir.join(CONFIG_FILE_NAME);
    Ok(config_file_path)
}

/// Create default config file.
pub fn make_default_config() -> Result<PathBuf, TealdeerError> {
    let config_dir = get_config_dir()?;

    // Ensure that config directory exists
    if !config_dir.exists() {
        if let Err(e) = fs::create_dir_all(&config_dir) {
            return Err(ConfigError(format!(
                "Could not create config directory: {}",
                e
            )));
        }
    } else if !config_dir.is_dir() {
        return Err(ConfigError(format!(
            "Config directory could not be created: {} already exists but is not a directory",
            config_dir.to_string_lossy(),
        )));
    }

    // Ensure that a config file doesn't get overwritten
    let config_file_path = config_dir.join(CONFIG_FILE_NAME);
    if config_file_path.is_file() {
        return Err(ConfigError(format!(
            "A configuration file already exists at {}, no action was taken.",
            config_file_path.to_str().unwrap()
        )));
    }

    // Create default config
    let serialized_config = toml::to_string(&RawConfig::new())
        .map_err(|err| ConfigError(format!("Failed to serialize default config: {}", err)))?;

    // Write default config
    let mut config_file = fs::File::create(&config_file_path).map_err(map_io_err_to_config_err)?;
    let _wc = config_file
        .write(serialized_config.as_bytes())
        .map_err(map_io_err_to_config_err)?;

    Ok(config_file_path)
}

#[test]
fn test_serialize_deserialize() {
    let raw_config = RawConfig::new();
    let serialized = toml::to_string(&raw_config).unwrap();
    let deserialized: RawConfig = toml::from_str(&serialized).unwrap();
    assert_eq!(raw_config, deserialized);
}
<commit_msg>Add config field for compact output<commit_after>use std::env;
use std::fs;
use std::io::{Error as IoError, Read, Write};
use std::path::PathBuf;

use ansi_term::{Color, Style};
use app_dirs::{get_app_root, AppDataType};
use log::debug;
use serde_derive::{Deserialize, Serialize};
use toml;

use crate::error::TealdeerError::{self, ConfigError};

pub const CONFIG_FILE_NAME: &str = "config.toml";

fn default_underline() -> bool {
    false
}

fn default_bold() -> bool {
    false
}

#[serde(rename_all = "lowercase")]
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
pub enum RawColor {
    Black,
    Red,
    Green,
    Yellow,
    Blue,
    Purple,
    Cyan,
    White,
}

impl From<RawColor> for Color {
    fn from(raw_color: RawColor) -> Self {
        match raw_color {
            RawColor::Black => Color::Black,
            RawColor::Red => Color::Red,
            RawColor::Green => Color::Green,
            RawColor::Yellow => Color::Yellow,
            RawColor::Blue => Color::Blue,
            RawColor::Purple => Color::Purple,
            RawColor::Cyan => Color::Cyan,
            RawColor::White => Color::White,
        }
    }
}

#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
struct RawStyle {
    pub foreground: Option<RawColor>,
    pub background: Option<RawColor>,
    #[serde(default = "default_underline")]
    pub underline: bool,
    #[serde(default = "default_bold")]
    pub bold: bool,
}

impl Default for RawStyle {
    fn default() -> Self {
        Self {
            foreground: None,
            background: None,
            underline: false,
            bold: false,
        }
    }
} // impl RawStyle

impl From<RawStyle> for Style {
    fn from(raw_style: RawStyle) -> Self {
        let mut style = Self::default();

        if let Some(foreground) = raw_style.foreground {
            style = style.fg(Color::from(foreground));
        }

        if let Some(background) = raw_style.background {
            style = style.on(Color::from(background));
        }

        if raw_style.underline {
            style = style.underline();
        }

        if raw_style.bold {
            style = style.bold();
        }

        style
    }
}

#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
struct RawStyleConfig {
    #[serde(default)]
    pub description: RawStyle,
    #[serde(default)]
    pub command_name: RawStyle,
    #[serde(default)]
    pub example_text: RawStyle,
    #[serde(default)]
    pub example_code: RawStyle,
    #[serde(default)]
    pub example_variable: RawStyle,
}

#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
struct RawDisplayConfig {
    #[serde(default)]
    pub compact: bool,
    #[serde(default)]
    pub use_pager: bool,
}

#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
struct RawConfig {
    #[serde(default)]
    style: RawStyleConfig,
    #[serde(default)]
    display: RawDisplayConfig,
}

impl RawConfig {
    fn new() -> Self {
        let mut raw_config = Self::default();

        // Set default config
        raw_config.style.example_text.foreground = Some(RawColor::Green);
        raw_config.style.command_name.foreground = Some(RawColor::Cyan);
        raw_config.style.example_code.foreground = Some(RawColor::Cyan);
        raw_config.style.example_variable.foreground = Some(RawColor::Cyan);
        raw_config.style.example_variable.underline = true;
        raw_config.display.use_pager = false;

        raw_config
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct StyleConfig {
    pub description: Style,
    pub command_name: Style,
    pub example_text: Style,
    pub example_code: Style,
    pub example_variable: Style,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct DisplayConfig {
    pub compact: bool,
    pub use_pager: bool,
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Config {
    pub style: StyleConfig,
    pub display: DisplayConfig,
}

impl From<RawConfig> for Config {
    fn from(raw_config: RawConfig) -> Self {
        Self {
            style: StyleConfig {
                command_name: raw_config.style.command_name.into(),
                description: raw_config.style.description.into(),
                example_text: raw_config.style.example_text.into(),
                example_code: raw_config.style.example_code.into(),
                example_variable: raw_config.style.example_variable.into(),
            },
            display: DisplayConfig {
                compact: raw_config.display.compact,
                use_pager: raw_config.display.use_pager,
            },
        }
    }
}

#[allow(clippy::needless_pass_by_value)]
fn map_io_err_to_config_err(e: IoError) -> TealdeerError {
    ConfigError(format!("Io Error: {}", e))
}

impl Config {
    pub fn load(enable_styles: bool) -> Result<Self, TealdeerError> {
        debug!("Loading config");

        // Determine path
        let config_file_path = get_config_path()
            .map_err(|e| ConfigError(format!("Could not determine config path: {}", e)))?;

        // Load raw config
        let raw_config: RawConfig = if config_file_path.exists() && config_file_path.is_file() {
            let mut config_file =
                fs::File::open(config_file_path).map_err(map_io_err_to_config_err)?;
            let mut contents = String::new();
            let _ = config_file
                .read_to_string(&mut contents)
                .map_err(map_io_err_to_config_err)?;
            toml::from_str(&contents)
                .map_err(|err| ConfigError(format!("Failed to parse config file: {}", err)))?
        } else {
            RawConfig::new()
        };

        // Convert to config
        let mut config = Self::from(raw_config);

        // Potentially override styles
        if !enable_styles {
            config.style = StyleConfig {
                command_name: Style::default(),
                description: Style::default(),
                example_text: Style::default(),
                example_code: Style::default(),
                example_variable: Style::default(),
            };
        }

        Ok(config)
    }
}

/// Return the path to the config directory.
///
/// The config dir path can be overridden using the `TEALDEER_CONFIG_DIR` env
/// variable. Otherwise, the user config directory is returned.
///
/// Note that this function does not verify whether the directory at that
/// loation exists, or is a directory.
pub fn get_config_dir() -> Result<PathBuf, TealdeerError> {
    // Allow overriding the config directory by setting the
    // $TEALDEER_CONFIG_DIR env variable.
    if let Ok(value) = env::var("TEALDEER_CONFIG_DIR") {
        return Ok(PathBuf::from(value));
    };

    // Otherwise, fall back to the user config directory.
    match get_app_root(AppDataType::UserConfig, &crate::APP_INFO) {
        Ok(dirs) => Ok(dirs),
        Err(_) => Err(ConfigError(
            "Could not determine the user config directory.".into(),
        )),
    }
}

/// Return the path to the config file.
///
/// Note that this function does not verify whether the file at that location
/// exists, or is a file.
pub fn get_config_path() -> Result<PathBuf, TealdeerError> {
    let config_dir = get_config_dir()?;
    let config_file_path = config_dir.join(CONFIG_FILE_NAME);
    Ok(config_file_path)
}

/// Create default config file.
pub fn make_default_config() -> Result<PathBuf, TealdeerError> {
    let config_dir = get_config_dir()?;

    // Ensure that config directory exists
    if !config_dir.exists() {
        if let Err(e) = fs::create_dir_all(&config_dir) {
            return Err(ConfigError(format!(
                "Could not create config directory: {}",
                e
            )));
        }
    } else if !config_dir.is_dir() {
        return Err(ConfigError(format!(
            "Config directory could not be created: {} already exists but is not a directory",
            config_dir.to_string_lossy(),
        )));
    }

    // Ensure that a config file doesn't get overwritten
    let config_file_path = config_dir.join(CONFIG_FILE_NAME);
    if config_file_path.is_file() {
        return Err(ConfigError(format!(
            "A configuration file already exists at {}, no action was taken.",
            config_file_path.to_str().unwrap()
        )));
    }

    // Create default config
    let serialized_config = toml::to_string(&RawConfig::new())
        .map_err(|err| ConfigError(format!("Failed to serialize default config: {}", err)))?;

    // Write default config
    let mut config_file = fs::File::create(&config_file_path).map_err(map_io_err_to_config_err)?;
    let _wc = config_file
        .write(serialized_config.as_bytes())
        .map_err(map_io_err_to_config_err)?;

    Ok(config_file_path)
}

#[test]
fn test_serialize_deserialize() {
    let raw_config = RawConfig::new();
    let serialized = toml::to_string(&raw_config).unwrap();
    let deserialized: RawConfig = toml::from_str(&serialized).unwrap();
    assert_eq!(raw_config, deserialized);
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::borrow::Cow;
use clap::ArgMatches;
use util;

#[derive(Debug, Clone)]
pub struct Config<'a> {
    pub install_dir: PathBuf,
    pub shim_dir: PathBuf,
    pub versions_dir: PathBuf,
    pub arch: Option<Cow<'a, str>>,
    pub version: Option<&'a str>,
    pub build_conf: PathBuf,
}

impl<'a> Default for Config<'a> {
    fn default() -> Config<'a> {
        Config {
            install_dir: PathBuf::from(""),
            shim_dir: PathBuf::from(""),
            versions_dir: PathBuf::from(""),
            arch: None,
            version: None,
            build_conf: PathBuf::from(""),
        }
    }
}

impl<'a> Config<'a> {
    pub fn new() -> Config<'a> {
        let install_dir = util::obtain_install_base_path();
        let shim_dir = install_dir.join("shims").join("bin");
        let groonga_versioned_dir = util::obtain_groonga_versioned_path();
        let build_conf = install_dir.join("build.toml");
        Config {
            install_dir: install_dir,
            shim_dir: shim_dir,
            versions_dir: groonga_versioned_dir,
            build_conf: build_conf,
            ..Config::default()
        }
    }

    pub fn from_matches(m: &'a ArgMatches) -> Config<'a> {
        let install_dir = util::obtain_install_base_path();
        let shim_dir = install_dir.join("shims").join("bin");
        let groonga_versioned_dir = util::obtain_groonga_versioned_path();
        let version = m.value_of("VERSION");
        let default_arch = util::obtain_arch().expect("Unsupported architecture.");
        let arch = match m.value_of("arch").unwrap_or(&*default_arch) {
            "x64" | "x86_64" => Some(Cow::Borrowed("x64")),
            "x86" | "i686" => Some(Cow::Borrowed("x86")),
            _ => None,
        };
        let build_conf = install_dir.join("build.toml");
        Config {
            install_dir: install_dir,
            shim_dir: shim_dir,
            versions_dir: groonga_versioned_dir,
            arch: arch,
            version: version,
            build_conf: build_conf,
        }
    }
}
<commit_msg>config: Add Config::new() test case<commit_after>use std::path::PathBuf;
use std::borrow::Cow;
use clap::ArgMatches;
use util;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Config<'a> {
    pub install_dir: PathBuf,
    pub shim_dir: PathBuf,
    pub versions_dir: PathBuf,
    pub arch: Option<Cow<'a, str>>,
    pub version: Option<&'a str>,
    pub build_conf: PathBuf,
}

impl<'a> Default for Config<'a> {
    fn default() -> Config<'a> {
        Config {
            install_dir: PathBuf::from(""),
            shim_dir: PathBuf::from(""),
            versions_dir: PathBuf::from(""),
            arch: None,
            version: None,
            build_conf: PathBuf::from(""),
        }
    }
}

impl<'a> Config<'a> {
    pub fn new() -> Config<'a> {
        let install_dir = util::obtain_install_base_path();
        let shim_dir = install_dir.join("shims").join("bin");
        let groonga_versioned_dir = util::obtain_groonga_versioned_path();
        let build_conf = install_dir.join("build.toml");
        Config {
            install_dir: install_dir,
            shim_dir: shim_dir,
            versions_dir: groonga_versioned_dir,
            build_conf: build_conf,
            ..Config::default()
        }
    }

    pub fn from_matches(m: &'a ArgMatches) -> Config<'a> {
        let install_dir = util::obtain_install_base_path();
        let shim_dir = install_dir.join("shims").join("bin");
        let groonga_versioned_dir = util::obtain_groonga_versioned_path();
        let version = m.value_of("VERSION");
        let default_arch = util::obtain_arch().expect("Unsupported architecture.");
        let arch = match m.value_of("arch").unwrap_or(&*default_arch) {
            "x64" | "x86_64" => Some(Cow::Borrowed("x64")),
            "x86" | "i686" => Some(Cow::Borrowed("x86")),
            _ => None,
        };
        let build_conf = install_dir.join("build.toml");
        Config {
            install_dir: install_dir,
            shim_dir: shim_dir,
            versions_dir: groonga_versioned_dir,
            arch: arch,
            version: version,
            build_conf: build_conf,
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::env;
    use std::path::PathBuf;

    #[cfg(target_os = "linux")]
    fn stub_home() -> &'static str {
        "/home/grnenv"
    }
    #[cfg(target_os = "macos")]
    fn stub_home() -> &'static str {
        "/Users/grnenv"
    }
    #[cfg(target_os = "windows")]
    fn stub_home() -> &'static str {
        "C:\\Users\\grnenv"
    }

    #[test]
    fn test_config() {
        let home = env::home_dir().unwrap();
        let stub_home = stub_home();
        let _ = env::set_var("HOME", stub_home.clone());
        let install_dir = PathBuf::from(stub_home.clone()).join(".groonga");
        let versions_dir = PathBuf::from(stub_home.clone()).join(".groonga").join("versions");
        let shim_dir = PathBuf::from(stub_home.clone()).join(".groonga").join("shims").join("bin");
        let build_conf = PathBuf::from(stub_home.clone()).join(".groonga").join("build.toml");
        let expected = Config {
            install_dir: install_dir,
            shim_dir: shim_dir,
            versions_dir: versions_dir,
            arch: None,
            version: None,
            build_conf: build_conf,
        };
        let config = Config::new();
        assert_eq!(expected, config);
        let _ = env::set_var("HOME", home);
    }
}
<|endoftext|>


<commit_before>use super::dirs::dir_config_create;
use super::error::ConfigError;

extern crate config;
use self::config::reader::from_file;
use self::config::types::{Config, SettingsList};

pub fn load_config(app: &str, file: &str) -> Result<Config, ConfigError> {
    let mut path_buf = try!(dir_config_create(app));
    path_buf.push(file);
    let path = path_buf.as_path();

    if path.exists() {
        let config = try!(from_file(path));
        Ok(config)
    } else {
        Ok(Config::new(SettingsList::new()))
    }
}
<commit_msg>config: use stable function call<commit_after>use super::dirs::dir_config_create;
use super::error::ConfigError;

extern crate config;
use self::config::reader::from_file;
use self::config::types::{Config, SettingsList};

use std::fs::metadata;

pub fn load_config(app: &str, file: &str) -> Result<Config, ConfigError> {
    let mut path_buf = try!(dir_config_create(app));
    path_buf.push(file);
    let path = path_buf.as_path();

    if metadata(path).ok().map_or(false, |m| m.is_file()) {
        let config = try!(from_file(path));
        Ok(config)
    } else {
        Ok(Config::new(SettingsList::new()))
    }
}
<|endoftext|>


<commit_before>use std::fmt::{Display, Formatter, Result};
use num_cpus;
use types::{CoordSum, Depth};

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum UcbType {
  Ucb1,
  Ucb1Tuned
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum UctKomiType {
  None,
  Static,
  Dynamic
}

impl Display for UctKomiType {
  fn fmt(&self, f: &mut Formatter) -> Result {
    match self {
      &UctKomiType::None => write!(f, "None"),
      &UctKomiType::Static => write!(f, "Static"),
      &UctKomiType::Dynamic => write!(f, "Dynamic")
    }
  }
}

static UCT_RADIUS: CoordSum = 3;

static UCB_TYPE: UcbType = UcbType::Ucb1Tuned;

static UCT_DRAW_WEIGHT: f32 = 0.4;

static UCTK: f32 = 1.0;

static UCT_WHEN_CREATE_CHILDREN: usize = 2;

static UCT_DEPTH: Depth = 8;

static mut THREADS_COUNT: usize = 4;

static UCT_KOMI_TYPE: UctKomiType = UctKomiType::Static;

static UCT_RED: f32 = 0.45;

static UCT_GREEN: f32 = 0.5;

static UCT_KOMI_MIN_ITERATIONS: usize = 1000;

pub fn init() {
  unsafe {
    THREADS_COUNT = num_cpus::get();
  }
}

#[inline]
pub fn uct_radius() -> CoordSum {
  UCT_RADIUS
}

#[inline]
pub fn ucb_type() -> UcbType {
  UCB_TYPE
}

#[inline]
pub fn uct_draw_weight() -> f32 {
  UCT_DRAW_WEIGHT
}

#[inline]
pub fn uctk() -> f32 {
  UCTK
}

#[inline]
pub fn uct_when_create_children() -> usize {
  UCT_WHEN_CREATE_CHILDREN
}

#[inline]
pub fn uct_depth() -> Depth {
  UCT_DEPTH
}

#[inline]
pub fn threads_count() -> usize {
  unsafe { THREADS_COUNT }
}

#[inline]
pub fn uct_komi_type() -> UctKomiType {
  UCT_KOMI_TYPE
}

#[inline]
pub fn uct_red() -> f32 {
  UCT_RED
}

#[inline]
pub fn uct_green() -> f32 {
  UCT_GREEN
}

#[inline]
pub fn uct_komi_min_iterations() -> usize {
  UCT_KOMI_MIN_ITERATIONS
}
<commit_msg>Small addition.<commit_after>use std::fmt::{Display, Formatter, Result};
use num_cpus;
use types::{CoordSum, Depth};

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum UcbType {
  Ucb1,
  Ucb1Tuned
}

impl Display for UcbType {
  fn fmt(&self, f: &mut Formatter) -> Result {
    match self {
      &UcbType::Ucb1 => write!(f, "Ucb1"),
      &UcbType::Ucb1Tuned => write!(f, "Ucb1Tuned")
    }
  }
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum UctKomiType {
  None,
  Static,
  Dynamic
}

impl Display for UctKomiType {
  fn fmt(&self, f: &mut Formatter) -> Result {
    match self {
      &UctKomiType::None => write!(f, "None"),
      &UctKomiType::Static => write!(f, "Static"),
      &UctKomiType::Dynamic => write!(f, "Dynamic")
    }
  }
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum Solver {
  Uct,
  Heuristic
}

impl Display for Solver {
  fn fmt(&self, f: &mut Formatter) -> Result {
    match self {
      &Solver::Uct => write!(f, "Uct"),
      &Solver::Heuristic => write!(f, "Heuristic")
    }
  }
}

static UCT_RADIUS: CoordSum = 3;

static UCB_TYPE: UcbType = UcbType::Ucb1Tuned;

static UCT_DRAW_WEIGHT: f32 = 0.4;

static UCTK: f32 = 1.0;

static UCT_WHEN_CREATE_CHILDREN: usize = 2;

static UCT_DEPTH: Depth = 8;

static mut THREADS_COUNT: usize = 4;

static UCT_KOMI_TYPE: UctKomiType = UctKomiType::Static;

static UCT_RED: f32 = 0.45;

static UCT_GREEN: f32 = 0.5;

static UCT_KOMI_MIN_ITERATIONS: usize = 1000;

pub fn init() {
  unsafe {
    THREADS_COUNT = num_cpus::get();
  }
}

#[inline]
pub fn uct_radius() -> CoordSum {
  UCT_RADIUS
}

#[inline]
pub fn ucb_type() -> UcbType {
  UCB_TYPE
}

#[inline]
pub fn uct_draw_weight() -> f32 {
  UCT_DRAW_WEIGHT
}

#[inline]
pub fn uctk() -> f32 {
  UCTK
}

#[inline]
pub fn uct_when_create_children() -> usize {
  UCT_WHEN_CREATE_CHILDREN
}

#[inline]
pub fn uct_depth() -> Depth {
  UCT_DEPTH
}

#[inline]
pub fn threads_count() -> usize {
  unsafe { THREADS_COUNT }
}

#[inline]
pub fn uct_komi_type() -> UctKomiType {
  UCT_KOMI_TYPE
}

#[inline]
pub fn uct_red() -> f32 {
  UCT_RED
}

#[inline]
pub fn uct_green() -> f32 {
  UCT_GREEN
}

#[inline]
pub fn uct_komi_min_iterations() -> usize {
  UCT_KOMI_MIN_ITERATIONS
}
<|endoftext|>