<commit_before>extern crate std;
use fc::for_other_imageflow_crates::preludes::default::*;
extern crate imageflow_core as fc;
extern crate chrono;

use chrono::UTC;
use fc::clients::stateless;
use std::process::{Command, Output};
#[allow(unused_imports)]
use std::time::{Duration, Instant};

// create dir
// export sample json files
// export sample images
// test a couple remote URLs that we trust to work for years
// use a few embedded ones
// run imageflow in a few different ways

// #[derive(Clone, Debug, PartialEq)]
// enum ToolProduct{
//    CrashedUTF8{stderr: String, stdout: String},
//    NoErrorUTF8{stdout: String},
//    UserErrorUTF8{stdout: String, stderr: String, exit_code: i32},
//    GracefulBugUTF8{stdout: String, stderr: String, exit_code: i32},
//    Exited(Output),
//    Other(Output)
// }
//
//
// fn into_product(r: Output) -> ToolProduct{
//    let stdout_str = str::from_utf8(&r.stdout).map(|s| s.to_owned());
//    let stderr_str = str::from_utf8(&r.stderr).map(|s| s.to_owned());
//    if stderr_str.is_err() || stdout_str.is_err(){
//        if r.status.code() == None {
//            return ToolProduct::Other(r);
//        }else{
//            return ToolProduct::Exited(r);
//        }
//    }
//
//    let stderr_present = r.stderr.len() > 0;
//
//    match r.status.code(){
//        Some(65) => ToolProduct::UserErrorUTF8{ stdout: stdout_str.unwrap(), stderr: stderr_str.unwrap(),exit_code: r.status.code().unwrap()},
//        Some(70) => ToolProduct::GracefulBugUTF8{ stdout: stdout_str.unwrap(), stderr: stderr_str.unwrap(),exit_code: r.status.code().unwrap()},
//        None => ToolProduct::CrashedUTF8{ stdout: stdout_str.unwrap(), stderr: stderr_str.unwrap()},
//        Some(0) if !stderr_present => ToolProduct::NoErrorUTF8{ stdout: stdout_str.unwrap()},
//        Some(_) => ToolProduct::Exited(r)
//    }
// }
#[derive(Clone, Debug, PartialEq)]
struct ToolProduct {
    r: Output,
}
fn into_product(r: Output) -> ToolProduct {
    ToolProduct { r: r }
}

impl ToolProduct {
    //    fn status_code(&self) -> Option<i32> {
    //        match *self {
    //            ToolProduct::NoErrorUTF8 { .. } => Some(0),
    //            ToolProduct::UserErrorUTF8 { exit_code, .. } =>
    //                Some(exit_code),
    //            ToolProduct::GracefulBugUTF8 { exit_code, .. } =>
    //                Some(exit_code),
    //            ToolProduct::Exited(ref out) =>
    //                {out.status.code()}
    //            ToolProduct::Other(ref out) => {out.status.code()}
    //            ToolProduct::CrashedUTF8{ .. } => None
    //        }
    //    }

    fn status_code(&self) -> Option<i32> {
        self.r.status.code()
    }
    fn stdout_bytes(&self) -> usize {
        self.r.stdout.len()
    }
    fn stderr_bytes(&self) -> usize {
        self.r.stderr.len()
    }

    fn stderr_str(&self) -> &str {
        std::str::from_utf8(&self.r.stderr)
            .expect("Implement lossy UTF-8 decoding for test results")
    }
    fn stdout_str(&self) -> &str {
        std::str::from_utf8(&self.r.stdout)
            .expect("Implement lossy UTF-8 decoding for test results")
    }
    fn expect_exit_0_no_output(&self, m: &str) -> &ToolProduct {
        if self.stderr_bytes() > 0 || self.stdout_bytes() > 0 || self.status_code() != Some(0) {
            panic!("{}\nExpected exit code 0 and no output to stderr or stdout. Received {:?}",
                   m,
                   self.r);
        }
        &self
    }
    fn expect_status_code(&self, code: Option<i32>) -> &ToolProduct {
        assert_eq!(code, self.status_code());
        &self
    }
    fn expect_stderr_contains(&self, substring: &str) -> &ToolProduct {
        if !self.stderr_str().contains(substring) {
            panic!("Failed to locate substring {:?} within stderr output {}",
                   substring,
                   self.stderr_str());
        }
        self
    }

    fn expect_stdout_contains(&self, substring: &str) -> &ToolProduct {
        if !self.stdout_str().contains(substring) {
            panic!("Failed to locate substring {:?} within stdout output {}",
                   substring,
                   self.stdout_str());
        }
        self
    }
    fn parse_stdout_as<T>(&self) -> std::result::Result<T, serde_json::error::Error>
        where T: serde::Deserialize
    {
        serde_json::from_slice(&self.r.stdout)
    }

    fn dump(&self) -> &ToolProduct {
        let _ = writeln!(&mut std::io::stderr(),
                         "{:?}\n{}",
                         self.r,
                         self.stderr_str());
        self
    }
}

struct TestContext {
    imageflow_tool: PathBuf,
    test_dir: PathBuf,
}

impl TestContext {
    fn create(parent_folder: &Path, tool_location: Option<PathBuf>) -> TestContext {
        let self_path = match tool_location {
            None => std::env::current_exe().expect("For --self-test to work, we need to know the binary's location. env::current_exe failed"),
            Some(p) => p,
        };
        let dir = parent_folder.join(format!("{:032}", UTC::now().timestamp()));

        if let Err(e) = create_dir_all(&dir) {
            panic!("Failed to create directory {:?} due to {:?}", dir, e);
        }

        let to_path = dir.join("valgrind_suppressions.txt");
        std::fs::copy(Path::new("..").join("valgrind_suppressions.txt"), to_path).unwrap();

        TestContext {
            imageflow_tool: self_path,
            test_dir: dir,
        }
    }

    fn exec(&self, args: &str) -> ToolProduct {
        let args_vec = args.split_whitespace().collect::<Vec<&str>>();
        let dir = self.test_dir.as_path();
        let exe = self.imageflow_tool.as_path();

        writeln!(&mut std::io::stderr(),
                 "Testing {} {}",
                 exe.to_str().unwrap(),
                 args);
        // change working dir to dir
        let mut cmd = Command::new(exe);
        cmd.args(args_vec.as_slice()).current_dir(dir).env("RUST_BACKTRACE", "1");
        let output: Output = cmd.output().expect("Failed to start?");

        // Try to debug segfaults
        if output.status.code() == None {

            std::io::stderr().write(&output.stderr).unwrap();
            std::io::stdout().write(&output.stdout).unwrap();
            println!("exit code {:?}", output.status.code());

            // Killed by signal.
            // 11 Segmentation fault
            // 4 illegal instruction 6 abort 8 floating point error

            let mut cmd = Command::new("valgrind");
            cmd.arg("-q").arg("--error-exitcode=9").arg(exe);
            cmd.args(args_vec.as_slice()).current_dir(dir).env("RUST_BACKTRACE", "1");

            println!("{:?}", cmd);

            let _ = cmd.status(); //.expect("Failed to start valgrind?");
        }

        into_product(output)
    }

    fn write_json<T>(&self, filename: &str, info: T)
        where T: serde::Serialize
    {
        let path = self.test_dir.join(filename);
        let mut file = BufWriter::new(File::create(&path).unwrap());
        write!(file, "{}", serde_json::to_string_pretty(&info).unwrap()).unwrap();
    }

    fn create_blank(&self,
                    filename_without_ext: &str,
                    w: usize,
                    h: usize,
                    encoder: s::EncoderPreset) {

        // Invalid read here; the result of create_canvas is not being accessed correctly.
        let req = stateless::BuildRequest {
            inputs: vec![],
            framewise: s::Framewise::Steps(vec![s::Node::CreateCanvas {
                                                    w: w,
                                                    h: h,
                                                    format: s::PixelFormat::Bgr24,
                                                    color: s::Color::Black,
                                                },
                                                s::Node::Encode {
                                                    io_id: 0,
                                                    preset: encoder,
                                                }]),
            export_graphs_to: None, /* Some(std::path::PathBuf::from(format!("./{}/{}_debug", dir, filename_without_ext))) */
        };
        let result = stateless::LibClient::new().build(req).unwrap();
        let ref out: stateless::BuildOutput = result.outputs[0];
        let mut path = self.test_dir.join(filename_without_ext);
        path.set_extension(&out.file_ext);

        let mut file = BufWriter::new(File::create(&path).unwrap());
        file.write(&out.bytes).unwrap();
    }
}

