<commit_before>//! Snapshot testing library, see
//! https://github.com/rust-analyzer/rust-analyzer/pull/5101
use std::{
    collections::HashMap,
    env, fmt, fs, mem,
    ops::Range,
    panic,
    path::{Path, PathBuf},
    sync::Mutex,
};

use difference::Changeset;
use once_cell::sync::Lazy;
use stdx::{lines_with_ends, trim_indent};

const HELP: &str = "
You can update all `expect![[]]` tests by running:

    env UPDATE_EXPECT=1 cargo test

To update a single test, place the cursor on `expect` token and use `run` feature of rust-analyzer.
";

fn update_expect() -> bool {
    env::var("UPDATE_EXPECT").is_ok()
}

/// expect![[r#"inline snapshot"#]]
#[macro_export]
macro_rules! expect {
    [[$data:literal]] => {$crate::Expect {
        position: $crate::Position {
            file: file!(),
            line: line!(),
            column: column!(),
        },
        data: $data,
    }};
    [[]] => { $crate::expect![[""]] };
}

/// expect_file!["/crates/foo/test_data/bar.html"]
#[macro_export]
macro_rules! expect_file {
    [$path:literal] => {$crate::ExpectFile { path: $path }};
}

#[derive(Debug)]
pub struct Expect {
    pub position: Position,
    pub data: &'static str,
}

#[derive(Debug)]
pub struct ExpectFile {
    pub path: &'static str,
}

#[derive(Debug)]
pub struct Position {
    pub file: &'static str,
    pub line: u32,
    pub column: u32,
}

impl fmt::Display for Position {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}:{}:{}", self.file, self.line, self.column)
    }
}

impl Expect {
    pub fn assert_eq(&self, actual: &str) {
        let trimmed = self.trimmed();
        if &trimmed == actual {
            return;
        }
        Runtime::fail_expect(self, &trimmed, actual);
    }
    pub fn assert_debug_eq(&self, actual: &impl fmt::Debug) {
        let actual = format!("{:#?}\n", actual);
        self.assert_eq(&actual)
    }

    fn trimmed(&self) -> String {
        if !self.data.contains('\n') {
            return self.data.to_string();
        }
        trim_indent(self.data)
    }

    fn locate(&self, file: &str) -> Location {
        let mut target_line = None;
        let mut line_start = 0;
        for (i, line) in lines_with_ends(file).enumerate() {
            if i == self.position.line as usize - 1 {
                let pat = "expect![[";
                let offset = line.find(pat).unwrap();
                let literal_start = line_start + offset + pat.len();
                let indent = line.chars().take_while(|&it| it == ' ').count();
                target_line = Some((literal_start, indent));
                break;
            }
            line_start += line.len();
        }
        let (literal_start, line_indent) = target_line.unwrap();
        let literal_length =
            file[literal_start..].find("]]").expect("Couldn't find matching `]]` for `expect![[`.");
        let literal_range = literal_start..literal_start + literal_length;
        Location { line_indent, literal_range }
    }
}

impl ExpectFile {
    pub fn assert_eq(&self, actual: &str) {
        let expected = self.read();
        if actual == expected {
            return;
        }
        Runtime::fail_file(self, &expected, actual);
    }
    fn read(&self) -> String {
        fs::read_to_string(self.abs_path()).unwrap_or_default().replace("\r\n", "\n")
    }
    fn write(&self, contents: &str) {
        fs::write(self.abs_path(), contents).unwrap()
    }
    fn abs_path(&self) -> PathBuf {
        workspace_root().join(self.path)
    }
}

#[derive(Default)]
struct Runtime {
    help_printed: bool,
    per_file: HashMap<&'static str, FileRuntime>,
}
static RT: Lazy<Mutex<Runtime>> = Lazy::new(Default::default);

impl Runtime {
    fn fail_expect(expect: &Expect, expected: &str, actual: &str) {
        let mut rt = RT.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
        if update_expect() {
            println!("\x1b[1m\x1b[92mupdating\x1b[0m: {}", expect.position);
            rt.per_file
                .entry(expect.position.file)
                .or_insert_with(|| FileRuntime::new(expect))
                .update(expect, actual);
            return;
        }
        rt.panic(expect.position.to_string(), expected, actual);
    }

    fn fail_file(expect: &ExpectFile, expected: &str, actual: &str) {
        let mut rt = RT.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
        if update_expect() {
            println!("\x1b[1m\x1b[92mupdating\x1b[0m: {}", expect.path);
            expect.write(actual);
            return;
        }
        rt.panic(expect.path.to_string(), expected, actual);
    }