pub fn run(tool_location: Option<PathBuf>) -> i32 {

    let c = TestContext::create(Path::new("self_tests"), tool_location);
    // encapsulate scenario/example for reuse

    {
        c.write_json("example1.json", s::Build001::example_with_steps());
        c.create_blank("200x200", 200, 200, s::EncoderPreset::libjpegturbo());
        c.create_blank("200x200", 200, 200, s::EncoderPreset::libpng32());

        c.exec("v0.1/build --json example1.json --in 200x200.png 200x200.jpg --out out0.jpg --response out0.json").expect_exit_0_no_output("");
        // TODO: Verify out0.json exists and was created
    }
    {
        c.write_json("example2.json", s::Build001::example_with_steps());
        c.create_blank("200x200", 200, 200, s::EncoderPreset::libjpegturbo());
        c.create_blank("200x200", 200, 200, s::EncoderPreset::libpng32());

        let result =
            c.exec("v0.1/build --json example2.json --in 200x200.png 200x200.jpg --out out0.jpg");

        result.expect_status_code(Some(0));

        let resp: s::Response001 = result.parse_stdout_as::<s::Response001>().unwrap();
        match resp.data {
            s::ResponsePayload::BuildResult(info) => {
                println!("encodes: {:?}", &info.encodes);
                assert!(info.encodes.len() >= 1);
                let encode: &s::EncodeResult = &info.encodes[0];
                assert_eq!(encode.w, 100);
            }
            _ => panic!("Build result not sent"),
        }

    }

    // It seems that Clap always uses status code 1 to indicate a parsing failure
    c.exec("bad command").expect_status_code(Some(1));

    // Write something unexpected, but valid JSON
    c.write_json("random_object.json", s::PngBitDepth::Png24);

    c.exec("v0.1/build --json random_object.json")
        .expect_status_code(Some(65))
        .expect_stderr_contains("InvalidType(Str)");
    // .expect_stdout_contains("")   ; //todo: should respond with JSON version of error message

    {
        // Test having both input and canvas point to the same bitmap
        let a = fluent::fluently().canvas_bgra32(10, 10, s::Color::Black);
        let b = a.branch().copy_rect_from(a.branch(), 0, 0, 5, 5, 0, 0);
        c.write_json("bad__canvas_and_input_equal.json",
                     s::Build001 {
                         builder_config: None,
                         framewise: b.builder().to_framewise(),
                         io: vec![],
                     });
        c.exec("v0.1/build --json bad__canvas_and_input_equal.json").dump();
    }

    {
        // Test a cycle
        let mut nodes = HashMap::new();
        nodes.insert("0".to_owned(), s::Node::FlipH);
        nodes.insert("1".to_owned(), s::Node::FlipV);
        let g = s::Graph {
            edges: vec![s::Edge {
                            from: 0,
                            to: 1,
                            kind: s::EdgeKind::Input,
                        },
                        s::Edge {
                            from: 1,
                            to: 0,
                            kind: s::EdgeKind::Input,
                        }],
            nodes: nodes,
        };
        c.write_json("bad__cycle.json",
                     s::Build001 {
                         builder_config: None,
                         framewise: s::Framewise::Graph(g),
                         io: vec![],
                     });
        c.exec("v0.1/build --json bad__cycle.json").dump();
    }
    {
        // Test a loop TODO: Fix
        let mut nodes = HashMap::new();
        nodes.insert("0".to_owned(), s::Node::FlipH);
        let g = s::Graph {
            edges: vec![s::Edge {
                            from: 0,
                            to: 0,
                            kind: s::EdgeKind::Input,
                        }],
            nodes: nodes,
        };
        c.write_json("bad__loop.json",
                     s::Build001 {
                         builder_config: None,
                         framewise: s::Framewise::Graph(g),
                         io: vec![],
                     });
        let result = c.exec("v0.1/build --json bad__loop.json");
        // Stack overflow
        assert_eq!(result.status_code(), None);
    }

    // Test a cycle
    //    let a = fluent::fluently().create_canvas(10,10,s::PixelFormat::Bgr24, s::Color::Black);
    //    let b = fluent::fluently().create_canvas(10,10,s::PixelFormat::Bgr24, s::Color::Black);
    //
    //    let c = a.branch().copy_rect_from(b);
    //
    //    .copy_rect_from()

    // --json [path]
    // --response [response_json_path]
    // --demo [name]
    // --in 0 a.png b.png
    // --out a.png
    // --local-only (prevent remote URL requests)
    // --no-io-ids (Disables interpretation of numbers in --in and --out as io_id assignment).
    // --no-clobber
    // --debug (verbose, graph export, frame export?)
    // --debug-package

    // file.json --in a.png a.png --out s.png
    // file.json --in 0 a.png 1 b.png --out 3 base64

    println!("Stub self-test");
    0
}
<commit_msg>fix(self_test): windows responds differently to stack overflow<commit_after>extern crate std;
use fc::for_other_imageflow_crates::preludes::default::*;
extern crate imageflow_core as fc;
extern crate chrono;

use chrono::UTC;
use fc::clients::stateless;
use std::process::{Command, Output};
#[allow(unused_imports)]
use std::time::{Duration, Instant};

// create dir
// export sample json files
// export sample images
// test a couple remote URLs that we trust to work for years
// use a few embedded ones
// run imageflow in a few different ways

// #[derive(Clone, Debug, PartialEq)]
// enum ToolProduct{
//    CrashedUTF8{stderr: String, stdout: String},
//    NoErrorUTF8{stdout: String},
//    UserErrorUTF8{stdout: String, stderr: String, exit_code: i32},
//    GracefulBugUTF8{stdout: String, stderr: String, exit_code: i32},
//    Exited(Output),
//    Other(Output)
// }
//
//
// fn into_product(r: Output) -> ToolProduct{
//    let stdout_str = str::from_utf8(&r.stdout).map(|s| s.to_owned());
//    let stderr_str = str::from_utf8(&r.stderr).map(|s| s.to_owned());
//    if stderr_str.is_err() || stdout_str.is_err(){
//        if r.status.code() == None {
//            return ToolProduct::Other(r);
//        }else{
//            return ToolProduct::Exited(r);
//        }
//    }
//
//    let stderr_present = r.stderr.len() > 0;
//
//    match r.status.code(){
//        Some(65) => ToolProduct::UserErrorUTF8{ stdout: stdout_str.unwrap(), stderr: stderr_str.unwrap(),exit_code: r.status.code().unwrap()},
//        Some(70) => ToolProduct::GracefulBugUTF8{ stdout: stdout_str.unwrap(), stderr: stderr_str.unwrap(),exit_code: r.status.code().unwrap()},
//        None => ToolProduct::CrashedUTF8{ stdout: stdout_str.unwrap(), stderr: stderr_str.unwrap()},
//        Some(0) if !stderr_present => ToolProduct::NoErrorUTF8{ stdout: stdout_str.unwrap()},
//        Some(_) => ToolProduct::Exited(r)
//    }
// }
#[derive(Clone, Debug, PartialEq)]
struct ToolProduct {
    r: Output,
}
fn into_product(r: Output) -> ToolProduct {
    ToolProduct { r: r }
}

impl ToolProduct {
    //    fn status_code(&self) -> Option<i32> {
    //        match *self {
    //            ToolProduct::NoErrorUTF8 { .. } => Some(0),
    //            ToolProduct::UserErrorUTF8 { exit_code, .. } =>
    //                Some(exit_code),
    //            ToolProduct::GracefulBugUTF8 { exit_code, .. } =>
    //                Some(exit_code),
    //            ToolProduct::Exited(ref out) =>
    //                {out.status.code()}
    //            ToolProduct::Other(ref out) => {out.status.code()}
    //            ToolProduct::CrashedUTF8{ .. } => None
    //        }
    //    }

    fn status_code(&self) -> Option<i32> {
        self.r.status.code()
    }
    fn stdout_bytes(&self) -> usize {
        self.r.stdout.len()
    }
    fn stderr_bytes(&self) -> usize {
        self.r.stderr.len()
    }

    fn stderr_str(&self) -> &str {
        std::str::from_utf8(&self.r.stderr)
            .expect("Implement lossy UTF-8 decoding for test results")
    }
    fn stdout_str(&self) -> &str {
        std::str::from_utf8(&self.r.stdout)
            .expect("Implement lossy UTF-8 decoding for test results")
    }
    fn expect_exit_0_no_output(&self, m: &str) -> &ToolProduct {
        if self.stderr_bytes() > 0 || self.stdout_bytes() > 0 || self.status_code() != Some(0) {
            panic!("{}\nExpected exit code 0 and no output to stderr or stdout. Received {:?}",
                   m,
                   self.r);
        }
        &self
    }
    fn expect_status_code(&self, code: Option<i32>) -> &ToolProduct {
        assert_eq!(code, self.status_code());
        &self
    }
    fn expect_stderr_contains(&self, substring: &str) -> &ToolProduct {
        if !self.stderr_str().contains(substring) {
            panic!("Failed to locate substring {:?} within stderr output {}",
                   substring,
                   self.stderr_str());
        }
        self
    }

    fn expect_stdout_contains(&self, substring: &str) -> &ToolProduct {
        if !self.stdout_str().contains(substring) {
            panic!("Failed to locate substring {:?} within stdout output {}",
                   substring,
                   self.stdout_str());
        }
        self
    }
    fn parse_stdout_as<T>(&self) -> std::result::Result<T, serde_json::error::Error>
        where T: serde::Deserialize
    {
        serde_json::from_slice(&self.r.stdout)
    }

    fn dump(&self) -> &ToolProduct {
        let _ = writeln!(&mut std::io::stderr(),
                         "{:?}\n{}",
                         self.r,
                         self.stderr_str());
        self
    }
}

struct TestContext {
    imageflow_tool: PathBuf,
    test_dir: PathBuf,
}

impl TestContext {
    fn create(parent_folder: &Path, tool_location: Option<PathBuf>) -> TestContext {
        let self_path = match tool_location {
            None => std::env::current_exe().expect("For --self-test to work, we need to know the binary's location. env::current_exe failed"),
            Some(p) => p,
        };
        let dir = parent_folder.join(format!("{:032}", UTC::now().timestamp()));

        if let Err(e) = create_dir_all(&dir) {
            panic!("Failed to create directory {:?} due to {:?}", dir, e);
        }

        let to_path = dir.join("valgrind_suppressions.txt");
        std::fs::copy(Path::new("..").join("valgrind_suppressions.txt"), to_path).unwrap();

        TestContext {
            imageflow_tool: self_path,
            test_dir: dir,
        }
    }

    fn exec(&self, args: &str) -> ToolProduct {
        let args_vec = args.split_whitespace().collect::<Vec<&str>>();
        let dir = self.test_dir.as_path();
        let exe = self.imageflow_tool.as_path();

        writeln!(&mut std::io::stderr(),
                 "Testing {} {}",
                 exe.to_str().unwrap(),
                 args);
        // change working dir to dir
        let mut cmd = Command::new(exe);
        cmd.args(args_vec.as_slice()).current_dir(dir).env("RUST_BACKTRACE", "1");
        let output: Output = cmd.output().expect("Failed to start?");

        // Try to debug segfaults
        if output.status.code() == None {

            std::io::stderr().write(&output.stderr).unwrap();
            std::io::stdout().write(&output.stdout).unwrap();
            println!("exit code {:?}", output.status.code());

            // Killed by signal.
            // 11 Segmentation fault
            // 4 illegal instruction 6 abort 8 floating point error

            let mut cmd = Command::new("valgrind");
            cmd.arg("-q").arg("--error-exitcode=9").arg(exe);
            cmd.args(args_vec.as_slice()).current_dir(dir).env("RUST_BACKTRACE", "1");

            println!("{:?}", cmd);

            let _ = cmd.status(); //.expect("Failed to start valgrind?");
        }

        into_product(output)
    }

    fn write_json<T>(&self, filename: &str, info: T)
        where T: serde::Serialize
    {
        let path = self.test_dir.join(filename);
        let mut file = BufWriter::new(File::create(&path).unwrap());
        write!(file, "{}", serde_json::to_string_pretty(&info).unwrap()).unwrap();
    }

    fn create_blank(&self,
                    filename_without_ext: &str,
                    w: usize,
                    h: usize,
                    encoder: s::EncoderPreset) {

        // Invalid read here; the result of create_canvas is not being accessed correctly.
        let req = stateless::BuildRequest {
            inputs: vec![],
            framewise: s::Framewise::Steps(vec![s::Node::CreateCanvas {
                                                    w: w,
                                                    h: h,
                                                    format: s::PixelFormat::Bgr24,
                                                    color: s::Color::Black,
                                                },
                                                s::Node::Encode {
                                                    io_id: 0,
                                                    preset: encoder,
                                                }]),
            export_graphs_to: None, /* Some(std::path::PathBuf::from(format!("./{}/{}_debug", dir, filename_without_ext))) */
        };
        let result = stateless::LibClient::new().build(req).unwrap();
        let ref out: stateless::BuildOutput = result.outputs[0];
        let mut path = self.test_dir.join(filename_without_ext);
        path.set_extension(&out.file_ext);

        let mut file = BufWriter::new(File::create(&path).unwrap());
        file.write(&out.bytes).unwrap();
    }
}

pub fn run(tool_location: Option<PathBuf>) -> i32 {

    let c = TestContext::create(Path::new("self_tests"), tool_location);
    // encapsulate scenario/example for reuse

    {
        c.exec("diagnose --show-compilation-info").expect_status_code(Some(0));
        c.exec("--version").expect_status_code(Some(0));
        c.exec("-V").expect_status_code(Some(0));
    }
    {
        c.write_json("example1.json", s::Build001::example_with_steps());
        c.create_blank("200x200", 200, 200, s::EncoderPreset::libjpegturbo());
        c.create_blank("200x200", 200, 200, s::EncoderPreset::libpng32());

        c.exec("v0.1/build --json example1.json --in 200x200.png 200x200.jpg --out out0.jpg --response out0.json").expect_exit_0_no_output("");
        // TODO: Verify out0.json exists and was created
    }
    {
        c.write_json("example2.json", s::Build001::example_with_steps());
        c.create_blank("200x200", 200, 200, s::EncoderPreset::libjpegturbo());
        c.create_blank("200x200", 200, 200, s::EncoderPreset::libpng32());

        let result =
            c.exec("v0.1/build --json example2.json --in 200x200.png 200x200.jpg --out out0.jpg");

        result.expect_status_code(Some(0));

        let resp: s::Response001 = result.parse_stdout_as::<s::Response001>().unwrap();
        match resp.data {
            s::ResponsePayload::BuildResult(info) => {
                println!("encodes: {:?}", &info.encodes);
                assert!(info.encodes.len() >= 1);
                let encode: &s::EncodeResult = &info.encodes[0];
                assert_eq!(encode.w, 100);
            }
            _ => panic!("Build result not sent"),
        }

    }

    // It seems that Clap always uses status code 1 to indicate a parsing failure
    c.exec("bad command").expect_status_code(Some(1));

    // Write something unexpected, but valid JSON
    c.write_json("random_object.json", s::PngBitDepth::Png24);

    c.exec("v0.1/build --json random_object.json")
        .expect_status_code(Some(65))
        .expect_stderr_contains("InvalidType(Str)");
    // .expect_stdout_contains("")   ; //todo: should respond with JSON version of error message

    {
        // Test having both input and canvas point to the same bitmap
        let a = fluent::fluently().canvas_bgra32(10, 10, s::Color::Black);
        let b = a.branch().copy_rect_from(a.branch(), 0, 0, 5, 5, 0, 0);
        c.write_json("bad__canvas_and_input_equal.json",
                     s::Build001 {
                         builder_config: None,
                         framewise: b.builder().to_framewise(),
                         io: vec![],
                     });
        c.exec("v0.1/build --json bad__canvas_and_input_equal.json").dump();
    }

    {
        // Test a cycle
        let mut nodes = HashMap::new();
        nodes.insert("0".to_owned(), s::Node::FlipH);
        nodes.insert("1".to_owned(), s::Node::FlipV);
        let g = s::Graph {
            edges: vec![s::Edge {
                            from: 0,
                            to: 1,
                            kind: s::EdgeKind::Input,
                        },
                        s::Edge {
                            from: 1,
                            to: 0,
                            kind: s::EdgeKind::Input,
                        }],
            nodes: nodes,
        };
        c.write_json("bad__cycle.json",
                     s::Build001 {
                         builder_config: None,
                         framewise: s::Framewise::Graph(g),
                         io: vec![],
                     });
        c.exec("v0.1/build --json bad__cycle.json").dump();
    }
    {
        // Test a loop TODO: Fix
        let mut nodes = HashMap::new();
        nodes.insert("0".to_owned(), s::Node::FlipH);
        let g = s::Graph {
            edges: vec![s::Edge {
                            from: 0,
                            to: 0,
                            kind: s::EdgeKind::Input,
                        }],
            nodes: nodes,
        };
        c.write_json("bad__loop.json",
                     s::Build001 {
                         builder_config: None,
                         framewise: s::Framewise::Graph(g),
                         io: vec![],
                     });
        let result = c.exec("v0.1/build --json bad__loop.json");
        // Stack overflow. None on linux, Some(1073741571) on windows
        //assert_eq!(result., None);
    }

    // Test a cycle
    //    let a = fluent::fluently().create_canvas(10,10,s::PixelFormat::Bgr24, s::Color::Black);
    //    let b = fluent::fluently().create_canvas(10,10,s::PixelFormat::Bgr24, s::Color::Black);
    //
    //    let c = a.branch().copy_rect_from(b);
    //
    //    .copy_rect_from()

    // --json [path]
    // --response [response_json_path]
    // --demo [name]
    // --in 0 a.png b.png
    // --out a.png
    // --local-only (prevent remote URL requests)
    // --no-io-ids (Disables interpretation of numbers in --in and --out as io_id assignment).
    // --no-clobber
    // --debug (verbose, graph export, frame export?)
    // --debug-package

    // file.json --in a.png a.png --out s.png
    // file.json --in 0 a.png 1 b.png --out 3 base64

    println!("Stub self-test");
    0
}
<|endoftext|>


<commit_before>use num::traits::{Zero};

#[derive(PartialEq,Debug)]
pub struct Matrix44<T> {
    pub m: [[T; 4]; 4],
}

impl <T> Matrix44<T> where T: Zero {
    pub fn zero() -> Matrix44<T> {
        Matrix44 { m: [
            [T::zero(), T::zero(), T::zero(), T::zero()],
            [T::zero(), T::zero(), T::zero(), T::zero()],
            [T::zero(), T::zero(), T::zero(), T::zero()],
            [T::zero(), T::zero(), T::zero(), T::zero()], ]}
    }