    fn panic(&mut self, position: String, expected: &str, actual: &str) {
        let print_help = !mem::replace(&mut self.help_printed, true);
        let help = if print_help { HELP } else { "" };

        let diff = Changeset::new(actual, expected, "\n");

        println!(
            "\n
\x1b[1m\x1b[91merror\x1b[97m: expect test failed\x1b[0m
   \x1b[1m\x1b[34m-->\x1b[0m {}
{}
\x1b[1mExpect\x1b[0m:
----
{}
----

\x1b[1mActual\x1b[0m:
----
{}
----

\x1b[1mDiff\x1b[0m:
----
{}
----
",
            position, help, expected, actual, diff
        );
        // Use resume_unwind instead of panic!() to prevent a backtrace, which is unnecessary noise.
        panic::resume_unwind(Box::new(()));
    }
}

struct FileRuntime {
    path: PathBuf,
    original_text: String,
    patchwork: Patchwork,
}

impl FileRuntime {
    fn new(expect: &Expect) -> FileRuntime {
        let path = workspace_root().join(expect.position.file);
        let original_text = fs::read_to_string(&path).unwrap();
        let patchwork = Patchwork::new(original_text.clone());
        FileRuntime { path, original_text, patchwork }
    }
    fn update(&mut self, expect: &Expect, actual: &str) {
        let loc = expect.locate(&self.original_text);
        let patch = format_patch(loc.line_indent.clone(), actual);
        self.patchwork.patch(loc.literal_range, &patch);
        fs::write(&self.path, &self.patchwork.text).unwrap()
    }
}

#[derive(Debug)]
struct Location {
    line_indent: usize,
    literal_range: Range<usize>,
}

#[derive(Debug)]
struct Patchwork {
    text: String,
    indels: Vec<(Range<usize>, usize)>,
}

impl Patchwork {
    fn new(text: String) -> Patchwork {
        Patchwork { text, indels: Vec::new() }
    }
    fn patch(&mut self, mut range: Range<usize>, patch: &str) {
        self.indels.push((range.clone(), patch.len()));
        self.indels.sort_by_key(|(delete, _insert)| delete.start);

        let (delete, insert) = self
            .indels
            .iter()
            .take_while(|(delete, _)| delete.start < range.start)
            .map(|(delete, insert)| (delete.end - delete.start, insert))
            .fold((0usize, 0usize), |(x1, y1), (x2, y2)| (x1 + x2, y1 + y2));

        for pos in &mut [&mut range.start, &mut range.end] {
            **pos -= delete;
            **pos += insert;
        }

        self.text.replace_range(range, &patch);
    }
}

fn format_patch(line_indent: usize, patch: &str) -> String {
    let mut max_hashes = 0;
    let mut cur_hashes = 0;
    for byte in patch.bytes() {
        if byte != b'#' {
            cur_hashes = 0;
            continue;
        }
        cur_hashes += 1;
        max_hashes = max_hashes.max(cur_hashes);
    }
    let hashes = &"#".repeat(max_hashes + 1);
    let indent = &" ".repeat(line_indent);
    let is_multiline = patch.contains('\n');

    let mut buf = String::new();
    buf.push('r');
    buf.push_str(hashes);
    buf.push('"');
    if is_multiline {
        buf.push('\n');
    }
    let mut final_newline = false;
    for line in lines_with_ends(patch) {
        if is_multiline {
            buf.push_str(indent);
            buf.push_str("    ");
        }
        buf.push_str(line);
        final_newline = line.ends_with('\n');
    }
    if final_newline {
        buf.push_str(indent);
    }
    buf.push('"');
    buf.push_str(hashes);
    buf
}

fn workspace_root() -> PathBuf {
    Path::new(
        &env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()),
    )
    .ancestors()
    .nth(2)
    .unwrap()
    .to_path_buf()
}

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

    #[test]
    fn test_format_patch() {
        let patch = format_patch(0, "hello\nworld\n");
        expect![[r##"
            r#"
                hello
                world
            "#"##]]
        .assert_eq(&patch);

        let patch = format_patch(4, "single line");
        expect![[r##"r#"single line"#"##]].assert_eq(&patch);
    }

    #[test]
    fn test_patchwork() {
        let mut patchwork = Patchwork::new("one two three".to_string());
        patchwork.patch(4..7, "zwei");
        patchwork.patch(0..3, "один");
        patchwork.patch(8..13, "3");
        expect![[r#"
            Patchwork {
                text: "один zwei 3",
                indels: [
                    (
                        0..3,
                        8,
                    ),
                    (
                        4..7,
                        4,
                    ),
                    (
                        8..13,
                        1,
                    ),
                ],
            }
        "#]]
        .assert_debug_eq(&patchwork);
    }
}
<commit_msg>No blank indent<commit_after>//! Snapshot testing library, see
//! https://github.com/rust-analyzer/rust-analyzer/pull/5101
use std::{
    collections::HashMap,
    env, fmt, fs, mem,
    ops::Range,
    panic,
    path::{Path, PathBuf},
    sync::Mutex,
};

use difference::Changeset;
use once_cell::sync::Lazy;
use stdx::{lines_with_ends, trim_indent};

const HELP: &str = "
You can update all `expect![[]]` tests by running:

    env UPDATE_EXPECT=1 cargo test

To update a single test, place the cursor on `expect` token and use `run` feature of rust-analyzer.
";

fn update_expect() -> bool {
    env::var("UPDATE_EXPECT").is_ok()
}

/// expect![[r#"inline snapshot"#]]
#[macro_export]
macro_rules! expect {
    [[$data:literal]] => {$crate::Expect {
        position: $crate::Position {
            file: file!(),
            line: line!(),
            column: column!(),
        },
        data: $data,
    }};
    [[]] => { $crate::expect![[""]] };
}

/// expect_file!["/crates/foo/test_data/bar.html"]
#[macro_export]
macro_rules! expect_file {
    [$path:literal] => {$crate::ExpectFile { path: $path }};
}

#[derive(Debug)]
pub struct Expect {
    pub position: Position,
    pub data: &'static str,
}

#[derive(Debug)]
pub struct ExpectFile {
    pub path: &'static str,
}

#[derive(Debug)]
pub struct Position {
    pub file: &'static str,
    pub line: u32,
    pub column: u32,
}

impl fmt::Display for Position {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}:{}:{}", self.file, self.line, self.column)
    }
}

impl Expect {
    pub fn assert_eq(&self, actual: &str) {
        let trimmed = self.trimmed();
        if &trimmed == actual {
            return;
        }
        Runtime::fail_expect(self, &trimmed, actual);
    }
    pub fn assert_debug_eq(&self, actual: &impl fmt::Debug) {
        let actual = format!("{:#?}\n", actual);
        self.assert_eq(&actual)
    }

    fn trimmed(&self) -> String {
        if !self.data.contains('\n') {
            return self.data.to_string();
        }
        trim_indent(self.data)
    }

    fn locate(&self, file: &str) -> Location {
        let mut target_line = None;
        let mut line_start = 0;
        for (i, line) in lines_with_ends(file).enumerate() {
            if i == self.position.line as usize - 1 {
                let pat = "expect![[";
                let offset = line.find(pat).unwrap();
                let literal_start = line_start + offset + pat.len();
                let indent = line.chars().take_while(|&it| it == ' ').count();
                target_line = Some((literal_start, indent));
                break;
            }
            line_start += line.len();
        }
        let (literal_start, line_indent) = target_line.unwrap();
        let literal_length =
            file[literal_start..].find("]]").expect("Couldn't find matching `]]` for `expect![[`.");
        let literal_range = literal_start..literal_start + literal_length;
        Location { line_indent, literal_range }
    }
}

impl ExpectFile {
    pub fn assert_eq(&self, actual: &str) {
        let expected = self.read();
        if actual == expected {
            return;
        }
        Runtime::fail_file(self, &expected, actual);
    }
    fn read(&self) -> String {
        fs::read_to_string(self.abs_path()).unwrap_or_default().replace("\r\n", "\n")
    }
    fn write(&self, contents: &str) {
        fs::write(self.abs_path(), contents).unwrap()
    }
    fn abs_path(&self) -> PathBuf {
        workspace_root().join(self.path)
    }
}

#[derive(Default)]
struct Runtime {
    help_printed: bool,
    per_file: HashMap<&'static str, FileRuntime>,
}
static RT: Lazy<Mutex<Runtime>> = Lazy::new(Default::default);

impl Runtime {
    fn fail_expect(expect: &Expect, expected: &str, actual: &str) {
        let mut rt = RT.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
        if update_expect() {
            println!("\x1b[1m\x1b[92mupdating\x1b[0m: {}", expect.position);
            rt.per_file
                .entry(expect.position.file)
                .or_insert_with(|| FileRuntime::new(expect))
                .update(expect, actual);
            return;
        }
        rt.panic(expect.position.to_string(), expected, actual);
    }

    fn fail_file(expect: &ExpectFile, expected: &str, actual: &str) {
        let mut rt = RT.lock().unwrap_or_else(|poisoned| poisoned.into_inner());
        if update_expect() {
            println!("\x1b[1m\x1b[92mupdating\x1b[0m: {}", expect.path);
            expect.write(actual);
            return;
        }
        rt.panic(expect.path.to_string(), expected, actual);
    }

    fn panic(&mut self, position: String, expected: &str, actual: &str) {
        let print_help = !mem::replace(&mut self.help_printed, true);
        let help = if print_help { HELP } else { "" };

        let diff = Changeset::new(actual, expected, "\n");

        println!(
            "\n
\x1b[1m\x1b[91merror\x1b[97m: expect test failed\x1b[0m
   \x1b[1m\x1b[34m-->\x1b[0m {}
{}
\x1b[1mExpect\x1b[0m:
----
{}
----

\x1b[1mActual\x1b[0m:
----
{}
----

\x1b[1mDiff\x1b[0m:
----
{}
----
",
            position, help, expected, actual, diff
        );
        // Use resume_unwind instead of panic!() to prevent a backtrace, which is unnecessary noise.
        panic::resume_unwind(Box::new(()));
    }
}

struct FileRuntime {
    path: PathBuf,
    original_text: String,
    patchwork: Patchwork,
}

impl FileRuntime {
    fn new(expect: &Expect) -> FileRuntime {
        let path = workspace_root().join(expect.position.file);
        let original_text = fs::read_to_string(&path).unwrap();
        let patchwork = Patchwork::new(original_text.clone());
        FileRuntime { path, original_text, patchwork }
    }
    fn update(&mut self, expect: &Expect, actual: &str) {
        let loc = expect.locate(&self.original_text);
        let patch = format_patch(loc.line_indent.clone(), actual);
        self.patchwork.patch(loc.literal_range, &patch);
        fs::write(&self.path, &self.patchwork.text).unwrap()
    }
}

#[derive(Debug)]
struct Location {
    line_indent: usize,
    literal_range: Range<usize>,
}

#[derive(Debug)]
struct Patchwork {
    text: String,
    indels: Vec<(Range<usize>, usize)>,
}

impl Patchwork {
    fn new(text: String) -> Patchwork {
        Patchwork { text, indels: Vec::new() }
    }
    fn patch(&mut self, mut range: Range<usize>, patch: &str) {
        self.indels.push((range.clone(), patch.len()));
        self.indels.sort_by_key(|(delete, _insert)| delete.start);

        let (delete, insert) = self
            .indels
            .iter()
            .take_while(|(delete, _)| delete.start < range.start)
            .map(|(delete, insert)| (delete.end - delete.start, insert))
            .fold((0usize, 0usize), |(x1, y1), (x2, y2)| (x1 + x2, y1 + y2));

        for pos in &mut [&mut range.start, &mut range.end] {
            **pos -= delete;
            **pos += insert;
        }

        self.text.replace_range(range, &patch);
    }
}

fn format_patch(line_indent: usize, patch: &str) -> String {
    let mut max_hashes = 0;
    let mut cur_hashes = 0;
    for byte in patch.bytes() {
        if byte != b'#' {
            cur_hashes = 0;
            continue;
        }
        cur_hashes += 1;
        max_hashes = max_hashes.max(cur_hashes);
    }
    let hashes = &"#".repeat(max_hashes + 1);
    let indent = &" ".repeat(line_indent);
    let is_multiline = patch.contains('\n');

    let mut buf = String::new();
    buf.push('r');
    buf.push_str(hashes);
    buf.push('"');
    if is_multiline {
        buf.push('\n');
    }
    let mut final_newline = false;
    for line in lines_with_ends(patch) {
        if is_multiline && !line.trim().is_empty() {
            buf.push_str(indent);
            buf.push_str("    ");
        }
        buf.push_str(line);
        final_newline = line.ends_with('\n');
    }
    if final_newline {
        buf.push_str(indent);
    }
    buf.push('"');
    buf.push_str(hashes);
    buf
}

fn workspace_root() -> PathBuf {
    Path::new(
        &env::var("CARGO_MANIFEST_DIR").unwrap_or_else(|_| env!("CARGO_MANIFEST_DIR").to_owned()),
    )
    .ancestors()
    .nth(2)
    .unwrap()
    .to_path_buf()
}

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

    #[test]
    fn test_format_patch() {
        let patch = format_patch(0, "hello\nworld\n");
        expect![[r##"
            r#"
                hello
                world
            "#"##]]
        .assert_eq(&patch);

        let patch = format_patch(4, "single line");
        expect![[r##"r#"single line"#"##]].assert_eq(&patch);
    }

    #[test]
    fn test_patchwork() {
        let mut patchwork = Patchwork::new("one two three".to_string());
        patchwork.patch(4..7, "zwei");
        patchwork.patch(0..3, "один");
        patchwork.patch(8..13, "3");
        expect![[r#"
            Patchwork {
                text: "один zwei 3",
                indels: [
                    (
                        0..3,
                        8,
                    ),
                    (
                        4..7,
                        4,
                    ),
                    (
                        8..13,
                        1,
                    ),
                ],
            }
        "#]]
        .assert_debug_eq(&patchwork);
    }
}
<|endoftext|>


<commit_before>use expect_test::expect;
use rustzx_test::framework::{presets, RustZXTester};
use std::time::Duration;

#[test]
fn sound_48k() {
    let mut tester = RustZXTester::new("sound_48k", presets::settings_48k());
    tester.load_sna("sound.48k.sna.gz");
    tester.start_sound_capture();
    tester.emulate_for(Duration::from_secs(2));
    tester.expect_sound(
        "beeper_plus_ay",
        expect![[r#"HPoS7J290tGhhdIMViBIwcW1EgwwRyxcTvViGOQYJC0="#]],
    );
}

#[test]
fn sound_128k() {
    let mut tester = RustZXTester::new("sound_128k", presets::settings_128k());
    tester.load_sna("sound.128k.sna.gz");
    tester.start_sound_capture();
    tester.emulate_for(Duration::from_secs(2));
    tester.expect_sound(
        "beeper_plus_ay",
        expect![[r#"r1Mh8DO3Ci3iF75aYUS8ajCcqAePdd01snEySOv30rM="#]],
    );
}
<commit_msg>Fixed sound tests expected data after z88dk update<commit_after>use expect_test::expect;
use rustzx_test::framework::{presets, RustZXTester};
use std::time::Duration;

#[test]
fn sound_48k() {
    let mut tester = RustZXTester::new("sound_48k", presets::settings_48k());
    tester.load_sna("sound.48k.sna.gz");
    tester.start_sound_capture();
    tester.emulate_for(Duration::from_secs(2));
    tester.expect_sound(
        "beeper_plus_ay",
        expect![[r#"EPGBleJ2tzxSDYEJ1MKxDR4lT3iTdwXX+RHJt0GbZXs="#]],
    );
}

#[test]
fn sound_128k() {
    let mut tester = RustZXTester::new("sound_128k", presets::settings_128k());
    tester.load_sna("sound.128k.sna.gz");
    tester.start_sound_capture();
    tester.emulate_for(Duration::from_secs(2));
    tester.expect_sound(
        "beeper_plus_ay",
        expect![[r#"wyo0bqTXzJucLwWkpinHkBS5jdpJp3AVqmn0+Rolng0="#]],
    );
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use std::rc::Rc;

#[derive(Debug, PartialEq, Clone)]
pub enum CC {
    // condition codes
    E, L, LE, G, GE,
}

#[derive(Debug, Clone)]
pub enum Ast {
    Symbol(Rc<String>),
    Number(i64),
    Bool(bool),
    List(Vec<Ast>),
    FuncName(Rc<String>),  // for closure-conversion

    Define(Rc<String>, Vec<Rc<String>>, Box<Ast>),
    If(Box<Ast>,     // cnd
       Box<Ast>,     // thn
       Box<Ast>),    // els
    Let(Vec<(Rc<String>, Ast)>, Box<Ast>),
    Lambda(Vec<Rc<String>>, Box<Ast>),
    Tuple(Vec<Ast>),
    Cmp(CC, Box<Ast>, Box<Ast>),
    App(Box<Ast>, Vec<Ast>),
    Prog(Vec<Ast>, Box<Ast>),
    Nil,
}

static mut VAR_COUNTER : i32 = 0;
pub fn get_unique_varname(stem: &str) -> String {
    unsafe {
        VAR_COUNTER += 1;
        return stem.to_string() + &VAR_COUNTER.to_string();
    }
}

impl Ast {
    pub fn uniquify(&self, mapping: &mut HashMap<Rc<String>, Rc<String>>) -> Self {
        match self {
            Ast::Symbol(name) => {
                let uniq_name = mapping.get(name)
                    .expect("unbound symbol");
                Ast::Symbol(uniq_name.clone())
            },
            Ast::Number(_) | Ast::Bool(_) => self.clone(),
            Ast::Tuple(elts) => {
                let elts =
                    elts.iter().map(|e| e.uniquify(mapping)).collect();
                Ast::Tuple(elts)
            },
            Ast::Let(bindings, body) => {
                let mut new_bindings = vec![];
                for (k, v) in bindings {
                    let uniq_k = Rc::new(get_unique_varname(&k));
                    new_bindings.push((uniq_k.clone(),
                                       v.uniquify(mapping)));
                    mapping.insert(k.clone(), uniq_k.clone());

                }
                Ast::Let(new_bindings,
                         Box::new(body.uniquify(mapping)))
            },
            Ast::List(elts) => {
                let new_elts : Vec<_> = elts.iter().map(|e| e.uniquify(mapping)).collect();
                Ast::List(new_elts)
            },
            Ast::Cmp(cc, left, right) =>
                return Ast::Cmp(cc.clone(),
                                box left.uniquify(mapping),
                                box right.uniquify(mapping)),
            Ast::Lambda(args, body) => {
                let mut new_args = vec![];
                for arg in args {
                    let new_arg = Rc::new(get_unique_varname(arg));
                    new_args.push(new_arg.clone());
                    mapping.insert(arg.clone(), new_arg.clone());
                }

                 Ast::Lambda(new_args,
                             box body.uniquify(mapping))
            },
            Ast::Define(name, args, val) => {
                let uniq_fname = Rc::new(get_unique_varname(name));
                mapping.insert(name.clone(), uniq_fname.clone());

                let mut new_args = vec![];
                for arg in args {
                    let new_arg = Rc::new(get_unique_varname(arg));
                    new_args.push(new_arg.clone());
                    mapping.insert(arg.clone(), new_arg.clone());
                }

                Ast::Define(uniq_fname.clone(),
                            new_args,
                            box val.uniquify(mapping))
            },
            Ast::If(cond, thn, els) =>
                Ast::If(box (cond.uniquify(mapping)),
                        box (thn.uniquify(mapping)),
                        box (els.uniquify(mapping))),
            Ast::App(f, args) => {
                let new_args : Vec<_> = args.iter()
                    .map(|a| a.uniquify(mapping)).collect();
                Ast::App(box f.uniquify(mapping),
                         new_args)
            },
            Ast::Prog(defs, e) => {
                let new_defs : Vec<_> = defs.iter()
                    .map(|def| def.uniquify(mapping)).collect();
                Ast::Prog(new_defs, box e.uniquify(mapping))
            },
            _ => panic!("NYI"),
        }
    }

    fn get_free_variables(&self,
                          env: &HashSet<Rc<String>>,
                          parent_env: &HashSet<Rc<String>>) -> Vec<Rc<String>> {
        match self {
            Ast::Number(_) => vec![],
            Ast::Symbol(name) => {
                match env.get(name) {
                    Some(_) => vec![],
                    None => {
                        match parent_env.get(name) {
                            Some(_) => vec![name.clone()],
                            None => panic!("no binding found in parent env for free-variable {} env: {:?} parent-env: {:?}", name, env, parent_env),
                        }
                    }
                }
            },
            Ast::If(cnd, thn, els) => {
                let mut cnd_freevars =
                    cnd.get_free_variables(env, parent_env);
                let thn_freevars =
                    thn.get_free_variables(env, parent_env);
                let els_freevars =
                    els.get_free_variables(env, parent_env);

                cnd_freevars.extend_from_slice(&thn_freevars);
                cnd_freevars.extend_from_slice(&els_freevars);

                return cnd_freevars;
            },
            Ast::Define(_, args, body) |
            Ast::Lambda(args, body) => {
                let mut new_parent_env : HashSet<Rc<String>> = HashSet::new()
                    .union(&env).cloned().collect();
                new_parent_env = new_parent_env
                    .union(&parent_env).cloned().collect();

                let new_env : HashSet<Rc<String>> = args.iter().map(|a| a.clone()).collect();

                println!("[lambda] new_env: {:?} new_parent_env: {:?}",
                         new_env,
                         new_parent_env);

                body.get_free_variables(&new_env, &new_parent_env)
            },
            Ast::Let(bindings, body) => {
                let mut new_env = HashSet::new();
                let mut bindings_free_vars = vec![];
                for (k, v) in bindings {
                    let v_freevars : Vec<_> =
                        v.get_free_variables(env, parent_env);
                    new_env.insert(k.clone());
                    bindings_free_vars.extend_from_slice(&v_freevars);
                }

                new_env = new_env.union(&env).cloned().collect();
                let body_freevars : Vec<_> =
                    body.get_free_variables(&new_env,
                                            parent_env);
                bindings_free_vars.extend_from_slice(&body_freevars);

                return bindings_free_vars;
            },
            Ast::App(_, args) => {
                let mut args_freevars = vec![];
                for arg in args {
                    let arg_freevars : Vec<_> =
                        arg.get_free_variables(env,
                                               parent_env);
                    args_freevars.extend_from_slice(&arg_freevars);
                }

                return args_freevars;
            },
            _ => panic!("NYI: {:?}", self),
        }
    }

    fn symbol_is_primitive(sym: &str) -> bool {
        match sym {
            "+" | "-" | "tuple-ref" | "tuple" => true,
            _ => false,
        }
    }

    fn get_define_name(def: &Ast) -> Rc<String> {
        match def {
            Ast::Define(name, _, _) => name.clone(),
            _ => panic!("not a Define"),
        }
    }

    pub fn convert_to_closures(&self, env: &HashSet<Rc<String>>, toplevel_funs: &HashSet<Rc<String>>)
                           -> (Ast, Vec<Ast>) {
        match self {
            Ast::Cmp(_, _, _) |
            Ast::Bool(_) |
            Ast::Symbol(_) |
            Ast::FuncName(_) |
            Ast::Number(_) => (self.clone(), vec![]),
            Ast::If(cnd, thn, els) => {
                let (converted_cnd, mut cnd_defines) =
                    cnd.convert_to_closures(env, toplevel_funs);
                let (converted_thn, thn_defines) =
                    thn.convert_to_closures(env, toplevel_funs);
                let (converted_els, els_defines) =
                    els.convert_to_closures(env, toplevel_funs);

                let converted = Ast::If(box converted_cnd,
                                        box converted_thn,
                                        box converted_els);

                cnd_defines.extend_from_slice(&thn_defines);
                cnd_defines.extend_from_slice(&els_defines);

                return (converted, cnd_defines);
            },
            Ast::Define(name, args, body) => {
                let mut new_args = args.clone();
                let mut new_env = env.clone();

                for arg in args {
                    new_env.insert(arg.clone());
                }
                let (converted_body, body_defines) =
                    body.convert_to_closures(&new_env, toplevel_funs);

                new_args.insert(0, Rc::new("clos".to_string()));

                let converted = Ast::Define(name.clone(),
                                            new_args,
                                            box converted_body);

                return (converted, body_defines);

            },
            Ast::Lambda(args, body) => {
                let mut new_env = HashSet::new();
                let mut new_args = args.clone();
                for arg in args {
                    new_env.insert(arg.clone());
                }

                let (converted_body, mut new_defines) =
                    body.convert_to_closures(&new_env, toplevel_funs);

                let lambda_name = Rc::new(get_unique_varname("lam"));
                let free_vars : Vec<_> = body.get_free_variables(&new_env,
                                                                 env);
                let mut load_free_vars = converted_body;
                for (i, fvar) in free_vars.iter().enumerate() {
                    let bindings = vec![(fvar.clone(),
                                         Ast::App(box Ast::Symbol(Rc::new("tuple-ref".to_string())),
                                                  vec![Ast::Symbol(Rc::new("clos".to_string())),
                                                       Ast::Number((i+1) as i64)]))];
                    load_free_vars =
                        Ast::Let(bindings,
                                 box load_free_vars);
                }

                new_args.insert(0, Rc::new("clos".to_string()));

                let mut closure_elts =
                    vec![Ast::FuncName(lambda_name.clone())];

                let free_vars : Vec<Ast> =
                    free_vars.iter().map(|fv| Ast::Symbol(fv.clone())).collect();
                closure_elts.extend_from_slice(&free_vars[..]);
                let closure = Ast::Tuple(closure_elts);

                new_defines.extend_from_slice(&[
                    Ast::Define(lambda_name.clone(),
                                new_args,
                                box load_free_vars)
                ]);

                return (closure, new_defines);
            },
            Ast::Tuple(elts) => {
                let mut converted_elts = vec![];
                let mut elts_defines = vec![];

                for elt in elts {
                    let (conv_elt, elt_defines) : (Ast, Vec<Ast>) =
                        elt.convert_to_closures(env, toplevel_funs);
                    converted_elts.push(conv_elt);
                    elts_defines.extend_from_slice(&elt_defines);
                }

                let converted = Ast::Tuple(converted_elts);
                return (converted, elts_defines);

            },
            Ast::App(box Ast::Symbol(f), ref args)
                if Self::symbol_is_primitive(f) => {
                    let mut converted_args = vec![];
                    let mut args_defines = vec![];

                    for arg in args.clone() {
                        let (conv_arg, arg_defines) : (Ast, Vec<Ast>) =
                            arg.convert_to_closures(env, toplevel_funs);
                        converted_args.push(conv_arg);
                        args_defines.extend_from_slice(&arg_defines);
                    }

                    let converted = Ast::App(box Ast::Symbol(f.clone()),
                                             converted_args);
                    return (converted, args_defines);
                },
            Ast::App(box Ast::Symbol(f), ref args)
                if !Self::symbol_is_primitive(f) => {
                    let fname = match toplevel_funs.get(f) {
                        Some(_) => Ast::Tuple(vec![Ast::FuncName(f.clone())]),
                        None => Ast::Symbol(f.clone()),
                    };

                    let (fclos, fdefines) : (Ast, Vec<Ast>) =
                        fname.convert_to_closures(env, toplevel_funs);
                    let f_temp = Rc::new(get_unique_varname("tmp"));

                    let mut converted_args =
                        vec![Ast::Symbol(f_temp.clone())];
                    let mut args_defines = vec![];

                    for arg in args {
                        let (conv_arg, arg_defines) : (Ast, Vec<Ast>) =
                            arg.convert_to_closures(env, toplevel_funs);
                        converted_args.push(conv_arg);
                        args_defines.extend_from_slice(&arg_defines);
                    }

                    args_defines.extend_from_slice(&fdefines);

                    let converted = Ast::Let(vec![(f_temp.clone(), fclos)],
                                               box Ast::App(
                                                   box Ast::App(box Ast::Symbol(Rc::new("tuple-ref".to_string())),
                                                                vec![Ast::Symbol(f_temp),
                                                                     Ast::Number(0)]),
                                                   converted_args));
                    return (converted, args_defines);
                },
            Ast::Let(bindings, body) => {
                let mut new_bindings = vec![];
                let mut bindings_defines = vec![];
                let mut new_env = env.clone();

                for (k, v) in bindings {
                    let (converted_v, v_defines) : (Ast, Vec<Ast>) =
                        v.convert_to_closures(env, toplevel_funs);

                    new_env.insert(k.clone());
                    new_bindings.push((k.clone(), converted_v));
                    bindings_defines.extend_from_slice(&v_defines);
                };

                let (converted_body, body_defines) : (Ast, Vec<Ast>) =
                    body.convert_to_closures(&new_env, toplevel_funs);

                bindings_defines.extend_from_slice(&body_defines);

                let converted = Ast::Let(new_bindings,
                                         box converted_body);
                return (converted, bindings_defines);
            },
            Ast::Prog(defines, main) => {
                let mut converted_defines = vec![];
                let mut defines_new_defines = vec![];
                let mut toplevel_funs = toplevel_funs.clone();

                for def in defines {
                    toplevel_funs.insert(Self::get_define_name(&def));
                    let (converted_define, new_defines) : (Ast, Vec<Ast>) =
                        def.convert_to_closures(env, &toplevel_funs);

                    converted_defines.push(converted_define);
                    defines_new_defines.extend_from_slice(&new_defines);
                }

                let (converted_main, main_defines) : (Ast, Vec<Ast>) =
                    main.convert_to_closures(env, &toplevel_funs);

                converted_defines.extend_from_slice(&defines_new_defines);
                converted_defines.extend_from_slice(&main_defines);

                let converted = Ast::Prog(converted_defines,
                                            box converted_main);

                return (converted, vec![]);
            },
            _ => panic!("NYI: {:?}", self),
        }
    }
}
<commit_msg>Add comment about convert_to_closures<commit_after>use std::collections::{HashMap, HashSet};
use std::rc::Rc;

#[derive(Debug, PartialEq, Clone)]
pub enum CC {
    // condition codes
    E, L, LE, G, GE,
}

#[derive(Debug, Clone)]
pub enum Ast {
    Symbol(Rc<String>),
    Number(i64),
    Bool(bool),
    List(Vec<Ast>),
    FuncName(Rc<String>),  // for closure-conversion

    Define(Rc<String>, Vec<Rc<String>>, Box<Ast>),
    If(Box<Ast>,     // cnd
       Box<Ast>,     // thn
       Box<Ast>),    // els
    Let(Vec<(Rc<String>, Ast)>, Box<Ast>),
    Lambda(Vec<Rc<String>>, Box<Ast>),
    Tuple(Vec<Ast>),
    Cmp(CC, Box<Ast>, Box<Ast>),
    App(Box<Ast>, Vec<Ast>),
    Prog(Vec<Ast>, Box<Ast>),
    Nil,
}

static mut VAR_COUNTER : i32 = 0;
pub fn get_unique_varname(stem: &str) -> String {
    unsafe {
        VAR_COUNTER += 1;
        return stem.to_string() + &VAR_COUNTER.to_string();
    }
}

impl Ast {
    pub fn uniquify(&self, mapping: &mut HashMap<Rc<String>, Rc<String>>) -> Self {
        match self {
            Ast::Symbol(name) => {
                let uniq_name = mapping.get(name)
                    .expect("unbound symbol");
                Ast::Symbol(uniq_name.clone())
            },
            Ast::Number(_) | Ast::Bool(_) => self.clone(),
            Ast::Tuple(elts) => {
                let elts =
                    elts.iter().map(|e| e.uniquify(mapping)).collect();
                Ast::Tuple(elts)
            },
            Ast::Let(bindings, body) => {
                let mut new_bindings = vec![];
                for (k, v) in bindings {
                    let uniq_k = Rc::new(get_unique_varname(&k));
                    new_bindings.push((uniq_k.clone(),
                                       v.uniquify(mapping)));
                    mapping.insert(k.clone(), uniq_k.clone());

                }
                Ast::Let(new_bindings,
                         Box::new(body.uniquify(mapping)))
            },
            Ast::List(elts) => {
                let new_elts : Vec<_> = elts.iter().map(|e| e.uniquify(mapping)).collect();
                Ast::List(new_elts)
            },
            Ast::Cmp(cc, left, right) =>
                return Ast::Cmp(cc.clone(),
                                box left.uniquify(mapping),
                                box right.uniquify(mapping)),
            Ast::Lambda(args, body) => {
                let mut new_args = vec![];
                for arg in args {
                    let new_arg = Rc::new(get_unique_varname(arg));
                    new_args.push(new_arg.clone());
                    mapping.insert(arg.clone(), new_arg.clone());
                }

                 Ast::Lambda(new_args,
                             box body.uniquify(mapping))
            },
            Ast::Define(name, args, val) => {
                let uniq_fname = Rc::new(get_unique_varname(name));
                mapping.insert(name.clone(), uniq_fname.clone());

                let mut new_args = vec![];
                for arg in args {
                    let new_arg = Rc::new(get_unique_varname(arg));
                    new_args.push(new_arg.clone());
                    mapping.insert(arg.clone(), new_arg.clone());
                }

                Ast::Define(uniq_fname.clone(),
                            new_args,
                            box val.uniquify(mapping))
            },
            Ast::If(cond, thn, els) =>
                Ast::If(box (cond.uniquify(mapping)),
                        box (thn.uniquify(mapping)),
                        box (els.uniquify(mapping))),
            Ast::App(f, args) => {
                let new_args : Vec<_> = args.iter()
                    .map(|a| a.uniquify(mapping)).collect();
                Ast::App(box f.uniquify(mapping),
                         new_args)
            },
            Ast::Prog(defs, e) => {
                let new_defs : Vec<_> = defs.iter()
                    .map(|def| def.uniquify(mapping)).collect();
                Ast::Prog(new_defs, box e.uniquify(mapping))
            },
            _ => panic!("NYI"),
        }
    }

    fn get_free_variables(&self,
                          env: &HashSet<Rc<String>>,
                          parent_env: &HashSet<Rc<String>>) -> Vec<Rc<String>> {
        match self {
            Ast::Number(_) => vec![],
            Ast::Symbol(name) => {
                match env.get(name) {
                    Some(_) => vec![],
                    None => {
                        match parent_env.get(name) {
                            Some(_) => vec![name.clone()],
                            None => panic!("no binding found in parent env for free-variable {} env: {:?} parent-env: {:?}", name, env, parent_env),
                        }
                    }
                }
            },
            Ast::If(cnd, thn, els) => {
                let mut cnd_freevars =
                    cnd.get_free_variables(env, parent_env);
                let thn_freevars =
                    thn.get_free_variables(env, parent_env);
                let els_freevars =
                    els.get_free_variables(env, parent_env);

                cnd_freevars.extend_from_slice(&thn_freevars);
                cnd_freevars.extend_from_slice(&els_freevars);

                return cnd_freevars;
            },
            Ast::Define(_, args, body) |
            Ast::Lambda(args, body) => {
                let mut new_parent_env : HashSet<Rc<String>> = HashSet::new()
                    .union(&env).cloned().collect();
                new_parent_env = new_parent_env
                    .union(&parent_env).cloned().collect();

                let new_env : HashSet<Rc<String>> = args.iter().map(|a| a.clone()).collect();

                println!("[lambda] new_env: {:?} new_parent_env: {:?}",
                         new_env,
                         new_parent_env);

                body.get_free_variables(&new_env, &new_parent_env)
            },
            Ast::Let(bindings, body) => {
                let mut new_env = HashSet::new();
                let mut bindings_free_vars = vec![];
                for (k, v) in bindings {
                    let v_freevars : Vec<_> =
                        v.get_free_variables(env, parent_env);
                    new_env.insert(k.clone());
                    bindings_free_vars.extend_from_slice(&v_freevars);
                }

                new_env = new_env.union(&env).cloned().collect();
                let body_freevars : Vec<_> =
                    body.get_free_variables(&new_env,
                                            parent_env);
                bindings_free_vars.extend_from_slice(&body_freevars);

                return bindings_free_vars;
            },
            Ast::App(_, args) => {
                let mut args_freevars = vec![];
                for arg in args {
                    let arg_freevars : Vec<_> =
                        arg.get_free_variables(env,
                                               parent_env);
                    args_freevars.extend_from_slice(&arg_freevars);
                }

                return args_freevars;
            },
            _ => panic!("NYI: {:?}", self),
        }
    }

    fn symbol_is_primitive(sym: &str) -> bool {
        match sym {
            "+" | "-" | "tuple-ref" | "tuple" => true,
            _ => false,
        }
    }

    fn get_define_name(def: &Ast) -> Rc<String> {
        match def {
            Ast::Define(name, _, _) => name.clone(),
            _ => panic!("not a Define"),
        }
    }

    /// Converts a lambda into a top-level define'd function. For all
    /// functions, adds a closure arg, and updates function
    /// applications to pass the closure arg. The `clos` arg is a
    /// tuple (f, a1, ..., an) capturing free variables.
    pub fn convert_to_closures(&self, env: &HashSet<Rc<String>>, toplevel_funs: &HashSet<Rc<String>>)
                           -> (Ast, Vec<Ast>) {
        match self {
            Ast::Cmp(_, _, _) |
            Ast::Bool(_) |
            Ast::Symbol(_) |
            Ast::FuncName(_) |
            Ast::Number(_) => (self.clone(), vec![]),
            Ast::If(cnd, thn, els) => {
                let (converted_cnd, mut cnd_defines) =
                    cnd.convert_to_closures(env, toplevel_funs);
                let (converted_thn, thn_defines) =
                    thn.convert_to_closures(env, toplevel_funs);
                let (converted_els, els_defines) =
                    els.convert_to_closures(env, toplevel_funs);

                let converted = Ast::If(box converted_cnd,
                                        box converted_thn,
                                        box converted_els);

                cnd_defines.extend_from_slice(&thn_defines);
                cnd_defines.extend_from_slice(&els_defines);

                return (converted, cnd_defines);
            },
            Ast::Define(name, args, body) => {
                let mut new_args = args.clone();
                let mut new_env = env.clone();

                for arg in args {
                    new_env.insert(arg.clone());
                }
                let (converted_body, body_defines) =
                    body.convert_to_closures(&new_env, toplevel_funs);

                new_args.insert(0, Rc::new("clos".to_string()));

                let converted = Ast::Define(name.clone(),
                                            new_args,
                                            box converted_body);

                return (converted, body_defines);

            },
            Ast::Lambda(args, body) => {
                let mut new_env = HashSet::new();
                let mut new_args = args.clone();
                for arg in args {
                    new_env.insert(arg.clone());
                }

                let (converted_body, mut new_defines) =
                    body.convert_to_closures(&new_env, toplevel_funs);

                let lambda_name = Rc::new(get_unique_varname("lam"));
                let free_vars : Vec<_> = body.get_free_variables(&new_env,
                                                                 env);
                let mut load_free_vars = converted_body;
                for (i, fvar) in free_vars.iter().enumerate() {
                    let bindings = vec![(fvar.clone(),
                                         Ast::App(box Ast::Symbol(Rc::new("tuple-ref".to_string())),
                                                  vec![Ast::Symbol(Rc::new("clos".to_string())),
                                                       Ast::Number((i+1) as i64)]))];
                    load_free_vars =
                        Ast::Let(bindings,
                                 box load_free_vars);
                }

                new_args.insert(0, Rc::new("clos".to_string()));

                let mut closure_elts =
                    vec![Ast::FuncName(lambda_name.clone())];

                let free_vars : Vec<Ast> =
                    free_vars.iter().map(|fv| Ast::Symbol(fv.clone())).collect();
                closure_elts.extend_from_slice(&free_vars[..]);
                let closure = Ast::Tuple(closure_elts);

                new_defines.extend_from_slice(&[
                    Ast::Define(lambda_name.clone(),
                                new_args,
                                box load_free_vars)
                ]);

                return (closure, new_defines);
            },
            Ast::Tuple(elts) => {
                let mut converted_elts = vec![];
                let mut elts_defines = vec![];

                for elt in elts {
                    let (conv_elt, elt_defines) : (Ast, Vec<Ast>) =
                        elt.convert_to_closures(env, toplevel_funs);
                    converted_elts.push(conv_elt);
                    elts_defines.extend_from_slice(&elt_defines);
                }

                let converted = Ast::Tuple(converted_elts);
                return (converted, elts_defines);

            },
            Ast::App(box Ast::Symbol(f), ref args)
                if Self::symbol_is_primitive(f) => {
                    let mut converted_args = vec![];
                    let mut args_defines = vec![];

                    for arg in args.clone() {
                        let (conv_arg, arg_defines) : (Ast, Vec<Ast>) =
                            arg.convert_to_closures(env, toplevel_funs);
                        converted_args.push(conv_arg);
                        args_defines.extend_from_slice(&arg_defines);
                    }

                    let converted = Ast::App(box Ast::Symbol(f.clone()),
                                             converted_args);
                    return (converted, args_defines);
                },
            Ast::App(box Ast::Symbol(f), ref args)
                if !Self::symbol_is_primitive(f) => {
                    let fname = match toplevel_funs.get(f) {
                        Some(_) => Ast::Tuple(vec![Ast::FuncName(f.clone())]),
                        None => Ast::Symbol(f.clone()),
                    };

                    let (fclos, fdefines) : (Ast, Vec<Ast>) =
                        fname.convert_to_closures(env, toplevel_funs);
                    let f_temp = Rc::new(get_unique_varname("tmp"));

                    let mut converted_args =
                        vec![Ast::Symbol(f_temp.clone())];
                    let mut args_defines = vec![];

                    for arg in args {
                        let (conv_arg, arg_defines) : (Ast, Vec<Ast>) =
                            arg.convert_to_closures(env, toplevel_funs);
                        converted_args.push(conv_arg);
                        args_defines.extend_from_slice(&arg_defines);
                    }

                    args_defines.extend_from_slice(&fdefines);

                    let converted = Ast::Let(vec![(f_temp.clone(), fclos)],
                                               box Ast::App(
                                                   box Ast::App(box Ast::Symbol(Rc::new("tuple-ref".to_string())),
                                                                vec![Ast::Symbol(f_temp),
                                                                     Ast::Number(0)]),
                                                   converted_args));
                    return (converted, args_defines);
                },
            Ast::Let(bindings, body) => {
                let mut new_bindings = vec![];
                let mut bindings_defines = vec![];
                let mut new_env = env.clone();

                for (k, v) in bindings {
                    let (converted_v, v_defines) : (Ast, Vec<Ast>) =
                        v.convert_to_closures(env, toplevel_funs);

                    new_env.insert(k.clone());
                    new_bindings.push((k.clone(), converted_v));
                    bindings_defines.extend_from_slice(&v_defines);
                };

                let (converted_body, body_defines) : (Ast, Vec<Ast>) =
                    body.convert_to_closures(&new_env, toplevel_funs);

                bindings_defines.extend_from_slice(&body_defines);

                let converted = Ast::Let(new_bindings,
                                         box converted_body);
                return (converted, bindings_defines);
            },
            Ast::Prog(defines, main) => {
                let mut converted_defines = vec![];
                let mut defines_new_defines = vec![];
                let mut toplevel_funs = toplevel_funs.clone();

                for def in defines {
                    toplevel_funs.insert(Self::get_define_name(&def));
                    let (converted_define, new_defines) : (Ast, Vec<Ast>) =
                        def.convert_to_closures(env, &toplevel_funs);

                    converted_defines.push(converted_define);
                    defines_new_defines.extend_from_slice(&new_defines);
                }

                let (converted_main, main_defines) : (Ast, Vec<Ast>) =
                    main.convert_to_closures(env, &toplevel_funs);

                converted_defines.extend_from_slice(&defines_new_defines);
                converted_defines.extend_from_slice(&main_defines);

                let converted = Ast::Prog(converted_defines,
                                            box converted_main);

                return (converted, vec![]);
            },
            _ => panic!("NYI: {:?}", self),
        }
    }
}
<|endoftext|>


<commit_before>use std::env;

use crate::error::Result;
use crate::map::Map;
use crate::source::Source;
use crate::value::{Value, ValueKind};

#[cfg(feature = "convert-case")]
use convert_case::{Case, Casing};

/// An environment source collects a dictionary of environment variables values into a hierarchical
/// config Value type. We have to be aware how the config tree is created from the environment
/// dictionary, therefore we are mindful about prefixes for the environment keys, level separators,
/// encoding form (kebab, snake case) etc.
#[must_use]
#[derive(Clone, Debug, Default)]
pub struct Environment {
    /// Optional prefix that will limit access to the environment to only keys that
    /// begin with the defined prefix.
    ///
    /// A prefix with a separator of `_` is tested to be present on each key before its considered
    /// to be part of the source environment.
    ///
    /// For example, the key `CONFIG_DEBUG` would become `DEBUG` with a prefix of `config`.
    prefix: Option<String>,

    /// Optional character sequence that separates the prefix from the rest of the key
    prefix_separator: Option<String>,

    /// Optional character sequence that separates each key segment in an environment key pattern.
    /// Consider a nested configuration such as `redis.password`, a separator of `_` would allow
    /// an environment key of `REDIS_PASSWORD` to match.
    separator: Option<String>,

    /// Optional directive to translate collected keys into a form that matches what serializers
    /// that the configuration would expect. For example if you have the `kebab-case` attribute
    /// for your serde config types, you may want to pass Case::Kebab here.
    #[cfg(feature = "convert-case")]
    convert_case: Option<convert_case::Case>,

    /// Optional character sequence that separates each env value into a vector. only works when try_parsing is set to true
    /// Once set, you cannot have type String on the same environment, unless you set list_parse_keys.
    list_separator: Option<String>,
    /// A list of keys which should always be parsed as a list. If not set you can have only Vec<String> or String (not both) in one environment.
    list_parse_keys: Option<Vec<String>>,

    /// Ignore empty env values (treat as unset).
    ignore_empty: bool,

    /// Parses booleans, integers and floats if they're detected (can be safely parsed).
    try_parsing: bool,

    // Preserve the prefix while parsing
    keep_prefix: bool,

    /// Alternate source for the environment. This can be used when you want to test your own code
    /// using this source, without the need to change the actual system environment variables.
    ///
    /// ## Example
    ///
    /// ```rust
    /// # use config::{Environment, Config};
    /// # use serde::Deserialize;
    /// # use std::collections::HashMap;
    /// # use std::convert::TryInto;
    /// #
    /// #[test]
    /// fn test_config() -> Result<(), config::ConfigError> {
    ///   #[derive(Clone, Debug, Deserialize)]
    ///   struct MyConfig {
    ///     pub my_string: String,
    ///   }
    ///
    ///   let source = Environment::default()
    ///     .source(Some({
    ///       let mut env = HashMap::new();
    ///       env.insert("MY_STRING".into(), "my-value".into());
    ///       env
    ///   }));
    ///
    ///   let config: MyConfig = Config::builder()
    ///     .add_source(source)
    ///     .build()?
    ///     .try_into()?;
    ///   assert_eq!(config.my_string, "my-value");
    ///
    ///   Ok(())
    /// }
    /// ```
    source: Option<Map<String, String>>,
}

impl Environment {
    #[deprecated(since = "0.12.0", note = "please use 'Environment::default' instead")]
    pub fn new() -> Self {
        Self::default()
    }

    pub fn with_prefix(s: &str) -> Self {
        Self {
            prefix: Some(s.into()),
            ..Self::default()
        }
    }

    pub fn prefix(mut self, s: &str) -> Self {
        self.prefix = Some(s.into());
        self
    }

    #[cfg(feature = "convert-case")]
    pub fn with_convert_case(tt: Case) -> Self {
        Self::default().convert_case(tt)
    }

    #[cfg(feature = "convert-case")]
    pub fn convert_case(mut self, tt: Case) -> Self {
        self.convert_case = Some(tt);
        self
    }

    pub fn prefix_separator(mut self, s: &str) -> Self {
        self.prefix_separator = Some(s.into());
        self
    }

    pub fn separator(mut self, s: &str) -> Self {
        self.separator = Some(s.into());
        self
    }

    /// When set and try_parsing is true, then all environment variables will be parsed as [`Vec<String>`] instead of [`String`].
    /// See [`with_list_parse_key`] when you want to use [`Vec<String>`] in combination with [`String`].
    pub fn list_separator(mut self, s: &str) -> Self {
        self.list_separator = Some(s.into());
        self
    }

    /// Add a key which should be parsed as a list when collecting [`Value`]s from the environment.
    /// Once list_separator is set, the type for string is [`Vec<String>`].
    /// To switch the default type back to type Strings you need to provide the keys which should be [`Vec<String>`] using this function.
    pub fn with_list_parse_key(mut self, key: &str) -> Self {
        if self.list_parse_keys == None {
            self.list_parse_keys = Some(vec![key.into()])
        } else {
            self.list_parse_keys = self.list_parse_keys.map(|mut keys| {
                keys.push(key.into());
                keys
            });
        }
        self
    }

    pub fn ignore_empty(mut self, ignore: bool) -> Self {
        self.ignore_empty = ignore;
        self
    }

    /// Note: enabling `try_parsing` can reduce performance it will try and parse
    /// each environment variable 3 times (bool, i64, f64)
    pub fn try_parsing(mut self, try_parsing: bool) -> Self {
        self.try_parsing = try_parsing;
        self
    }

    pub fn keep_prefix(mut self, keep: bool) -> Self {
        self.keep_prefix = keep;
        self
    }

    pub fn source(mut self, source: Option<Map<String, String>>) -> Self {
        self.source = source;
        self
    }
}

impl Source for Environment {
    fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
        Box::new((*self).clone())
    }

    fn collect(&self) -> Result<Map<String, Value>> {
        let mut m = Map::new();
        let uri: String = "the environment".into();

        let separator = self.separator.as_deref().unwrap_or("");
        #[cfg(feature = "convert-case")]
        let convert_case = &self.convert_case;
        let prefix_separator = match (self.prefix_separator.as_deref(), self.separator.as_deref()) {
            (Some(pre), _) => pre,
            (None, Some(sep)) => sep,
            (None, None) => "_",
        };

        // Define a prefix pattern to test and exclude from keys
        let prefix_pattern = self
            .prefix
            .as_ref()
            .map(|prefix| format!("{}{}", prefix, prefix_separator).to_lowercase());

        let collector = |(key, value): (String, String)| {
            // Treat empty environment variables as unset
            if self.ignore_empty && value.is_empty() {
                return;
            }

            let mut key = key.to_lowercase();

            // Check for prefix
            if let Some(ref prefix_pattern) = prefix_pattern {
                if key.starts_with(prefix_pattern) {
                    if !self.keep_prefix {
                        // Remove this prefix from the key
                        key = key[prefix_pattern.len()..].to_string();
                    }
                } else {
                    // Skip this key
                    return;
                }
            }

            // If separator is given replace with `.`
            if !separator.is_empty() {
                key = key.replace(separator, ".");
            }

            #[cfg(feature = "convert-case")]
            if let Some(convert_case) = convert_case {
                key = key.to_case(*convert_case);
            }

            let value = if self.try_parsing {
                // convert to lowercase because bool parsing expects all lowercase
                if let Ok(parsed) = value.to_lowercase().parse::<bool>() {
                    ValueKind::Boolean(parsed)
                } else if let Ok(parsed) = value.parse::<i64>() {
                    ValueKind::I64(parsed)
                } else if let Ok(parsed) = value.parse::<f64>() {
                    ValueKind::Float(parsed)
                } else if let Some(separator) = &self.list_separator {
                    if let Some(keys) = &self.list_parse_keys {
                        if keys.contains(&key) {
                            let v: Vec<Value> = value
                                .split(separator)
                                .map(|s| Value::new(Some(&uri), ValueKind::String(s.to_string())))
                                .collect();
                            ValueKind::Array(v)
                        } else {
                            ValueKind::String(value)
                        }
                    } else {
                        let v: Vec<Value> = value
                            .split(separator)
                            .map(|s| Value::new(Some(&uri), ValueKind::String(s.to_string())))
                            .collect();
                        ValueKind::Array(v)
                    }
                } else {
                    ValueKind::String(value)
                }
            } else {
                ValueKind::String(value)
            };

            m.insert(key, Value::new(Some(&uri), value));
        };

        match &self.source {
            Some(source) => source.clone().into_iter().for_each(collector),
            None => env::vars().for_each(collector),
        }

        Ok(m)
    }
}
<commit_msg>Fix clippy: Do not manually check for None<commit_after>use std::env;

use crate::error::Result;
use crate::map::Map;
use crate::source::Source;
use crate::value::{Value, ValueKind};

#[cfg(feature = "convert-case")]
use convert_case::{Case, Casing};

/// An environment source collects a dictionary of environment variables values into a hierarchical
/// config Value type. We have to be aware how the config tree is created from the environment
/// dictionary, therefore we are mindful about prefixes for the environment keys, level separators,
/// encoding form (kebab, snake case) etc.
#[must_use]
#[derive(Clone, Debug, Default)]
pub struct Environment {
    /// Optional prefix that will limit access to the environment to only keys that
    /// begin with the defined prefix.
    ///
    /// A prefix with a separator of `_` is tested to be present on each key before its considered
    /// to be part of the source environment.
    ///
    /// For example, the key `CONFIG_DEBUG` would become `DEBUG` with a prefix of `config`.
    prefix: Option<String>,

    /// Optional character sequence that separates the prefix from the rest of the key
    prefix_separator: Option<String>,

    /// Optional character sequence that separates each key segment in an environment key pattern.
    /// Consider a nested configuration such as `redis.password`, a separator of `_` would allow
    /// an environment key of `REDIS_PASSWORD` to match.
    separator: Option<String>,

    /// Optional directive to translate collected keys into a form that matches what serializers
    /// that the configuration would expect. For example if you have the `kebab-case` attribute
    /// for your serde config types, you may want to pass Case::Kebab here.
    #[cfg(feature = "convert-case")]
    convert_case: Option<convert_case::Case>,

    /// Optional character sequence that separates each env value into a vector. only works when try_parsing is set to true
    /// Once set, you cannot have type String on the same environment, unless you set list_parse_keys.
    list_separator: Option<String>,
    /// A list of keys which should always be parsed as a list. If not set you can have only Vec<String> or String (not both) in one environment.
    list_parse_keys: Option<Vec<String>>,

    /// Ignore empty env values (treat as unset).
    ignore_empty: bool,

    /// Parses booleans, integers and floats if they're detected (can be safely parsed).
    try_parsing: bool,

    // Preserve the prefix while parsing
    keep_prefix: bool,

    /// Alternate source for the environment. This can be used when you want to test your own code
    /// using this source, without the need to change the actual system environment variables.
    ///
    /// ## Example
    ///
    /// ```rust
    /// # use config::{Environment, Config};
    /// # use serde::Deserialize;
    /// # use std::collections::HashMap;
    /// # use std::convert::TryInto;
    /// #
    /// #[test]
    /// fn test_config() -> Result<(), config::ConfigError> {
    ///   #[derive(Clone, Debug, Deserialize)]
    ///   struct MyConfig {
    ///     pub my_string: String,
    ///   }
    ///
    ///   let source = Environment::default()
    ///     .source(Some({
    ///       let mut env = HashMap::new();
    ///       env.insert("MY_STRING".into(), "my-value".into());
    ///       env
    ///   }));
    ///
    ///   let config: MyConfig = Config::builder()
    ///     .add_source(source)
    ///     .build()?
    ///     .try_into()?;
    ///   assert_eq!(config.my_string, "my-value");
    ///
    ///   Ok(())
    /// }
    /// ```
    source: Option<Map<String, String>>,
}

impl Environment {
    #[deprecated(since = "0.12.0", note = "please use 'Environment::default' instead")]
    pub fn new() -> Self {
        Self::default()
    }

    pub fn with_prefix(s: &str) -> Self {
        Self {
            prefix: Some(s.into()),
            ..Self::default()
        }
    }

    pub fn prefix(mut self, s: &str) -> Self {
        self.prefix = Some(s.into());
        self
    }

    #[cfg(feature = "convert-case")]
    pub fn with_convert_case(tt: Case) -> Self {
        Self::default().convert_case(tt)
    }

    #[cfg(feature = "convert-case")]
    pub fn convert_case(mut self, tt: Case) -> Self {
        self.convert_case = Some(tt);
        self
    }

    pub fn prefix_separator(mut self, s: &str) -> Self {
        self.prefix_separator = Some(s.into());
        self
    }

    pub fn separator(mut self, s: &str) -> Self {
        self.separator = Some(s.into());
        self
    }

    /// When set and try_parsing is true, then all environment variables will be parsed as [`Vec<String>`] instead of [`String`].
    /// See [`with_list_parse_key`] when you want to use [`Vec<String>`] in combination with [`String`].
    pub fn list_separator(mut self, s: &str) -> Self {
        self.list_separator = Some(s.into());
        self
    }

    /// Add a key which should be parsed as a list when collecting [`Value`]s from the environment.
    /// Once list_separator is set, the type for string is [`Vec<String>`].
    /// To switch the default type back to type Strings you need to provide the keys which should be [`Vec<String>`] using this function.
    pub fn with_list_parse_key(mut self, key: &str) -> Self {
        if self.list_parse_keys.is_none() {
            self.list_parse_keys = Some(vec![key.into()])
        } else {
            self.list_parse_keys = self.list_parse_keys.map(|mut keys| {
                keys.push(key.into());
                keys
            });
        }
        self
    }

    pub fn ignore_empty(mut self, ignore: bool) -> Self {
        self.ignore_empty = ignore;
        self
    }

    /// Note: enabling `try_parsing` can reduce performance it will try and parse
    /// each environment variable 3 times (bool, i64, f64)
    pub fn try_parsing(mut self, try_parsing: bool) -> Self {
        self.try_parsing = try_parsing;
        self
    }

    pub fn keep_prefix(mut self, keep: bool) -> Self {
        self.keep_prefix = keep;
        self
    }

    pub fn source(mut self, source: Option<Map<String, String>>) -> Self {
        self.source = source;
        self
    }
}

impl Source for Environment {
    fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
        Box::new((*self).clone())
    }

    fn collect(&self) -> Result<Map<String, Value>> {
        let mut m = Map::new();
        let uri: String = "the environment".into();

        let separator = self.separator.as_deref().unwrap_or("");
        #[cfg(feature = "convert-case")]
        let convert_case = &self.convert_case;
        let prefix_separator = match (self.prefix_separator.as_deref(), self.separator.as_deref()) {
            (Some(pre), _) => pre,
            (None, Some(sep)) => sep,
            (None, None) => "_",
        };

        // Define a prefix pattern to test and exclude from keys
        let prefix_pattern = self
            .prefix
            .as_ref()
            .map(|prefix| format!("{}{}", prefix, prefix_separator).to_lowercase());

        let collector = |(key, value): (String, String)| {
            // Treat empty environment variables as unset
            if self.ignore_empty && value.is_empty() {
                return;
            }

            let mut key = key.to_lowercase();

            // Check for prefix
            if let Some(ref prefix_pattern) = prefix_pattern {
                if key.starts_with(prefix_pattern) {
                    if !self.keep_prefix {
                        // Remove this prefix from the key
                        key = key[prefix_pattern.len()..].to_string();
                    }
                } else {
                    // Skip this key
                    return;
                }
            }

            // If separator is given replace with `.`
            if !separator.is_empty() {
                key = key.replace(separator, ".");
            }

            #[cfg(feature = "convert-case")]
            if let Some(convert_case) = convert_case {
                key = key.to_case(*convert_case);
            }

            let value = if self.try_parsing {
                // convert to lowercase because bool parsing expects all lowercase
                if let Ok(parsed) = value.to_lowercase().parse::<bool>() {
                    ValueKind::Boolean(parsed)
                } else if let Ok(parsed) = value.parse::<i64>() {
                    ValueKind::I64(parsed)
                } else if let Ok(parsed) = value.parse::<f64>() {
                    ValueKind::Float(parsed)
                } else if let Some(separator) = &self.list_separator {
                    if let Some(keys) = &self.list_parse_keys {
                        if keys.contains(&key) {
                            let v: Vec<Value> = value
                                .split(separator)
                                .map(|s| Value::new(Some(&uri), ValueKind::String(s.to_string())))
                                .collect();
                            ValueKind::Array(v)
                        } else {
                            ValueKind::String(value)
                        }
                    } else {
                        let v: Vec<Value> = value
                            .split(separator)
                            .map(|s| Value::new(Some(&uri), ValueKind::String(s.to_string())))
                            .collect();
                        ValueKind::Array(v)
                    }
                } else {
                    ValueKind::String(value)
                }
            } else {
                ValueKind::String(value)
            };

            m.insert(key, Value::new(Some(&uri), value));
        };

        match &self.source {
            Some(source) => source.clone().into_iter().for_each(collector),
            None => env::vars().for_each(collector),
        }

        Ok(m)
    }
}
<|endoftext|>


<commit_before>pub use std::num::ParseFloatError;
use std::str::{from_utf8_unchecked};

use base::{FromAscii};

impl FromAscii for f32 {
    type Err = ParseFloatError;

    #[inline]
    fn from_ascii(src: &[u8]) -> Result<Self, Self::Err> {
        unsafe {
            from_utf8_unchecked(src).parse()
        }
    }
}

impl FromAscii for f64 {
    type Err = ParseFloatError;

    #[inline]
    fn from_ascii(src: &[u8]) -> Result<Self, Self::Err> {
        unsafe {
            from_utf8_unchecked(src).parse()
        }
    }
}
<commit_msg>Add ParseFloatError<commit_after>use std::num;
use std::fmt;
use std::error::{Error};
use std::str::{from_utf8_unchecked};

use base::{FromAscii};

#[derive(Debug, Clone, PartialEq)]
pub struct ParseFloatError {
    kind: FloatErrorKind
}

#[derive(Debug, Clone, PartialEq)]
enum FloatErrorKind {
    FloatErrorKind
}

impl Error for ParseFloatError {
    fn description(&self) -> &str {
        "failed to parse float"
    }
}

impl From<num::ParseFloatError> for ParseFloatError {
    fn from(t: num::ParseFloatError) -> ParseFloatError {
        ParseFloatError { kind: FloatErrorKind::FloatErrorKind }
    }
}

impl fmt::Display for ParseFloatError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.description().fmt(f)
    }
}

impl FromAscii for f32 {
    type Err = ParseFloatError;

    #[inline]
    fn from_ascii(src: &[u8]) -> Result<Self, Self::Err> {
        unsafe {
            from_utf8_unchecked(src).parse().map_err(From::from)
        }
    }
}

impl FromAscii for f64 {
    type Err = ParseFloatError;

    #[inline]
    fn from_ascii(src: &[u8]) -> Result<Self, Self::Err> {
        unsafe {
            from_utf8_unchecked(src).parse().map_err(From::from)
        }
    }
}
<|endoftext|>


<commit_before>//!  Decoding of GIF Images
//!
//!  GIF (Graphics Interchange Format) is an image format that supports lossless compression.
//!
//!  # Related Links
//!  * <http://www.w3.org/Graphics/GIF/spec-gif89a.txt> - The GIF Specification
//!
//! # Examples
//! ```rust,no_run
//! use image::gif::{Decoder, Encoder};
//! use image::{ImageDecoder, AnimationDecoder};
//! use std::fs::File;
//! # fn main() -> std::io::Result<()> {
//! // Decode a gif into frames
//! let file_in = File::open("foo.gif")?;
//! let mut decoder = Decoder::new(file_in).unwrap();
//! let frames = decoder.into_frames();
//! let frames = frames.collect_frames().expect("error decoding gif");
//!
//! // Encode frames into a gif and save to a file
//! let mut file_out = File::open("out.gif")?;
//! let mut encoder = Encoder::new(file_out);
//! encoder.encode_frames(frames.into_iter());
//! # Ok(())
//! # }
//! ```
#![allow(clippy::while_let_loop)]

extern crate gif;
extern crate num_rational;

use std::clone::Clone;
use std::cmp::min;
use std::io::{self, Cursor, Read, Write};
use std::marker::PhantomData;
use std::mem;

use self::gif::{ColorOutput, SetParameter};
pub use self::gif::{DisposalMethod, Frame};

use animation;
use buffer::{ImageBuffer, Pixel};
use color;
use color::Rgba;
use image::{AnimationDecoder, ImageDecoder, ImageError, ImageResult};
use num_rational::Ratio;

/// GIF decoder
pub struct Decoder<R: Read> {
    reader: gif::Reader<R>,
}

impl<R: Read> Decoder<R> {
    /// Creates a new decoder that decodes the input steam ```r```
    pub fn new(r: R) -> ImageResult<Decoder<R>> {
        let mut decoder = gif::Decoder::new(r);
        decoder.set(ColorOutput::RGBA);

        Ok(Decoder {
            reader: decoder.read_info()?,
        })
    }
}

/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct GifReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for GifReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        if self.0.position() == 0 && buf.is_empty() {
            mem::swap(buf, self.0.get_mut());
            Ok(buf.len())
        } else {
            self.0.read_to_end(buf)
        }
    }
}

impl<'a, R: 'a + Read> ImageDecoder<'a> for Decoder<R> {
    type Reader = GifReader<R>;

    fn dimensions(&self) -> (u64, u64) {
        (u64::from(self.reader.width()), u64::from(self.reader.height()))
    }

    fn colortype(&self) -> color::ColorType {
        color::ColorType::RGBA(8)
    }

    fn into_reader(self) -> ImageResult<Self::Reader> {
        Ok(GifReader(Cursor::new(self.read_image()?), PhantomData))
    }

    fn read_image(mut self) -> ImageResult<Vec<u8>> {
        let (f_width, f_height, left, top);

        if let Some(frame) = self.reader.next_frame_info()? {
            left = u32::from(frame.left);
            top = u32::from(frame.top);
            f_width = u32::from(frame.width);
            f_height = u32::from(frame.height);
        } else {
            return Err(ImageError::ImageEnd);
        }

        let mut buf = vec![0; self.reader.buffer_size()];
        self.reader.read_into_buffer(&mut buf)?;

        // See the comments inside `<GifFrameIterator as Iterator>::next` about
        // the error handling of `from_raw`.
        let image_buffer_raw = ImageBuffer::from_raw(f_width, f_height, buf).ok_or_else(||
            ImageError::UnsupportedError("Image dimensions are too large".into())
        )?;

        // Recover the full image
        let (width, height) = (u32::from(self.reader.width()), u32::from(self.reader.height()));
        let image_buffer = full_image_from_frame(width, height, image_buffer_raw, left, top);

        Ok(image_buffer.into_raw())
    }
}

struct GifFrameIterator<R: Read> {
    reader: gif::Reader<R>,

    width: u32,
    height: u32,

    non_disposed_frame: ImageBuffer<Rgba<u8>, Vec<u8>>,
}

impl<R: Read> GifFrameIterator<R> {
    fn new(decoder: Decoder<R>) -> GifFrameIterator<R> {
        let (width, height) = decoder.dimensions();

        // TODO: Avoid this cast
        let (width, height) = (width as u32, height as u32);

        // intentionally ignore the background color for web compatibility

        // create the first non disposed frame
        let non_disposed_frame = ImageBuffer::from_pixel(width, height, Rgba([0, 0, 0, 0]));

        GifFrameIterator {
            reader: decoder.reader,
            width,
            height,
            non_disposed_frame,
        }
    }
}

impl<R: Read> Iterator for GifFrameIterator<R> {
    type Item = ImageResult<animation::Frame>;

    fn next(&mut self) -> Option<ImageResult<animation::Frame>> {
        // begin looping over each frame
        let (left, top, delay, dispose, f_width, f_height);

        match self.reader.next_frame_info() {
            Ok(frame_info) => {
                if let Some(frame) = frame_info {
                    left = u32::from(frame.left);
                    top = u32::from(frame.top);
                    f_width = u32::from(frame.width);
                    f_height = u32::from(frame.height);

                    // frame.delay is in units of 10ms so frame.delay*10 is in ms
                    delay = Ratio::new(frame.delay * 10, 1);
                    dispose = frame.dispose;
                } else {
                    // no more frames
                    return None;
                }
            },
            Err(err) => return Some(Err(err.into())),
        }

        let mut vec = vec![0; self.reader.buffer_size()];
        if let Err(err) = self.reader.fill_buffer(&mut vec) {
            return Some(Err(err.into()));
        }

        // create the image buffer from the raw frame.
        // `buffer_size` uses wrapping arithmetics, thus might not report the
        // correct storage requirement if the result does not fit in `usize`.
        // on the other hand, `ImageBuffer::from_raw` detects overflow and
        // reports by returning `None`.
        let image_buffer_raw = match ImageBuffer::from_raw(f_width, f_height, vec) {
            Some(image_buffer_raw) => image_buffer_raw,
            None => {
                return Some(Err(ImageError::UnsupportedError(
                    "Image dimensions are too large".into(),
                )))
            }
        };

        // if `image_buffer_raw`'s frame exactly matches the entire image, then
        // use it directly.
        //
        // otherwise, `image_buffer_raw` represents a smaller image.
        // create a new image of the target size and place
        // `image_buffer_raw` within it. the outside region is filled with
        // transparent pixels.
        let mut image_buffer =
            full_image_from_frame(self.width, self.height, image_buffer_raw, left, top);

        // loop over all pixels, checking if any pixels from the non disposed
        // frame need to be used
        for (x, y, pixel) in image_buffer.enumerate_pixels_mut() {
            let previous_img_buffer = &self.non_disposed_frame;
            let adjusted_pixel: &mut Rgba<u8> = pixel;
            let previous_pixel: &Rgba<u8> = previous_img_buffer.get_pixel(x, y);

            let pixel_alpha = adjusted_pixel.channels()[3];

            // If a pixel is not visible then we show the non disposed frame pixel instead
            if pixel_alpha == 0 {
                adjusted_pixel.blend(previous_pixel);
            }
        }

        let frame = animation::Frame::from_parts(
            image_buffer.clone(), 0, 0, delay
        );

        match dispose {
            DisposalMethod::Any => {
                // do nothing
                // (completely replace this frame with the next)
            }
            DisposalMethod::Keep => {
                // do not dispose
                // (keep pixels from this frame)
                self.non_disposed_frame = image_buffer;
            }
            DisposalMethod::Background => {
                // restore to background color
                // (background shows through transparent pixels in the next frame)
                for y in top..min(top + f_height, self.height) {
                    for x in left..min(left + f_width, self.width) {
                        self.non_disposed_frame.put_pixel(x, y, Rgba([0, 0, 0, 0]));
                    }
                }
            }
            DisposalMethod::Previous => {
                // restore to previous
                // (dispose frames leaving the last none disposal frame)
            }
        };

        Some(Ok(frame))
    }
}

/// Given a frame subimage, construct a full image of size
/// `(screen_width, screen_height)` by placing it at the top-left coordinates
/// `(left, top)`. The remaining portion is filled with transparent pixels.
fn full_image_from_frame(
    screen_width: u32,
    screen_height: u32,
    image: crate::RgbaImage,
    left: u32,
    top: u32,
) -> crate::RgbaImage {
    if (left, top) == (0, 0) && (screen_width, screen_height) == (image.width(), image.height()) {
        image
    } else {
        ImageBuffer::from_fn(screen_width, screen_height, |x, y| {
            let x = x.wrapping_sub(left);
            let y = y.wrapping_sub(top);
            if x < image.width() && y < image.height() {
                *image.get_pixel(x, y)
            } else {
                Rgba([0, 0, 0, 0])
            }
        })
    }
}

impl<'a, R: Read + 'a> AnimationDecoder<'a> for Decoder<R> {
    fn into_frames(self) -> animation::Frames<'a> {
        animation::Frames::new(Box::new(GifFrameIterator::new(self)))
    }
}

/// GIF encoder.
pub struct Encoder<W: Write> {
    w: Option<W>,
    gif_encoder: Option<gif::Encoder<W>>,
}

impl<W: Write> Encoder<W> {
    /// Creates a new GIF encoder.
    pub fn new(w: W) -> Encoder<W> {
        Encoder {
            w: Some(w),
            gif_encoder: None,
        }
    }
    /// Encodes a frame.
    pub fn encode(&mut self, frame: &Frame) -> ImageResult<()> {
        let result;
        if let Some(ref mut encoder) = self.gif_encoder {
            result = encoder.write_frame(frame).map_err(|err| err.into());
        } else {
            let writer = self.w.take().unwrap();
            let mut encoder = gif::Encoder::new(writer, frame.width, frame.height, &[])?;
            result = encoder.write_frame(&frame).map_err(|err| err.into());
            self.gif_encoder = Some(encoder);
        }
        result
    }

    /// Encodes Frames.
    /// Consider using `try_encode_frames` instead to encode an `animation::Frames` like iterator.
    pub fn encode_frames<F>(&mut self, frames: F) -> ImageResult<()>
    where
        F: IntoIterator<Item = animation::Frame>
    {
        for img_frame in frames {
            self.encode_single_frame(img_frame)?;
        }
        Ok(())
    }

    /// Try to encode a collection of `ImageResult<animation::Frame>` objects.
    /// Use this function to encode an `animation::Frames` like iterator.
    /// Whenever an `Err` item is encountered, that value is returned without further actions.
    pub fn try_encode_frames<F>(&mut self, frames: F) -> ImageResult<()>
    where
        F: IntoIterator<Item = ImageResult<animation::Frame>>
    {
        for img_frame in frames {
            self.encode_single_frame(img_frame?)?;
        }
        Ok(())
    }

    fn encode_single_frame(&mut self, img_frame: animation::Frame) -> ImageResult<()> {
        // get the delay before converting img_frame
        let frame_delay = img_frame.delay().to_integer();
        // convert img_frame into RgbaImage
        let rbga_frame = img_frame.into_buffer();

        // Create the gif::Frame from the animation::Frame
        let mut frame = Frame::from_rgba(rbga_frame.width() as u16, rbga_frame.height() as u16, &mut rbga_frame.into_raw());
        frame.delay = frame_delay;

        // encode the gif::Frame
        self.encode(&frame)
    }
}

impl From<gif::DecodingError> for ImageError {
    fn from(err: gif::DecodingError) -> ImageError {
        use self::gif::DecodingError::*;
        match err {
            Format(desc) | Internal(desc) => ImageError::FormatError(desc.into()),
            Io(io_err) => ImageError::IoError(io_err),
        }
    }
}
<commit_msg>Use read_into_buffer, which deinterlaces as needed<commit_after>//!  Decoding of GIF Images
//!
//!  GIF (Graphics Interchange Format) is an image format that supports lossless compression.
//!
//!  # Related Links
//!  * <http://www.w3.org/Graphics/GIF/spec-gif89a.txt> - The GIF Specification
//!
//! # Examples
//! ```rust,no_run
//! use image::gif::{Decoder, Encoder};
//! use image::{ImageDecoder, AnimationDecoder};
//! use std::fs::File;
//! # fn main() -> std::io::Result<()> {
//! // Decode a gif into frames
//! let file_in = File::open("foo.gif")?;
//! let mut decoder = Decoder::new(file_in).unwrap();
//! let frames = decoder.into_frames();
//! let frames = frames.collect_frames().expect("error decoding gif");
//!
//! // Encode frames into a gif and save to a file
//! let mut file_out = File::open("out.gif")?;
//! let mut encoder = Encoder::new(file_out);
//! encoder.encode_frames(frames.into_iter());
//! # Ok(())
//! # }
//! ```
#![allow(clippy::while_let_loop)]

extern crate gif;
extern crate num_rational;

use std::clone::Clone;
use std::cmp::min;
use std::io::{self, Cursor, Read, Write};
use std::marker::PhantomData;
use std::mem;

use self::gif::{ColorOutput, SetParameter};
pub use self::gif::{DisposalMethod, Frame};

use animation;
use buffer::{ImageBuffer, Pixel};
use color;
use color::Rgba;
use image::{AnimationDecoder, ImageDecoder, ImageError, ImageResult};
use num_rational::Ratio;

/// GIF decoder
pub struct Decoder<R: Read> {
    reader: gif::Reader<R>,
}

impl<R: Read> Decoder<R> {
    /// Creates a new decoder that decodes the input steam ```r```
    pub fn new(r: R) -> ImageResult<Decoder<R>> {
        let mut decoder = gif::Decoder::new(r);
        decoder.set(ColorOutput::RGBA);

        Ok(Decoder {
            reader: decoder.read_info()?,
        })
    }
}

/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct GifReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for GifReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        if self.0.position() == 0 && buf.is_empty() {
            mem::swap(buf, self.0.get_mut());
            Ok(buf.len())
        } else {
            self.0.read_to_end(buf)
        }
    }
}

impl<'a, R: 'a + Read> ImageDecoder<'a> for Decoder<R> {
    type Reader = GifReader<R>;

    fn dimensions(&self) -> (u64, u64) {
        (u64::from(self.reader.width()), u64::from(self.reader.height()))
    }

    fn colortype(&self) -> color::ColorType {
        color::ColorType::RGBA(8)
    }

    fn into_reader(self) -> ImageResult<Self::Reader> {
        Ok(GifReader(Cursor::new(self.read_image()?), PhantomData))
    }

    fn read_image(mut self) -> ImageResult<Vec<u8>> {
        let (f_width, f_height, left, top);

        if let Some(frame) = self.reader.next_frame_info()? {
            left = u32::from(frame.left);
            top = u32::from(frame.top);
            f_width = u32::from(frame.width);
            f_height = u32::from(frame.height);
        } else {
            return Err(ImageError::ImageEnd);
        }

        let mut buf = vec![0; self.reader.buffer_size()];
        self.reader.read_into_buffer(&mut buf)?;

        // See the comments inside `<GifFrameIterator as Iterator>::next` about
        // the error handling of `from_raw`.
        let image_buffer_raw = ImageBuffer::from_raw(f_width, f_height, buf).ok_or_else(||
            ImageError::UnsupportedError("Image dimensions are too large".into())
        )?;

        // Recover the full image
        let (width, height) = (u32::from(self.reader.width()), u32::from(self.reader.height()));
        let image_buffer = full_image_from_frame(width, height, image_buffer_raw, left, top);

        Ok(image_buffer.into_raw())
    }
}

struct GifFrameIterator<R: Read> {
    reader: gif::Reader<R>,

    width: u32,
    height: u32,

    non_disposed_frame: ImageBuffer<Rgba<u8>, Vec<u8>>,
}

impl<R: Read> GifFrameIterator<R> {
    fn new(decoder: Decoder<R>) -> GifFrameIterator<R> {
        let (width, height) = decoder.dimensions();

        // TODO: Avoid this cast
        let (width, height) = (width as u32, height as u32);

        // intentionally ignore the background color for web compatibility

        // create the first non disposed frame
        let non_disposed_frame = ImageBuffer::from_pixel(width, height, Rgba([0, 0, 0, 0]));

        GifFrameIterator {
            reader: decoder.reader,
            width,
            height,
            non_disposed_frame,
        }
    }
}

impl<R: Read> Iterator for GifFrameIterator<R> {
    type Item = ImageResult<animation::Frame>;

    fn next(&mut self) -> Option<ImageResult<animation::Frame>> {
        // begin looping over each frame
        let (left, top, delay, dispose, f_width, f_height);

        match self.reader.next_frame_info() {
            Ok(frame_info) => {
                if let Some(frame) = frame_info {
                    left = u32::from(frame.left);
                    top = u32::from(frame.top);
                    f_width = u32::from(frame.width);
                    f_height = u32::from(frame.height);

                    // frame.delay is in units of 10ms so frame.delay*10 is in ms
                    delay = Ratio::new(frame.delay * 10, 1);
                    dispose = frame.dispose;
                } else {
                    // no more frames
                    return None;
                }
            },
            Err(err) => return Some(Err(err.into())),
        }

        let mut vec = vec![0; self.reader.buffer_size()];
        if let Err(err) = self.reader.read_into_buffer(&mut vec) {
            return Some(Err(err.into()));
        }

        // create the image buffer from the raw frame.
        // `buffer_size` uses wrapping arithmetics, thus might not report the
        // correct storage requirement if the result does not fit in `usize`.
        // on the other hand, `ImageBuffer::from_raw` detects overflow and
        // reports by returning `None`.
        let image_buffer_raw = match ImageBuffer::from_raw(f_width, f_height, vec) {
            Some(image_buffer_raw) => image_buffer_raw,
            None => {
                return Some(Err(ImageError::UnsupportedError(
                    "Image dimensions are too large".into(),
                )))
            }
        };

        // if `image_buffer_raw`'s frame exactly matches the entire image, then
        // use it directly.
        //
        // otherwise, `image_buffer_raw` represents a smaller image.
        // create a new image of the target size and place
        // `image_buffer_raw` within it. the outside region is filled with
        // transparent pixels.
        let mut image_buffer =
            full_image_from_frame(self.width, self.height, image_buffer_raw, left, top);

        // loop over all pixels, checking if any pixels from the non disposed
        // frame need to be used
        for (x, y, pixel) in image_buffer.enumerate_pixels_mut() {
            let previous_img_buffer = &self.non_disposed_frame;
            let adjusted_pixel: &mut Rgba<u8> = pixel;
            let previous_pixel: &Rgba<u8> = previous_img_buffer.get_pixel(x, y);

            let pixel_alpha = adjusted_pixel.channels()[3];

            // If a pixel is not visible then we show the non disposed frame pixel instead
            if pixel_alpha == 0 {
                adjusted_pixel.blend(previous_pixel);
            }
        }

        let frame = animation::Frame::from_parts(
            image_buffer.clone(), 0, 0, delay
        );

        match dispose {
            DisposalMethod::Any => {
                // do nothing
                // (completely replace this frame with the next)
            }
            DisposalMethod::Keep => {
                // do not dispose
                // (keep pixels from this frame)
                self.non_disposed_frame = image_buffer;
            }
            DisposalMethod::Background => {
                // restore to background color
                // (background shows through transparent pixels in the next frame)
                for y in top..min(top + f_height, self.height) {
                    for x in left..min(left + f_width, self.width) {
                        self.non_disposed_frame.put_pixel(x, y, Rgba([0, 0, 0, 0]));
                    }
                }
            }
            DisposalMethod::Previous => {
                // restore to previous
                // (dispose frames leaving the last none disposal frame)
            }
        };

        Some(Ok(frame))
    }
}

/// Given a frame subimage, construct a full image of size
/// `(screen_width, screen_height)` by placing it at the top-left coordinates
/// `(left, top)`. The remaining portion is filled with transparent pixels.
fn full_image_from_frame(
    screen_width: u32,
    screen_height: u32,
    image: crate::RgbaImage,
    left: u32,
    top: u32,
) -> crate::RgbaImage {
    if (left, top) == (0, 0) && (screen_width, screen_height) == (image.width(), image.height()) {
        image
    } else {
        ImageBuffer::from_fn(screen_width, screen_height, |x, y| {
            let x = x.wrapping_sub(left);
            let y = y.wrapping_sub(top);
            if x < image.width() && y < image.height() {
                *image.get_pixel(x, y)
            } else {
                Rgba([0, 0, 0, 0])
            }
        })
    }
}

impl<'a, R: Read + 'a> AnimationDecoder<'a> for Decoder<R> {
    fn into_frames(self) -> animation::Frames<'a> {
        animation::Frames::new(Box::new(GifFrameIterator::new(self)))
    }
}

/// GIF encoder.
pub struct Encoder<W: Write> {
    w: Option<W>,
    gif_encoder: Option<gif::Encoder<W>>,
}

impl<W: Write> Encoder<W> {
    /// Creates a new GIF encoder.
    pub fn new(w: W) -> Encoder<W> {
        Encoder {
            w: Some(w),
            gif_encoder: None,
        }
    }
    /// Encodes a frame.
    pub fn encode(&mut self, frame: &Frame) -> ImageResult<()> {
        let result;
        if let Some(ref mut encoder) = self.gif_encoder {
            result = encoder.write_frame(frame).map_err(|err| err.into());
        } else {
            let writer = self.w.take().unwrap();
            let mut encoder = gif::Encoder::new(writer, frame.width, frame.height, &[])?;
            result = encoder.write_frame(&frame).map_err(|err| err.into());
            self.gif_encoder = Some(encoder);
        }
        result
    }

    /// Encodes Frames.
    /// Consider using `try_encode_frames` instead to encode an `animation::Frames` like iterator.
    pub fn encode_frames<F>(&mut self, frames: F) -> ImageResult<()>
    where
        F: IntoIterator<Item = animation::Frame>
    {
        for img_frame in frames {
            self.encode_single_frame(img_frame)?;
        }
        Ok(())
    }

    /// Try to encode a collection of `ImageResult<animation::Frame>` objects.
    /// Use this function to encode an `animation::Frames` like iterator.
    /// Whenever an `Err` item is encountered, that value is returned without further actions.
    pub fn try_encode_frames<F>(&mut self, frames: F) -> ImageResult<()>
    where
        F: IntoIterator<Item = ImageResult<animation::Frame>>
    {
        for img_frame in frames {
            self.encode_single_frame(img_frame?)?;
        }
        Ok(())
    }

    fn encode_single_frame(&mut self, img_frame: animation::Frame) -> ImageResult<()> {
        // get the delay before converting img_frame
        let frame_delay = img_frame.delay().to_integer();
        // convert img_frame into RgbaImage
        let rbga_frame = img_frame.into_buffer();

        // Create the gif::Frame from the animation::Frame
        let mut frame = Frame::from_rgba(rbga_frame.width() as u16, rbga_frame.height() as u16, &mut rbga_frame.into_raw());
        frame.delay = frame_delay;

        // encode the gif::Frame
        self.encode(&frame)
    }
}

impl From<gif::DecodingError> for ImageError {
    fn from(err: gif::DecodingError) -> ImageError {
        use self::gif::DecodingError::*;
        match err {
            Format(desc) | Internal(desc) => ImageError::FormatError(desc.into()),
            Io(io_err) => ImageError::IoError(io_err),
        }
    }
}
<|endoftext|>