    pub fn new(mm: [[T; 4]; 4]) -> Matrix44<T> {
        Matrix44 { m : mm }
    }
}

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

    #[test]
    fn should_be_initialized_as_zero_matrix() {
        let m: Matrix44<f64> = Matrix44::zero();

        assert_eq!(m, Matrix44::<f64> { m: [
            [0.0, 0.0, 0.0, 0.0],
            [0.0, 0.0, 0.0, 0.0],
            [0.0, 0.0, 0.0, 0.0],
            [0.0, 0.0, 0.0, 0.0],
            ]});
    }

    #[test]
    fn should_be_initialized_by_coefficients() {
        let m: Matrix44<f64> = Matrix44::new([
            [1.0, 0.0, 0.0, 0.0],
            [0.0, 2.0, 0.0, 0.0],
            [0.0, 0.0, 3.0, 0.0],
            [0.0, 0.0, 4.0, 0.0],
            ]);

        assert_eq!(m, Matrix44::<f64> { m: [
            [1.0, 0.0, 0.0, 0.0],
            [0.0, 2.0, 0.0, 0.0],
            [0.0, 0.0, 3.0, 0.0],
            [0.0, 0.0, 4.0, 0.0],
            ]});
    }
}
<commit_msg>Implement Index trait for Matrix44<commit_after>use num::traits::{Zero};
use std::ops::Index;

#[derive(PartialEq,Debug)]
pub struct Matrix44<T> {
    pub m: [[T; 4]; 4],
}

impl <T> Matrix44<T> where T: Zero {
    pub fn zero() -> Matrix44<T> {
        Matrix44 { m: [
            [T::zero(), T::zero(), T::zero(), T::zero()],
            [T::zero(), T::zero(), T::zero(), T::zero()],
            [T::zero(), T::zero(), T::zero(), T::zero()],
            [T::zero(), T::zero(), T::zero(), T::zero()], ]}
    }

    pub fn new(mm: [[T; 4]; 4]) -> Matrix44<T> {
        Matrix44 { m : mm }
    }
}

impl <T> Index<usize> for Matrix44<T> where T: Zero {
    type Output = [T; 4];

    fn index(&self, index: usize) -> &[T; 4] {
       &(self.m[index])
    }
}

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

    #[test]
    fn should_be_initialized_as_zero_matrix() {
        let m: Matrix44<f64> = Matrix44::zero();

        assert_eq!(m, Matrix44::<f64> { m: [
            [0.0, 0.0, 0.0, 0.0],
            [0.0, 0.0, 0.0, 0.0],
            [0.0, 0.0, 0.0, 0.0],
            [0.0, 0.0, 0.0, 0.0],
            ]});
    }

    #[test]
    fn should_be_initialized_by_coefficients() {
        let m: Matrix44<f64> = Matrix44::new([
            [1.0, 0.0, 0.0, 0.0],
            [0.0, 2.0, 0.0, 0.0],
            [0.0, 0.0, 3.0, 0.0],
            [0.0, 0.0, 4.0, 0.0],
            ]);

        assert_eq!(m, Matrix44::<f64> { m: [
            [1.0, 0.0, 0.0, 0.0],
            [0.0, 2.0, 0.0, 0.0],
            [0.0, 0.0, 3.0, 0.0],
            [0.0, 0.0, 4.0, 0.0],
            ]});
    }

    #[test]
    fn should_index_rows() {
        let m: Matrix44<f64> = Matrix44::new([
            [1.0, 2.0, 3.0, 4.0],
            [2.0, 3.0, 4.0, 5.0],
            [3.0, 4.0, 5.0, 6.0],
            [4.0, 5.0, 6.0, 7.0], ]);

        let row = m[1];

        assert_eq!(row, [2.0, 3.0, 4.0, 5.0]);
    }
}
<|endoftext|>


<commit_before><commit_msg>Add `crypt` convenience function<commit_after><|endoftext|>


<commit_before>use std::borrow::Cow;
use std::fmt;
use std::io::BufRead;
use std::result;

use enum_map::EnumMap;
use features::addr;
use features::lookup::BoxedLookup;
use features::parse_addr::parse_addressed_value_templates;
use features::Lookup;
use system::ParserState;
use {ErrorKind, Result};

/// Multiple addressable parts of the parser state.
///
/// `AddressedValues` represents multiple addresses into the parser state.
/// This can be used to construct feature vectors over the parser state.
pub struct AddressedValues(pub Vec<addr::AddressedValue>);

impl AddressedValues {
    /// Read addressed values specification from a text file.
    ///
    /// Such a text file consists of lines with the format
    ///
    /// ~~~text,no_run
    /// [address+] layer
    /// ~~~
    ///
    /// Multiple addresses are used to e.g. address the left/rightmost
    /// dependency of a token on the stack or buffer.
    pub fn from_buf_read<R>(read: R) -> Result<Self>
    where
        R: BufRead,
    {
        let mut addrs = Vec::new();

        for line in read.lines() {
            let line = line?;

            if line.trim().is_empty() {
                continue;
            }

            let mut layer_addrs = parse_addressed_value_templates(line.as_bytes())?;

            if layer_addrs.len() != 1 {
                bail!(ErrorKind::ConfigError(format!(
                    "Combinatory features are not \
                     supported/necessary: {}",
                    line
                )));
            }

            addrs.push(layer_addrs.remove(0));
        }

        Ok(AddressedValues(addrs))
    }
}

/// A feature vector.
///
/// `InputVector` instances represent feature vectors, also called
/// input layers in neural networks. The input vector is split in
/// vectors for differnt layers. In each layer, the feature is encoded
/// as a 32-bit identifier, which is typically the row of the layer
/// value in an embedding matrix.
pub struct InputVector {
    pub layers: EnumMap<Layer, Vec<i32>>,
}

impl InputVector {
    /// Construct a new input vector.
    pub fn new() -> Self {
        InputVector {
            layers: EnumMap::new(),
        }
    }
}

#[derive(Clone, Copy, Debug, Enum, Eq, PartialEq)]
pub enum Layer {
    Token,
    Tag,
    DepRel,
    Feature,
    Char,
}

impl fmt::Display for Layer {
    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        let s = match *self {
            Layer::Token => "tokens",
            Layer::Tag => "tags",
            Layer::DepRel => "deprels",
            Layer::Feature => "features",
            Layer::Char => "chars",
        };

        f.write_str(s)
    }
}

// I am not sure whether I like the use of Borrow here, but is there another
// convenient way to convert from both addr::Layer and &addr::Layer?
impl<'a> From<&'a addr::Layer> for Layer {
    fn from(layer: &addr::Layer) -> Self {
        match layer {
            &addr::Layer::Token => Layer::Token,
            &addr::Layer::Tag => Layer::Tag,
            &addr::Layer::DepRel => Layer::DepRel,
            &addr::Layer::Feature(_) => Layer::Feature,
            &addr::Layer::Char(_, _) => Layer::Char,
        }
    }
}

/// Lookups for layers.
///
/// This data structure bundles lookups for the different layers (tokens,
/// part-of-speech, etc).
pub struct LayerLookups(EnumMap<Layer, BoxedLookup>);

impl LayerLookups {
    pub fn new() -> Self {
        LayerLookups(EnumMap::new())
    }

    pub fn insert<L>(&mut self, layer: Layer, lookup: L)
    where
        L: Into<Box<Lookup>>,
    {
        self.0[layer] = BoxedLookup::new(lookup);
    }

    /// Get the lookup for a layer.
    pub fn layer_lookup(&self, layer: Layer) -> Option<&Lookup> {
        self.0[layer].as_ref()
    }
}

/// Vectorizer for parser states.
///
/// An `InputVectorizer` vectorizes parser states.
pub struct InputVectorizer {
    layer_lookups: LayerLookups,
    input_layer_addrs: AddressedValues,
}

impl InputVectorizer {
    /// Construct an input vectorizer.
    ///
    /// The vectorizer is constructed from the layer lookups and the parser
    /// state addresses from which the feature vector should be used. The layer
    /// lookups are used to find the indices that represent the features.
    pub fn new(layer_lookups: LayerLookups, input_addrs: AddressedValues) -> Self {
        InputVectorizer {
            layer_lookups: layer_lookups,
            input_layer_addrs: input_addrs,
        }
    }

    /// Get the layer lookups.
    pub fn layer_lookups(&self) -> &LayerLookups {
        &self.layer_lookups
    }

    pub fn layer_sizes(&self) -> EnumMap<Layer, usize> {
        let mut sizes = EnumMap::new();

        for layer in &self.input_layer_addrs.0 {
            match layer.layer {
                addr::Layer::Char(prefix_len, suffix_len) => {
                    sizes[Layer::Char] += prefix_len + suffix_len
                }
                ref layer => sizes[layer.into()] += 1,
            }
        }

        sizes
    }

    /// Vectorize a parser state.
    pub fn realize(&self, state: &ParserState) -> InputVector {
        let mut layers = EnumMap::new();

        for (layer, &size) in &self.layer_sizes() {
            layers[layer] = vec![0; size];
        }

        self.realize_into(state, &mut layers);

        InputVector { layers }
    }

    /// Vectorize a parser state into the given slices.
    pub fn realize_into<S>(&self, state: &ParserState, slices: &mut EnumMap<Layer, S>)
    where
        S: AsMut<[i32]>,
    {
        let mut layer_offsets: EnumMap<Layer, usize> = EnumMap::new();

        for layer in &self.input_layer_addrs.0 {
            let val = layer.get(state);
            let mut offset = &mut layer_offsets[(&layer.layer).into()];

            match layer.layer {
                addr::Layer::Char(prefix_len, suffix_len) => match val {
                    Some(chars) => {
                        for ch in chars.as_ref().chars() {
                            slices[Layer::Char].as_mut()[*offset] = lookup_char(
                                self.layer_lookups.layer_lookup(Layer::Char).unwrap(),
                                ch,
                            );

                            *offset += 1;
                        }
                    }
                    None => {
                        let null_char =
                            self.layer_lookups.layer_lookup(Layer::Char).unwrap().null() as i32;
                        for _ in 0..(prefix_len + suffix_len) {
                            slices[Layer::Char].as_mut()[*offset] = null_char;
                            *offset += 1;
                        }
                    }
                },
                ref layer => {
                    slices[layer.into()].as_mut()[*offset] =
                        lookup_value(self.layer_lookups.layer_lookup(layer.into()).unwrap(), val);
                    *offset += 1;
                }
            }
        }
    }
}

fn lookup_char(lookup: &Lookup, feature: char) -> i32 {
    if feature == '\0' {
        return lookup.null() as i32;
    }

    let feature = feature.to_string();
    if let Some(idx) = lookup.lookup(&feature) {
        idx as i32
    } else {
        lookup.unknown() as i32
    }
}

fn lookup_value(lookup: &Lookup, feature: Option<Cow<str>>) -> i32 {
    match feature {
        Some(f) => lookup.lookup(f.as_ref()).unwrap_or(lookup.unknown()) as i32,
        None => lookup.null() as i32,
    }
}
<commit_msg>Replace some `unwrap`s by `expect`s.<commit_after>use std::borrow::Cow;
use std::fmt;
use std::io::BufRead;
use std::result;

use enum_map::EnumMap;
use features::addr;
use features::lookup::BoxedLookup;
use features::parse_addr::parse_addressed_value_templates;
use features::Lookup;
use system::ParserState;
use {ErrorKind, Result};

/// Multiple addressable parts of the parser state.
///
/// `AddressedValues` represents multiple addresses into the parser state.
/// This can be used to construct feature vectors over the parser state.
pub struct AddressedValues(pub Vec<addr::AddressedValue>);

impl AddressedValues {
    /// Read addressed values specification from a text file.
    ///
    /// Such a text file consists of lines with the format
    ///
    /// ~~~text,no_run
    /// [address+] layer
    /// ~~~
    ///
    /// Multiple addresses are used to e.g. address the left/rightmost
    /// dependency of a token on the stack or buffer.
    pub fn from_buf_read<R>(read: R) -> Result<Self>
    where
        R: BufRead,
    {
        let mut addrs = Vec::new();

        for line in read.lines() {
            let line = line?;

            if line.trim().is_empty() {
                continue;
            }

            let mut layer_addrs = parse_addressed_value_templates(line.as_bytes())?;

            if layer_addrs.len() != 1 {
                bail!(ErrorKind::ConfigError(format!(
                    "Combinatory features are not \
                     supported/necessary: {}",
                    line
                )));
            }

            addrs.push(layer_addrs.remove(0));
        }

        Ok(AddressedValues(addrs))
    }
}

/// A feature vector.
///
/// `InputVector` instances represent feature vectors, also called
/// input layers in neural networks. The input vector is split in
/// vectors for differnt layers. In each layer, the feature is encoded
/// as a 32-bit identifier, which is typically the row of the layer
/// value in an embedding matrix.
pub struct InputVector {
    pub layers: EnumMap<Layer, Vec<i32>>,
}

impl InputVector {
    /// Construct a new input vector.
    pub fn new() -> Self {
        InputVector {
            layers: EnumMap::new(),
        }
    }
}

#[derive(Clone, Copy, Debug, Enum, Eq, PartialEq)]
pub enum Layer {
    Token,
    Tag,
    DepRel,
    Feature,
    Char,
}

impl fmt::Display for Layer {
    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        let s = match *self {
            Layer::Token => "tokens",
            Layer::Tag => "tags",
            Layer::DepRel => "deprels",
            Layer::Feature => "features",
            Layer::Char => "chars",
        };

        f.write_str(s)
    }
}

// I am not sure whether I like the use of Borrow here, but is there another
// convenient way to convert from both addr::Layer and &addr::Layer?
impl<'a> From<&'a addr::Layer> for Layer {
    fn from(layer: &addr::Layer) -> Self {
        match layer {
            &addr::Layer::Token => Layer::Token,
            &addr::Layer::Tag => Layer::Tag,
            &addr::Layer::DepRel => Layer::DepRel,
            &addr::Layer::Feature(_) => Layer::Feature,
            &addr::Layer::Char(_, _) => Layer::Char,
        }
    }
}

/// Lookups for layers.
///
/// This data structure bundles lookups for the different layers (tokens,
/// part-of-speech, etc).
pub struct LayerLookups(EnumMap<Layer, BoxedLookup>);

impl LayerLookups {
    pub fn new() -> Self {
        LayerLookups(EnumMap::new())
    }

    pub fn insert<L>(&mut self, layer: Layer, lookup: L)
    where
        L: Into<Box<Lookup>>,
    {
        self.0[layer] = BoxedLookup::new(lookup);
    }

    /// Get the lookup for a layer.
    pub fn layer_lookup(&self, layer: Layer) -> Option<&Lookup> {
        self.0[layer].as_ref()
    }
}

/// Vectorizer for parser states.
///
/// An `InputVectorizer` vectorizes parser states.
pub struct InputVectorizer {
    layer_lookups: LayerLookups,
    input_layer_addrs: AddressedValues,
}

impl InputVectorizer {
    /// Construct an input vectorizer.
    ///
    /// The vectorizer is constructed from the layer lookups and the parser
    /// state addresses from which the feature vector should be used. The layer
    /// lookups are used to find the indices that represent the features.
    pub fn new(layer_lookups: LayerLookups, input_addrs: AddressedValues) -> Self {
        InputVectorizer {
            layer_lookups: layer_lookups,
            input_layer_addrs: input_addrs,
        }
    }

    /// Get the layer lookups.
    pub fn layer_lookups(&self) -> &LayerLookups {
        &self.layer_lookups
    }

    pub fn layer_sizes(&self) -> EnumMap<Layer, usize> {
        let mut sizes = EnumMap::new();

        for layer in &self.input_layer_addrs.0 {
            match layer.layer {
                addr::Layer::Char(prefix_len, suffix_len) => {
                    sizes[Layer::Char] += prefix_len + suffix_len
                }
                ref layer => sizes[layer.into()] += 1,
            }
        }

        sizes
    }

    /// Vectorize a parser state.
    pub fn realize(&self, state: &ParserState) -> InputVector {
        let mut layers = EnumMap::new();

        for (layer, &size) in &self.layer_sizes() {
            layers[layer] = vec![0; size];
        }

        self.realize_into(state, &mut layers);

        InputVector { layers }
    }

    /// Vectorize a parser state into the given slices.
    pub fn realize_into<S>(&self, state: &ParserState, slices: &mut EnumMap<Layer, S>)
    where
        S: AsMut<[i32]>,
    {
        let mut layer_offsets: EnumMap<Layer, usize> = EnumMap::new();

        for layer in &self.input_layer_addrs.0 {
            let val = layer.get(state);
            let mut offset = &mut layer_offsets[(&layer.layer).into()];

            match layer.layer {
                addr::Layer::Char(prefix_len, suffix_len) => match val {
                    Some(chars) => {
                        for ch in chars.as_ref().chars() {
                            slices[Layer::Char].as_mut()[*offset] = lookup_char(
                                self.layer_lookups
                                    .layer_lookup(Layer::Char)
                                    .expect("Missing layer lookup for: Char"),
                                ch,
                            );

                            *offset += 1;
                        }
                    }
                    None => {
                        let null_char = self
                            .layer_lookups
                            .layer_lookup(Layer::Char)
                            .expect("Missing layer lookup for: Char")
                            .null() as i32;
                        for _ in 0..(prefix_len + suffix_len) {
                            slices[Layer::Char].as_mut()[*offset] = null_char;
                            *offset += 1;
                        }
                    }
                },
                ref layer => {
                    slices[layer.into()].as_mut()[*offset] = lookup_value(
                        self.layer_lookups
                            .layer_lookup(layer.into())
                            .expect(&format!("Missing layer lookup for: {:?}", layer)),
                        val,
                    );
                    *offset += 1;
                }
            }
        }
    }
}

fn lookup_char(lookup: &Lookup, feature: char) -> i32 {
    if feature == '\0' {
        return lookup.null() as i32;
    }

    let feature = feature.to_string();
    if let Some(idx) = lookup.lookup(&feature) {
        idx as i32
    } else {
        lookup.unknown() as i32
    }
}

fn lookup_value(lookup: &Lookup, feature: Option<Cow<str>>) -> i32 {
    match feature {
        Some(f) => lookup.lookup(f.as_ref()).unwrap_or(lookup.unknown()) as i32,
        None => lookup.null() as i32,
    }
}
<|endoftext|>


<commit_before>use redis;
use redis::{RedisResult, Value};
use redis::Value::{Nil, Okay};
use std::fs::File;
use std::path::Path;
use std::io::{self, Read};
use std::thread::sleep;
use std::time::{Duration, Instant};
use rand;
use rand::distributions::{IndependentSample, Range};

const DEFAULT_RETRY_COUNT : u32 = 3;
const DEFAULT_RETRY_DELAY : u32 = 200;
const CLOCK_DRIFT_FACTOR : f32 = 0.01;
const UNLOCK_SCRIPT : &'static str = r"if redis.call('get',KEYS[1]) == ARGV[1] then
                                        return redis.call('del',KEYS[1])
                                      else
                                        return 0
                                      end";

/// The lock manager.
///
/// Implements the necessary functionality to acquire and release locks
/// and handles the Redis connections.
pub struct RedLock {
    /// List of all Redis clients
    pub servers: Vec<redis::Client>,
    quorum: u32,
    retry_count: u32,
    retry_delay: u32
}

pub struct Lock<'a> {
    /// The resource to lock. Will be used as the key in Redis.
    pub resource: &'a [u8],
    /// The value for this lock.
    pub val: Vec<u8>,
    /// Time the lock is still valid.
    /// Should only be slightly smaller than the requested TTL.
    pub validity_time: usize
}

impl RedLock {
    /// Create a new lock manager instance, defined by the given Redis connection uris.
    /// Quorum is defined to be N/2+1, with N being the number of given Redis instances.
    ///
    /// Sample URI: `"redis://127.0.0.1:6379"`
    pub fn new(uris: Vec<&str>) -> RedLock {
        let quorum = (uris.len() as u32) / 2 + 1;
        let mut servers = Vec::with_capacity(uris.len());

        for &uri in uris.iter() {
            servers.push(redis::Client::open(uri).unwrap())
        }

        RedLock {
            servers: servers,
            quorum: quorum,
            retry_count: DEFAULT_RETRY_COUNT,
            retry_delay: DEFAULT_RETRY_DELAY
        }
    }

    /// Get 20 random bytes from `/dev/urandom`.
    pub fn get_unique_lock_id(&self) -> io::Result<Vec<u8>> {
        let file = File::open(&Path::new("/dev/urandom")).unwrap();
        let mut buf = Vec::with_capacity(20);
        match file.take(20).read_to_end(&mut buf) {
            Ok(20) => return Ok(buf),
            Ok(_) => return Err(io::Error::new(io::ErrorKind::Other, "Can't read enough random bytes")),
            Err(e) => return Err(e)
        }
    }

    /// Set retry count and retry delay.
    ///
    /// Retry count defaults to `3`.
    /// Retry delay defaults to `200`.
    pub fn set_retry(&mut self, count: u32, delay: u32) {
        self.retry_count = count;
        self.retry_delay = delay;
    }

    fn lock_instance(&self, client: &redis::Client, resource: &[u8], val: &[u8], ttl: usize) -> bool {
        let con = match client.get_connection() {
            Err(_) => return false,
            Ok(val) => val
        };
        let result : RedisResult<Value> = redis::cmd("SET").arg(resource).arg(val).arg("nx").arg("px").arg(ttl).query(&con);
        match result {
            Ok(Okay) => return true,
            Ok(Nil)  => return false,
            Ok(_)    => return false,
            Err(_)   => return false
        }
    }

    /// Acquire the lock for the given resource and the requested TTL.
    ///
    /// If it succeeds, a `Lock` instance is returned,
    /// including the value and the validity time
    ///
    /// If it fails. `None` is returned.
    /// A user should retry after a short wait time.
    pub fn lock<'a>(&'a self, resource: &'a [u8], ttl: usize) -> Option<Lock> {
        let val = self.get_unique_lock_id().unwrap();

        let between = Range::new(0, self.retry_delay);
        let mut rng = rand::thread_rng();

        for _ in 0..self.retry_count {
            let mut n = 0;
            let start_time = Instant::now();
            for &ref client in self.servers.iter() {
                if self.lock_instance(client, resource, &val, ttl) {
                    n += 1;
                }
            }

            let drift = (ttl as f32 * CLOCK_DRIFT_FACTOR) as usize + 2;
            let elapsed = start_time.elapsed();
            let validity_time = ttl - drift - elapsed.as_secs() as usize * 1000 - elapsed.subsec_nanos() as usize / 1000_000;

            if n >= self.quorum && validity_time > 0 {
                return Some(Lock {
                    resource: resource.clone(),
                    val: val,
                    validity_time: validity_time
                });
            } else {
                for &ref client in self.servers.iter() {
                    self.unlock_instance(client, resource, &val);
                }
            }

            let n = between.ind_sample(&mut rng);
            sleep(Duration::from_millis(n as u64));
        }
        return None
    }

    fn unlock_instance(&self, client: &redis::Client, resource: &[u8], val: &[u8]) -> bool {
        let con = match client.get_connection() {
            Err(_) => return false,
            Ok(val) => val
        };
        let script = redis::Script::new(UNLOCK_SCRIPT);
        let result : RedisResult<i32> = script.key(resource).arg(val).invoke(&con);
        match result {
            Ok(val) => return val == 1,
            Err(_)  => return false
        }
    }

    /// Unlock the given lock.
    ///
    /// Unlock is best effort. It will simply try to contact all instances
    /// and remove the key.
    pub fn unlock(&self, lock: &Lock) {
        for &ref client in self.servers.iter() {
            self.unlock_instance(client, lock.resource, &lock.val);
        }
    }
}

#[test]
fn test_redlock_get_unique_id() {
    let rl = RedLock::new(vec![]);

    match rl.get_unique_lock_id() {
        Ok(id) => {
            assert_eq!(20, id.len());
        },
        err => panic!("Error thrown: {:?}", err)
    }
}

#[test]
fn test_redlock_get_unique_id_uniqueness() {
    let rl = RedLock::new(vec![]);

    let id1 = rl.get_unique_lock_id().unwrap();
    let id2 = rl.get_unique_lock_id().unwrap();

    assert_eq!(20, id1.len());
    assert_eq!(20, id2.len());
    assert!(id1 != id2);
}

#[test]
fn test_redlock_valid_instance() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);
    assert_eq!(3, rl.servers.len());
    assert_eq!(2, rl.quorum);
}

#[test]
fn test_redlock_direct_unlock_fails() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);
    let key = rl.get_unique_lock_id().unwrap();

    let val = rl.get_unique_lock_id().unwrap();
    assert_eq!(false, rl.unlock_instance(&rl.servers[0], &key, &val))
}

#[test]
fn test_redlock_direct_unlock_succeeds() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);
    let key = rl.get_unique_lock_id().unwrap();

    let val = rl.get_unique_lock_id().unwrap();
    let con = rl.servers[0].get_connection().unwrap();
    redis::cmd("SET").arg(&*key).arg(&*val).execute(&con);

    assert_eq!(true, rl.unlock_instance(&rl.servers[0], &key, &val))
}

#[test]
fn test_redlock_direct_lock_succeeds() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);
    let key = rl.get_unique_lock_id().unwrap();

    let val = rl.get_unique_lock_id().unwrap();
    let con = rl.servers[0].get_connection().unwrap();

    redis::cmd("DEL").arg(&*key).execute(&con);
    assert_eq!(true, rl.lock_instance(&rl.servers[0], &*key, &*val, 1000))
}

#[test]
fn test_redlock_unlock() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);
    let key = rl.get_unique_lock_id().unwrap();

    let val = rl.get_unique_lock_id().unwrap();
    let con = rl.servers[0].get_connection().unwrap();
    let _ : () = redis::cmd("SET").arg(&*key).arg(&*val).query(&con).unwrap();

    let lock = Lock { resource: &key, val: val, validity_time: 0 };
    assert_eq!((), rl.unlock(&lock))
}

#[test]
fn test_redlock_lock() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);

    let key = rl.get_unique_lock_id().unwrap();
    match rl.lock(&key, 1000) {
        Some(lock) => {
            assert_eq!(&*key, lock.resource);
            assert_eq!(20, lock.val.len());
            assert!(lock.validity_time > 900);
        },
        None => panic!("Lock failed")
    }
}

#[test]
fn test_redlock_lock_unlock() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);
    let rl2 = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);

    let key = rl.get_unique_lock_id().unwrap();

    let lock = rl.lock(&key, 1000).unwrap();
    assert!(lock.validity_time > 900);

    match rl2.lock(&key, 1000) {
        Some(_l) => panic!("Lock acquired, even though it should be locked"),
        None => ()
    }

    rl.unlock(&lock);

    match rl2.lock(&key, 1000) {
        Some(l) => assert!(l.validity_time > 900),
        None => panic!("Lock couldn't be acquired")
    }
}
<commit_msg>Remove lifetime requirement of the resource in lock(), and make a copy of it in the Lock. Reference the lock manager in the Lock to keep the same lifetime semantics (this could also be PhantomData).<commit_after>use redis;
use redis::{RedisResult, Value};
use redis::Value::{Nil, Okay};
use std::fs::File;
use std::path::Path;
use std::io::{self, Read};
use std::thread::sleep;
use std::time::{Duration, Instant};
use rand;
use rand::distributions::{IndependentSample, Range};

const DEFAULT_RETRY_COUNT : u32 = 3;
const DEFAULT_RETRY_DELAY : u32 = 200;
const CLOCK_DRIFT_FACTOR : f32 = 0.01;
const UNLOCK_SCRIPT : &'static str = r"if redis.call('get',KEYS[1]) == ARGV[1] then
                                        return redis.call('del',KEYS[1])
                                      else
                                        return 0
                                      end";

/// The lock manager.
///
/// Implements the necessary functionality to acquire and release locks
/// and handles the Redis connections.
pub struct RedLock {
    /// List of all Redis clients
    pub servers: Vec<redis::Client>,
    quorum: u32,
    retry_count: u32,
    retry_delay: u32
}

pub struct Lock<'a> {
    /// The resource to lock. Will be used as the key in Redis.
    pub resource: Vec<u8>,
    /// The value for this lock.
    pub val: Vec<u8>,
    /// Time the lock is still valid.
    /// Should only be slightly smaller than the requested TTL.
    pub validity_time: usize,
    /// Used to limit the lifetime of a lock to its lock manager.
    pub lock_manager: &'a RedLock
}

impl RedLock {
    /// Create a new lock manager instance, defined by the given Redis connection uris.
    /// Quorum is defined to be N/2+1, with N being the number of given Redis instances.
    ///
    /// Sample URI: `"redis://127.0.0.1:6379"`
    pub fn new(uris: Vec<&str>) -> RedLock {
        let quorum = (uris.len() as u32) / 2 + 1;
        let mut servers = Vec::with_capacity(uris.len());

        for &uri in uris.iter() {
            servers.push(redis::Client::open(uri).unwrap())
        }

        RedLock {
            servers: servers,
            quorum: quorum,
            retry_count: DEFAULT_RETRY_COUNT,
            retry_delay: DEFAULT_RETRY_DELAY
        }
    }

    /// Get 20 random bytes from `/dev/urandom`.
    pub fn get_unique_lock_id(&self) -> io::Result<Vec<u8>> {
        let file = File::open(&Path::new("/dev/urandom")).unwrap();
        let mut buf = Vec::with_capacity(20);
        match file.take(20).read_to_end(&mut buf) {
            Ok(20) => return Ok(buf),
            Ok(_) => return Err(io::Error::new(io::ErrorKind::Other, "Can't read enough random bytes")),
            Err(e) => return Err(e)
        }
    }

    /// Set retry count and retry delay.
    ///
    /// Retry count defaults to `3`.
    /// Retry delay defaults to `200`.
    pub fn set_retry(&mut self, count: u32, delay: u32) {
        self.retry_count = count;
        self.retry_delay = delay;
    }

    fn lock_instance(&self, client: &redis::Client, resource: &[u8], val: &[u8], ttl: usize) -> bool {
        let con = match client.get_connection() {
            Err(_) => return false,
            Ok(val) => val
        };
        let result : RedisResult<Value> = redis::cmd("SET").arg(resource).arg(val).arg("nx").arg("px").arg(ttl).query(&con);
        match result {
            Ok(Okay) => return true,
            Ok(Nil)  => return false,
            Ok(_)    => return false,
            Err(_)   => return false
        }
    }

    /// Acquire the lock for the given resource and the requested TTL.
    ///
    /// If it succeeds, a `Lock` instance is returned,
    /// including the value and the validity time
    ///
    /// If it fails. `None` is returned.
    /// A user should retry after a short wait time.
    pub fn lock(&self, resource: &[u8], ttl: usize) -> Option<Lock> {
        let val = self.get_unique_lock_id().unwrap();

        let between = Range::new(0, self.retry_delay);
        let mut rng = rand::thread_rng();

        for _ in 0..self.retry_count {
            let mut n = 0;
            let start_time = Instant::now();
            for &ref client in self.servers.iter() {
                if self.lock_instance(client, resource, &val, ttl) {
                    n += 1;
                }
            }

            let drift = (ttl as f32 * CLOCK_DRIFT_FACTOR) as usize + 2;
            let elapsed = start_time.elapsed();
            let validity_time = ttl - drift - elapsed.as_secs() as usize * 1000 - elapsed.subsec_nanos() as usize / 1000_000;

            if n >= self.quorum && validity_time > 0 {
                return Some(Lock {
                    lock_manager: self,
                    resource: resource.to_vec(),
                    val: val,
                    validity_time: validity_time
                });
            } else {
                for &ref client in self.servers.iter() {
                    self.unlock_instance(client, resource, &val);
                }
            }

            let n = between.ind_sample(&mut rng);
            sleep(Duration::from_millis(n as u64));
        }
        return None
    }

    fn unlock_instance(&self, client: &redis::Client, resource: &[u8], val: &[u8]) -> bool {
        let con = match client.get_connection() {
            Err(_) => return false,
            Ok(val) => val
        };
        let script = redis::Script::new(UNLOCK_SCRIPT);
        let result : RedisResult<i32> = script.key(resource).arg(val).invoke(&con);
        match result {
            Ok(val) => return val == 1,
            Err(_)  => return false
        }
    }

    /// Unlock the given lock.
    ///
    /// Unlock is best effort. It will simply try to contact all instances
    /// and remove the key.
    pub fn unlock(&self, lock: &Lock) {
        for &ref client in self.servers.iter() {
            self.unlock_instance(client, &lock.resource, &lock.val);
        }
    }
}

#[test]
fn test_redlock_get_unique_id() {
    let rl = RedLock::new(vec![]);

    match rl.get_unique_lock_id() {
        Ok(id) => {
            assert_eq!(20, id.len());
        },
        err => panic!("Error thrown: {:?}", err)
    }
}

#[test]
fn test_redlock_get_unique_id_uniqueness() {
    let rl = RedLock::new(vec![]);

    let id1 = rl.get_unique_lock_id().unwrap();
    let id2 = rl.get_unique_lock_id().unwrap();

    assert_eq!(20, id1.len());
    assert_eq!(20, id2.len());
    assert!(id1 != id2);
}

#[test]
fn test_redlock_valid_instance() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);
    assert_eq!(3, rl.servers.len());
    assert_eq!(2, rl.quorum);
}

#[test]
fn test_redlock_direct_unlock_fails() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);
    let key = rl.get_unique_lock_id().unwrap();

    let val = rl.get_unique_lock_id().unwrap();
    assert_eq!(false, rl.unlock_instance(&rl.servers[0], &key, &val))
}

#[test]
fn test_redlock_direct_unlock_succeeds() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);
    let key = rl.get_unique_lock_id().unwrap();

    let val = rl.get_unique_lock_id().unwrap();
    let con = rl.servers[0].get_connection().unwrap();
    redis::cmd("SET").arg(&*key).arg(&*val).execute(&con);

    assert_eq!(true, rl.unlock_instance(&rl.servers[0], &key, &val))
}

#[test]
fn test_redlock_direct_lock_succeeds() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);
    let key = rl.get_unique_lock_id().unwrap();

    let val = rl.get_unique_lock_id().unwrap();
    let con = rl.servers[0].get_connection().unwrap();

    redis::cmd("DEL").arg(&*key).execute(&con);
    assert_eq!(true, rl.lock_instance(&rl.servers[0], &*key, &*val, 1000))
}

#[test]
fn test_redlock_unlock() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);
    let key = rl.get_unique_lock_id().unwrap();

    let val = rl.get_unique_lock_id().unwrap();
    let con = rl.servers[0].get_connection().unwrap();
    let _ : () = redis::cmd("SET").arg(&*key).arg(&*val).query(&con).unwrap();

    let lock = Lock { lock_manager: &rl, resource: key, val: val, validity_time: 0 };
    assert_eq!((), rl.unlock(&lock))
}

#[test]
fn test_redlock_lock() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);

    let key = rl.get_unique_lock_id().unwrap();
    match rl.lock(&key, 1000) {
        Some(lock) => {
            assert_eq!(key, lock.resource);
            assert_eq!(20, lock.val.len());
            assert!(lock.validity_time > 900);
        },
        None => panic!("Lock failed")
    }
}

#[test]
fn test_redlock_lock_unlock() {
    let rl = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);
    let rl2 = RedLock::new(vec!["redis://127.0.0.1:6380/", "redis://127.0.0.1:6381/", "redis://127.0.0.1:6382/", ]);

    let key = rl.get_unique_lock_id().unwrap();

    let lock = rl.lock(&key, 1000).unwrap();
    assert!(lock.validity_time > 900);

    match rl2.lock(&key, 1000) {
        Some(_l) => panic!("Lock acquired, even though it should be locked"),
        None => ()
    }

    rl.unlock(&lock);

    match rl2.lock(&key, 1000) {
        Some(l) => assert!(l.validity_time > 900),
        None => panic!("Lock couldn't be acquired")
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::str;
use httparse_orig;
use regex::Regex;
use connection::ToHostAndPort;
use parsable::{Parsable, Sendable, ParseStatus, parse_body};

pub struct Request {
    pub method: String,
    pub path: String,
    pub version: u8,
    pub headers: HashMap<String, Vec<u8>>,
    pub body: Option<Vec<u8>>,
}

impl Request {
    pub fn disassembly_path(&self) -> (&str, &str, u16, &str) {
        let re: Regex = Regex::new(r"^(.+?)://(.+?):?(\d+)?(/.*)?$").unwrap();
        for cap in re.captures_iter(self.path.as_str()) {
            return (cap.at(1).unwrap_or(""),
                    cap.at(2).unwrap_or(""),
                    str::FromStr::from_str(cap.at(3).unwrap_or("")).ok().unwrap_or(80),
                    cap.at(4).unwrap_or(""));
        }

        ("", "", 80, "")
    }

    pub fn must_close(&self) -> bool {
        let conn = self.headers.get("Connection");

        if self.version == 0 && conn.is_some() && conn.unwrap().as_slice() != b"Keep-Alive" {
            return true;
        } else if self.version == 1 && conn.is_some() && conn.unwrap().as_slice() != b"Close" {
            return false;
        }
        return true;
    }
}

impl Parsable for Request {
    type Parsed = Request;

    fn parse(buf: &[u8]) -> ParseStatus<Self::Parsed> {
        let mut headers = [httparse_orig::EMPTY_HEADER; 100];

        let mut req = httparse_orig::Request::new(&mut headers);
        let parse_status = match req.parse(&buf) {
            Ok(status) => status,
            Err(err) => return ParseStatus::Err(err),
        };

        let req_len = match parse_status.is_complete() {
            true => parse_status.unwrap(),
            false => return ParseStatus::InProgress,
        };

        let body = match parse_body(&req.headers, &buf[req_len..]) {
            ParseStatus::Complete(bdy) => bdy,
            ParseStatus::InProgress => return ParseStatus::InProgress,
            ParseStatus::Err(err) => return ParseStatus::Err(err),
        };

        let mut headers_hm = HashMap::new();
        for h in req.headers.iter() {
            headers_hm.insert(String::from(h.name), Vec::from(h.value));
        }

        let req = Request {
            method: String::from(req.method.unwrap()),
            path: String::from(req.path.unwrap()),
            version: req.version.unwrap(),
            headers: headers_hm,
            body: body,
        };

        ParseStatus::Complete(req)
    }
}

impl Sendable for Request {
    fn to_bytes(&self) -> Vec<u8> {
        let path = self.path
                       .split("/")
                       .skip(3)
                       .fold(String::from(""), |acc, s| acc + "/" + s);

        let mut headers = self.headers.clone();
        headers.insert(String::from("Connection"), Vec::from("Close"));

        let hs = headers.iter()
                        .filter(|h| h.0.as_str() != "Keep-Alive")
                        .fold(String::new(), |acc, (k, v)| {
                            return acc +
                                   format!("{}: {}\r\n", &k, str::from_utf8(&v).unwrap()).as_str();
                        });

        let s = format!("{} {} HTTP/1.{}\r\n{}\r\n",
                        self.method.as_str(),
                        path.as_str(),
                        self.version,
                        hs);

        let mut payload: Vec<u8> = Vec::from(s.as_bytes());
        if self.body.is_some() {
            payload.extend_from_slice(self.body.as_ref().unwrap());
        }

        payload
    }
}

impl ToHostAndPort for Request {
    fn to_host_and_port(&self) -> (&str, u16) {
        let (_, host, port, _) = self.disassembly_path();
        (host, port)
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn disassembly_request_path() {
        use super::Request;
        use super::super::Parsable;

        let src_path = "http://example.com:8888/index.html";
        let mut req = Request::new();
        req.path = String::from(src_path);
        let (protocol, host, port, path) = req.disassembly_path();

        assert_eq!(protocol, "http");
        assert_eq!(host, "example.com");
        assert_eq!(port, 8888);
        assert_eq!(path, "/index.html");
    }
}
<commit_msg>modify a request's test<commit_after>use std::collections::HashMap;
use std::str;
use httparse_orig;
use regex::Regex;
use connection::ToHostAndPort;
use parsable::{Parsable, Sendable, ParseStatus, parse_body};

pub struct Request {
    pub method: String,
    pub path: String,
    pub version: u8,
    pub headers: HashMap<String, Vec<u8>>,
    pub body: Option<Vec<u8>>,
}

impl Request {
    pub fn disassembly_path(&self) -> (&str, &str, u16, &str) {
        let re: Regex = Regex::new(r"^(.+?)://(.+?):?(\d+)?(/.*)?$").unwrap();
        for cap in re.captures_iter(self.path.as_str()) {
            return (cap.at(1).unwrap_or(""),
                    cap.at(2).unwrap_or(""),
                    str::FromStr::from_str(cap.at(3).unwrap_or("")).ok().unwrap_or(80),
                    cap.at(4).unwrap_or(""));
        }

        ("", "", 80, "")
    }

    pub fn must_close(&self) -> bool {
        let conn = self.headers.get("Connection");

        if self.version == 0 && conn.is_some() && conn.unwrap().as_slice() != b"Keep-Alive" {
            return true;
        } else if self.version == 1 && conn.is_some() && conn.unwrap().as_slice() != b"Close" {
            return false;
        }
        return true;
    }
}

impl Parsable for Request {
    type Parsed = Request;

    fn parse(buf: &[u8]) -> ParseStatus<Self::Parsed> {
        let mut headers = [httparse_orig::EMPTY_HEADER; 100];

        let mut req = httparse_orig::Request::new(&mut headers);
        let parse_status = match req.parse(&buf) {
            Ok(status) => status,
            Err(err) => return ParseStatus::Err(err),
        };

        let req_len = match parse_status.is_complete() {
            true => parse_status.unwrap(),
            false => return ParseStatus::InProgress,
        };

        let body = match parse_body(&req.headers, &buf[req_len..]) {
            ParseStatus::Complete(bdy) => bdy,
            ParseStatus::InProgress => return ParseStatus::InProgress,
            ParseStatus::Err(err) => return ParseStatus::Err(err),
        };

        let mut headers_hm = HashMap::new();
        for h in req.headers.iter() {
            headers_hm.insert(String::from(h.name), Vec::from(h.value));
        }

        let req = Request {
            method: String::from(req.method.unwrap()),
            path: String::from(req.path.unwrap()),
            version: req.version.unwrap(),
            headers: headers_hm,
            body: body,
        };

        ParseStatus::Complete(req)
    }
}

impl Sendable for Request {
    fn to_bytes(&self) -> Vec<u8> {
        let path = self.path
                       .split("/")
                       .skip(3)
                       .fold(String::from(""), |acc, s| acc + "/" + s);

        let mut headers = self.headers.clone();
        headers.insert(String::from("Connection"), Vec::from("Close"));

        let hs = headers.iter()
                        .filter(|h| h.0.as_str() != "Keep-Alive")
                        .fold(String::new(), |acc, (k, v)| {
                            return acc +
                                   format!("{}: {}\r\n", &k, str::from_utf8(&v).unwrap()).as_str();
                        });

        let s = format!("{} {} HTTP/1.{}\r\n{}\r\n",
                        self.method.as_str(),
                        path.as_str(),
                        self.version,
                        hs);

        let mut payload: Vec<u8> = Vec::from(s.as_bytes());
        if self.body.is_some() {
            payload.extend_from_slice(self.body.as_ref().unwrap());
        }

        payload
    }
}

impl ToHostAndPort for Request {
    fn to_host_and_port(&self) -> (&str, u16) {
        let (_, host, port, _) = self.disassembly_path();
        (host, port)
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn disassembly_request_path() {
        use super::Request;
        use super::super::{Parsable, ParseStatus};

        let bin = b"GET http://example.com:8888/index.html HTTP/1.1\r\n\r\n";

        match Request::parse(bin as &[u8]) {
            ParseStatus::Complete(req) => {
                let (protocol, host, port, path) = req.disassembly_path();
                assert_eq!(protocol, "http");
                assert_eq!(host, "example.com");
                assert_eq!(port, 8888);
                assert_eq!(path, "/index.html");
            }
            _ => panic!("Invalid reuslt"),
        };
    }
}
<|endoftext|>


<commit_before>pub mod vec;
pub mod merge;
pub mod union;

pub trait Set {
    type T;
    type E;
    type I: Iterator<Item = Result<Self::T, Self::E>>;

    fn size(&self) -> usize;
    fn get(&self, index: usize) -> Result<&Self::T, Self::E>;
    fn add(&mut self, item: Self::T) -> Result<(), Self::E>;
    fn into_iter(self) -> Self::I;
}

pub trait SetManager {
    type S: Set;
    type E;

    fn make_set(&mut self, size_hint: Option<usize>) -> Result<Self::S, Self::E>;

    fn reserve(&mut self, _set: &mut Self::S, _additional: usize) -> Result<(), Self::E> {
        // default is to do nothing
        Ok(())
    }
}
<commit_msg>gardening<commit_after>pub mod vec;
pub mod merge;
pub mod union;

pub trait Set {
    type T;
    type E;
    type I: Iterator<Item = Result<Self::T, Self::E>>;

    fn size(&self) -> usize;
    fn get(&self, index: usize) -> Result<&Self::T, Self::E>;
    fn add(&mut self, item: Self::T) -> Result<(), Self::E>;
    fn into_iter(self) -> Self::I;
}

pub trait SetManager {
    type S: Set;
    type E;

    fn make_set(&mut self, size_hint: Option<usize>) -> Result<Self::S, Self::E>;

    fn reserve(&mut self, _set: &mut Self::S, _additional: usize) -> Result<(), Self::E> {
        // default action is to do nothing
        Ok(())
    }
}
<|endoftext|>