<commit_before>use super::screen::{
    DeltaVector,
    ScreenPoint,
    ScreenRect,
};

use std::sync::{
    Arc,
    Mutex,
    Weak,
};

#[derive(Copy, Clone)]
pub enum MouseButton {
    Left,
    Middle,
    Right,
    ScrollWheel
}

#[derive(Copy, Clone)]
pub struct JoystickButton(u32);

#[derive(Copy, Clone)]
pub enum InputEvent {
    KeyDown(u8),
    KeyUp(u8),

    MouseDown(MouseButton, ScreenPoint),
    MouseUp(MouseButton, ScreenPoint),
    MouseMove(ScreenPoint, DeltaVector),

    JoystickMove(Device, DeltaVector),
    JoystickButtonDown(Device, JoystickButton),
    JoystickButtonUp(Device, JoystickButton),

    WmQuit,
    WmResize(ScreenRect),
    WmMove(ScreenPoint)
}

#[derive(Copy, Clone)]
pub struct Device {
    id: u32,
}

/// Keep track of all keys t
type KeysDown = [bool; 256];

/// Since we want cross-thread handling of input, we choose Arc
type ArcInputHandler = Arc<Mutex<Box<InputHandler>>>;
type WeakInputHandler = Weak<Mutex<Box<InputHandler>>>;

pub trait InputHandler {
    fn event(&mut self, target_id: u32, event: &InputEvent);

    #[cfg(test)] fn keys(&self) -> &KeysDown;
}

pub trait InputEventProducer {
    fn add_handler(&mut self, handler: &ArcInputHandler);
    // fn remove_handler(&mut self, handler: ArcInputHandler);
    fn publish(&mut self, event: &InputEvent);
}

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

    struct KeydownHandler { keys_down: KeysDown }
    impl KeydownHandler { fn keys(&self) -> &KeysDown { &self.keys_down } }
    impl InputHandler for KeydownHandler {

        fn event(&mut self, target_id: u32, event: &InputEvent) {
            match event {
                &InputEvent::KeyDown(code) => {
                    self.keys_down[code as usize] = true;
                },
                &InputEvent::KeyUp(code) => {
                    self.keys_down[code as usize] = false;
                },
                _ => { panic!("Nope!"); }
            }
        }

        #[cfg(test)] fn keys(&self) -> &KeysDown {
            &self.keys_down
        }
    }

    struct KeydownProducer {
        handlers: Vec<WeakInputHandler>,
    }

    impl InputEventProducer for KeydownProducer {
        fn add_handler(&mut self, handler: &ArcInputHandler) {
            let wh: WeakInputHandler = Arc::downgrade(handler);
            self.handlers.push(wh);
        }
/*        fn remove_handler(&mut self, handler: ArcInputHandler) {
            let found = self.handlers.iter().position(|h| {
                let it = h.upgrade();
                it.is_some() && it.unwrap() == handler
            });
            match found {
                Some(p) => {
                    self.handlers.remove(p);
                },
                None => {}
            }
        }
        */
        fn publish(&mut self, event: &InputEvent) {
            for handler in self.handlers.iter() {
                match handler.upgrade() {
                    Some(a) => {
                        match a.lock() {
                            Err(e) => {
                                panic!("unable to publish event to handler {}", e);
                            },
                            Ok(ref mut i) => {
                                i.event(0, event);
                            }

                        }
                    },
                    None => {} //dropped
                }
            }
        }
    }

    #[test]
    fn input_publisher_publishes_events() {

        let mut producer = KeydownProducer{ handlers: Vec::new() };

        // need these type hints for trait object
        let b1: Box<InputHandler> = Box::new(KeydownHandler{ keys_down:[false; 256] });
        let b2: Box<InputHandler> = Box::new(KeydownHandler{ keys_down:[false; 256] });

        let mut handler1 = Arc::new( Mutex::new(b1) );
        let mut handler2 = Arc::new( Mutex::new(b2) );

        producer.add_handler( &handler1 );
        producer.add_handler( &handler2 );

        let event = InputEvent::KeyDown(42);
        producer.publish(&event);

        let pressed = handler1.lock().unwrap().keys()[42];
        let pressed2 = handler2.lock().unwrap().keys()[42];
        assert!(pressed && pressed2);

    }

    #[test]
    fn input_handler_handles_events() {
        let mut handler = KeydownHandler{ keys_down: [false; 256] };
        let down_event = InputEvent::KeyDown(42);
        handler.event(0, &down_event);

        let up_event = InputEvent::KeyUp(42);
        assert_eq!(handler.keys()[42], true);

        handler.event(0, &up_event);
        assert_eq!(handler.keys()[42], false);
    }
}

<commit_msg>shortening mutex ref<commit_after>use super::screen::{
    DeltaVector,
    ScreenPoint,
    ScreenRect,
};

use std::sync::{
    Arc,
    Mutex,
    Weak,
};

#[derive(Copy, Clone)]
pub enum MouseButton {
    Left,
    Middle,
    Right,
    ScrollWheel
}

#[derive(Copy, Clone)]
pub struct JoystickButton(u32);

#[derive(Copy, Clone)]
pub enum InputEvent {
    KeyDown(u8),
    KeyUp(u8),

    MouseDown(MouseButton, ScreenPoint),
    MouseUp(MouseButton, ScreenPoint),
    MouseMove(ScreenPoint, DeltaVector),

    JoystickMove(Device, DeltaVector),
    JoystickButtonDown(Device, JoystickButton),
    JoystickButtonUp(Device, JoystickButton),

    WmQuit,
    WmResize(ScreenRect),
    WmMove(ScreenPoint)
}

#[derive(Copy, Clone)]
pub struct Device {
    id: u32,
}

/// Keep track of all keys t
type KeysDown = [bool; 256];

/// Since we want cross-thread handling of input, we choose Arc
type ArcInputHandler = Arc<Mutex<Box<InputHandler>>>;
type WeakInputHandler = Weak<Mutex<Box<InputHandler>>>;

pub trait InputHandler {
    fn event(&mut self, target_id: u32, event: &InputEvent);

    #[cfg(test)] fn keys(&self) -> &KeysDown;
}

pub trait InputEventProducer {
    fn add_handler(&mut self, handler: &ArcInputHandler);
    // fn remove_handler(&mut self, handler: ArcInputHandler);
    fn publish(&mut self, event: &InputEvent);
}

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

    struct KeydownHandler { keys_down: KeysDown }
    impl KeydownHandler { fn keys(&self) -> &KeysDown { &self.keys_down } }
    impl InputHandler for KeydownHandler {

        fn event(&mut self, target_id: u32, event: &InputEvent) {
            match event {
                &InputEvent::KeyDown(code) => {
                    self.keys_down[code as usize] = true;
                },
                &InputEvent::KeyUp(code) => {
                    self.keys_down[code as usize] = false;
                },
                _ => { panic!("Nope!"); }
            }
        }

        #[cfg(test)] fn keys(&self) -> &KeysDown {
            &self.keys_down
        }
    }

    struct KeydownProducer {
        handlers: Vec<WeakInputHandler>,
    }

    impl InputEventProducer for KeydownProducer {
        fn add_handler(&mut self, handler: &ArcInputHandler) {
            let wh: WeakInputHandler = Arc::downgrade(handler);
            self.handlers.push(wh);
        }

        fn publish(&mut self, event: &InputEvent) {
            for handler in self.handlers.iter() {
                match handler.upgrade() {
                    Some(a) => {
                        a.lock().unwrap().event(0, event);
                    },
                    None => {} //dropped
                }
            }
        }
    }

    #[test]
    fn input_publisher_publishes_events() {

        let mut producer = KeydownProducer{ handlers: Vec::new() };

        // need these type hints for trait object
        let b1: Box<InputHandler> = Box::new(KeydownHandler{ keys_down:[false; 256] });
        let b2: Box<InputHandler> = Box::new(KeydownHandler{ keys_down:[false; 256] });

        let mut handler1 = Arc::new( Mutex::new(b1) );
        let mut handler2 = Arc::new( Mutex::new(b2) );

        producer.add_handler( &handler1 );
        producer.add_handler( &handler2 );

        let event = InputEvent::KeyDown(42);
        producer.publish(&event);

        let pressed = handler1.lock().unwrap().keys()[42];
        let pressed2 = handler2.lock().unwrap().keys()[42];
        assert!(pressed && pressed2);

    }

    #[test]
    fn input_handler_handles_events() {
        let mut handler = KeydownHandler{ keys_down: [false; 256] };
        let down_event = InputEvent::KeyDown(42);
        handler.event(0, &down_event);

        let up_event = InputEvent::KeyUp(42);
        assert_eq!(handler.keys()[42], true);

        handler.event(0, &up_event);
        assert_eq!(handler.keys()[42], false);
    }
}

<|endoftext|>


<commit_before>extern mod linenoise;

mod rush {
    extern mod linenoise;
    extern mod core;
    use core::run;

    pub fn exec_command(stdin_fd: libc::c_int, command: &str) -> libc::c_int {
        let pipe_out = os::pipe();
        let pipe_err = os::pipe();
        let mut args: ~[~str] = ~[];
        let mut prog = ~"";
        let mut first = true;
        str::each_split_char(command, ' ', |item| {
            if (first) {
                prog = copy item.to_owned();
                first = false;
            } else {
                args.push(item.to_owned());
            }
            true
        });
        let pid = run::spawn_process(
                prog, args, &None, &None,
                stdin_fd, pipe_out.out, pipe_err.out);
        os::close(pipe_out.out);
        os::close(pipe_err.out);
        do task::spawn_sched(task::SingleThreaded) || {
            run::waitpid(pid);
        }
        pipe_out.in
    }

    pub fn handle_input(line: &str) {
        linenoise::history_add(line);
        linenoise::history_save("history.txt");
        let mut commands: ~[&str] = ~[];
        str::each_split_char_no_trailing(line, '|', |command| { commands.push(str::trim(command)); true });
        let pipe_in = os::pipe();
        let std_out = vec::foldl(pipe_in.in, commands, |stdin, command| {
            exec_command(stdin, *command)
        });
        os::close(pipe_in.out);

        do task::spawn_sched(task::SingleThreaded) || {
            unsafe {
                let file = os::fdopen(std_out);
                let reader = io::FILE_reader(file, false);
                let buf = io::with_bytes_writer(|writer| {
                    let mut bytes = [0, ..4096];
                    while !reader.eof() {
                        let nread = reader.read(bytes, bytes.len());
                        writer.write(bytes.slice(0, nread));
                        io::print(str::from_bytes(bytes.slice(0, nread)))
                    }
                });
                os::fclose(file);
            }
        }
    }

}

fn main() {
    linenoise::set_multiline(true);
    loop {
        let line = linenoise::init("rush: ");
        rush::handle_input(line);
    }
}
<commit_msg>Write to fd's<commit_after>extern mod linenoise;

mod rush {
    extern mod core;
    use core::run;

    pub struct JobOutput {
        stdout: libc::c_int,
        stderr: libc::c_int,
    }

    pub fn exec_command(input: JobOutput, command: &str) -> JobOutput {
        let pipe_out = os::pipe();
        let pipe_err = os::pipe();
        let mut args: ~[~str] = ~[];
        let mut prog = ~"";
        let mut first = true;
        str::each_split_char(command, ' ', |item| {
            if (first) {
                prog = copy item.to_owned();
                first = false;
            } else {
                args.push(item.to_owned());
            }
            true
        });
        let pid = run::spawn_process(
                prog, args, &None, &None,
                input.stdout, pipe_out.out, pipe_err.out);
        os::close(pipe_out.out);
        os::close(pipe_err.out);
        do task::spawn_sched(task::SingleThreaded) || {
            run::waitpid(pid);
        }
        JobOutput{
            stdout: pipe_out.in,
            stderr: pipe_err.in,
        }
    }

    pub fn handle_input(line: &str) {
        let mut commands: ~[&str] = ~[];
        str::each_split_char_no_trailing(line, '|', |command| { commands.push(str::trim(command)); true });
        let fake_out = JobOutput{
            stdout: -1,
            stderr: -1,
        };
        let job_output = vec::foldl(fake_out, commands, |stdin, command| {
            exec_command(stdin, *command)
        });
        proxy_fds(job_output.stdout, libc::STDOUT_FILENO as libc::c_int);
        proxy_fds(job_output.stderr, libc::STDERR_FILENO as libc::c_int);
    }
    pub fn proxy_fds(input: libc::c_int, output: libc::c_int) {
        if (input == -1) { return }
        do task::spawn_sched(task::SingleThreaded) || {
            unsafe {
                let output = io::fd_writer(output, false);
                let file = os::fdopen(input);
                let reader = io::FILE_reader(file, false);
                let mut bytes = [0, ..4096];
                while !reader.eof() {
                    let nread = reader.read(bytes, bytes.len());
                    output.write(bytes.slice(0, nread));
                }
                os::fclose(file);
            }
        }
    }

}

fn main() {
    linenoise::set_multiline(true);
    loop {
        let line = linenoise::init("rush: ");
        rush::handle_input(line);
        linenoise::history_add(line);
        linenoise::history_save("history.txt");
    }
}
<|endoftext|>


<commit_before>//! System calls for getting the terminal size.
//!
//! Getting the terminal size is performed using an ioctl command that takes
//! the file handle to the terminal -- which in this case, is stdout -- and
//! populates a structure containing the values.
//!
//! The size is needed when the user wants the output formatted into columns:
//! the default grid view, or the hybrid grid-details view.

use std::mem::zeroed;
use libc::{c_int, c_ushort, c_ulong, STDOUT_FILENO};

/// The number of rows and columns of a terminal.
struct Winsize {
    ws_row: c_ushort,
    ws_col: c_ushort,
}

// Unfortunately the actual command is not standardised...

#[cfg(any(target_os = "linux", target_os = "android"))]
static TIOCGWINSZ: c_ulong = 0x5413;

#[cfg(any(target_os = "macos", target_os = "ios", target_os = "dragonfly"))]
static TIOCGWINSZ: c_ulong = 0x40087468;

extern {
    pub fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int;
}

/// Runs the ioctl command. Returns (0, 0) if output is not to a terminal, or
/// there is an error. (0, 0) is an invalid size to have anyway, which is why
/// it can be used as a nil value.
unsafe fn get_dimensions() -> Winsize {
    let mut window: Winsize = zeroed();
    let result = ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut window);

    if result == -1 {
        zeroed()
    }
    else {
        window
    }
}

/// Query the current processes's output, returning its width and height as a
/// number of characters. Returns `None` if the output isn't to a terminal.
pub fn dimensions() -> Option<(usize, usize)> {
    let w = unsafe { get_dimensions() };

    if w.ws_col == 0 || w.ws_row == 0 {
        None
    }
    else {
        Some((w.ws_col as usize, w.ws_row as usize))
    }
}
<commit_msg>Fix getting tty window size on more BSDs<commit_after>//! System calls for getting the terminal size.
//!
//! Getting the terminal size is performed using an ioctl command that takes
//! the file handle to the terminal -- which in this case, is stdout -- and
//! populates a structure containing the values.
//!
//! The size is needed when the user wants the output formatted into columns:
//! the default grid view, or the hybrid grid-details view.

use std::mem::zeroed;
use libc::{c_int, c_ushort, c_ulong, STDOUT_FILENO};

/// The number of rows and columns of a terminal.
struct Winsize {
    ws_row: c_ushort,
    ws_col: c_ushort,
}

// Unfortunately the actual command is not standardised...

#[cfg(any(target_os = "linux", target_os = "android"))]
static TIOCGWINSZ: c_ulong = 0x5413;

#[cfg(any(target_os = "macos",
          target_os = "ios",
          target_os = "bitrig",
          target_os = "dragonfly",
          target_os = "freebsd",
          target_os = "netbsd",
          target_os = "openbsd"))]
static TIOCGWINSZ: c_ulong = 0x40087468;

extern {
    pub fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int;
}

/// Runs the ioctl command. Returns (0, 0) if output is not to a terminal, or
/// there is an error. (0, 0) is an invalid size to have anyway, which is why
/// it can be used as a nil value.
unsafe fn get_dimensions() -> Winsize {
    let mut window: Winsize = zeroed();
    let result = ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut window);

    if result == -1 {
        zeroed()
    }
    else {
        window
    }
}

/// Query the current processes's output, returning its width and height as a
/// number of characters. Returns `None` if the output isn't to a terminal.
pub fn dimensions() -> Option<(usize, usize)> {
    let w = unsafe { get_dimensions() };

    if w.ws_col == 0 || w.ws_row == 0 {
        None
    }
    else {
        Some((w.ws_col as usize, w.ws_row as usize))
    }
}
<|endoftext|>


<commit_before>use std::io::{Read, Write};
use std::net::{TcpStream, TcpListener};
use std::thread;

use super::*;

macro_rules! p {
    ($e:expr) => {
        match $e {
            Ok(r) => r,
            Err(e) => panic!("{:?}", e),
        }
    }
}

    #[test]
    fn connect_google() {
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        let s = p!(TcpStream::connect("google.com:443"));
        let mut socket = p!(builder.connect("google.com", s));

        p!(socket.write_all(b"GET / HTTP/1.0\r\n\r\n"));
        let mut result = vec![];
        p!(socket.read_to_end(&mut result));

        println!("{}", String::from_utf8_lossy(&result));
        assert!(result.starts_with(b"HTTP/1.0"));
        assert!(result.ends_with(b"\r\n") || result.ends_with(b""));
    }

    #[test]
    fn connect_bad_hostname() {
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        let s = p!(TcpStream::connect("google.com:443"));
        builder.connect("goggle.com", s).unwrap_err();
    }

    #[test]
    fn connect_bad_hostname_ignored() {
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        let s = p!(TcpStream::connect("google.com:443"));
        builder.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(s).unwrap();
    }

    #[test]
    fn server() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            let mut socket = p!(builder.accept(socket));

            let mut buf = [0; 5];
            p!(socket.read_exact(&mut buf));
            assert_eq!(&buf, b"hello");

            p!(socket.write_all(b"world"));
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        let builder = p!(builder.build());
        let mut socket = p!(builder.connect("foobar.com", socket));

        p!(socket.write_all(b"hello"));
        let mut buf = vec![];
        p!(socket.read_to_end(&mut buf));
        assert_eq!(buf, b"world");

        p!(j.join());
    }

    #[test]
    fn server_tls11_only() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let mut builder = p!(TlsAcceptor::builder(pkcs12));
        p!(builder.supported_protocols(&[Protocol::Tlsv11]));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            let mut socket = p!(builder.accept(socket));

            let mut buf = [0; 5];
            p!(socket.read_exact(&mut buf));
            assert_eq!(&buf, b"hello");

            p!(socket.write_all(b"world"));
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        p!(builder.supported_protocols(&[Protocol::Tlsv11]));
        let builder = p!(builder.build());
        let mut socket = p!(builder.connect("foobar.com", socket));

        p!(socket.write_all(b"hello"));
        let mut buf = vec![];
        p!(socket.read_to_end(&mut buf));
        assert_eq!(buf, b"world");

        p!(j.join());
    }

    #[test]
    fn server_no_shared_protocol() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let mut builder = p!(TlsAcceptor::builder(pkcs12));
        p!(builder.supported_protocols(&[Protocol::Tlsv12]));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            assert!(builder.accept(socket).is_err());
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        p!(builder.supported_protocols(&[Protocol::Sslv3, Protocol::Tlsv10, Protocol::Tlsv11]));
        let builder = p!(builder.build());
        assert!(builder.connect("foobar.com", socket).is_err());

        p!(j.join());
    }

    #[test]
    fn server_untrusted() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            // FIXME should assert error
            // https://github.com/steffengy/schannel-rs/issues/20
            let _ = builder.accept(socket);
        });

        let socket = p!(TcpStream::connect(("localhost", port)));
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        builder.connect("foobar.com", socket).unwrap_err();

        p!(j.join());
    }

    #[test]
    fn shutdown() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            let mut socket = p!(builder.accept(socket));

            let mut buf = [0; 5];
            p!(socket.read_exact(&mut buf));
            assert_eq!(&buf, b"hello");

            assert_eq!(p!(socket.read(&mut buf)), 0);
            p!(socket.shutdown());
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        let builder = p!(builder.build());
        let mut socket = p!(builder.connect("foobar.com", socket));

        p!(socket.write_all(b"hello"));
        p!(socket.shutdown());

        p!(j.join());
    }
<commit_msg>Add mod around tests to prevent losing indenting<commit_after>use std::io::{Read, Write};
use std::net::{TcpStream, TcpListener};
use std::thread;

use super::*;

macro_rules! p {
    ($e:expr) => {
        match $e {
            Ok(r) => r,
            Err(e) => panic!("{:?}", e),
        }
    }
}

mod tests {
    #[test]
    fn connect_google() {
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        let s = p!(TcpStream::connect("google.com:443"));
        let mut socket = p!(builder.connect("google.com", s));

        p!(socket.write_all(b"GET / HTTP/1.0\r\n\r\n"));
        let mut result = vec![];
        p!(socket.read_to_end(&mut result));

        println!("{}", String::from_utf8_lossy(&result));
        assert!(result.starts_with(b"HTTP/1.0"));
        assert!(result.ends_with(b"\r\n") || result.ends_with(b""));
    }

    #[test]
    fn connect_bad_hostname() {
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        let s = p!(TcpStream::connect("google.com:443"));
        builder.connect("goggle.com", s).unwrap_err();
    }

    #[test]
    fn connect_bad_hostname_ignored() {
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        let s = p!(TcpStream::connect("google.com:443"));
        builder.danger_connect_without_providing_domain_for_certificate_verification_and_server_name_indication(s).unwrap();
    }

    #[test]
    fn server() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            let mut socket = p!(builder.accept(socket));

            let mut buf = [0; 5];
            p!(socket.read_exact(&mut buf));
            assert_eq!(&buf, b"hello");

            p!(socket.write_all(b"world"));
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        let builder = p!(builder.build());
        let mut socket = p!(builder.connect("foobar.com", socket));

        p!(socket.write_all(b"hello"));
        let mut buf = vec![];
        p!(socket.read_to_end(&mut buf));
        assert_eq!(buf, b"world");

        p!(j.join());
    }

    #[test]
    fn server_tls11_only() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let mut builder = p!(TlsAcceptor::builder(pkcs12));
        p!(builder.supported_protocols(&[Protocol::Tlsv11]));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            let mut socket = p!(builder.accept(socket));

            let mut buf = [0; 5];
            p!(socket.read_exact(&mut buf));
            assert_eq!(&buf, b"hello");

            p!(socket.write_all(b"world"));
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        p!(builder.supported_protocols(&[Protocol::Tlsv11]));
        let builder = p!(builder.build());
        let mut socket = p!(builder.connect("foobar.com", socket));

        p!(socket.write_all(b"hello"));
        let mut buf = vec![];
        p!(socket.read_to_end(&mut buf));
        assert_eq!(buf, b"world");

        p!(j.join());
    }

    #[test]
    fn server_no_shared_protocol() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let mut builder = p!(TlsAcceptor::builder(pkcs12));
        p!(builder.supported_protocols(&[Protocol::Tlsv12]));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            assert!(builder.accept(socket).is_err());
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        p!(builder.supported_protocols(&[Protocol::Sslv3, Protocol::Tlsv10, Protocol::Tlsv11]));
        let builder = p!(builder.build());
        assert!(builder.connect("foobar.com", socket).is_err());

        p!(j.join());
    }

    #[test]
    fn server_untrusted() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            // FIXME should assert error
            // https://github.com/steffengy/schannel-rs/issues/20
            let _ = builder.accept(socket);
        });

        let socket = p!(TcpStream::connect(("localhost", port)));
        let builder = p!(TlsConnector::builder());
        let builder = p!(builder.build());
        builder.connect("foobar.com", socket).unwrap_err();

        p!(j.join());
    }

    #[test]
    fn shutdown() {
        let buf = include_bytes!("../test/identity.p12");
        let pkcs12 = p!(Pkcs12::from_der(buf, "mypass"));
        let builder = p!(TlsAcceptor::builder(pkcs12));
        let builder = p!(builder.build());

        let listener = p!(TcpListener::bind("0.0.0.0:0"));
        let port = p!(listener.local_addr()).port();

        let j = thread::spawn(move || {
            let socket = p!(listener.accept()).0;
            let mut socket = p!(builder.accept(socket));

            let mut buf = [0; 5];
            p!(socket.read_exact(&mut buf));
            assert_eq!(&buf, b"hello");

            assert_eq!(p!(socket.read(&mut buf)), 0);
            p!(socket.shutdown());
        });

        let root_ca = include_bytes!("../test/root-ca.der");
        let root_ca = Certificate::from_der(root_ca).unwrap();

        let socket = p!(TcpStream::connect(("localhost", port)));
        let mut builder = p!(TlsConnector::builder());
        p!(builder.add_root_certificate(root_ca));
        let builder = p!(builder.build());
        let mut socket = p!(builder.connect("foobar.com", socket));

        p!(socket.write_all(b"hello"));
        p!(socket.shutdown());

        p!(j.join());
    }
}<|endoftext|>


<commit_before>use num::{self};
use num::traits::{Zero, WrappingAdd, WrappingSub, WrappingMul, CheckedShl, CheckedShr, Signed};
use std::mem;
use std::cmp::{min};
use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign, Shl, Shr, Neg, Index};
use std::fmt::Debug;

pub trait Integer:
  'static + num::PrimInt + num::Integer + num::FromPrimitive +
  AddAssign <Self> + SubAssign <Self> + MulAssign <Self> +
  WrappingAdd + WrappingSub + WrappingMul +
  for<'a> Add <&'a Self, Output = Self> + for<'a> Sub <&'a Self, Output = Self> + for<'a> Mul <&'a Self, Output = Self> +
  CheckedShl + CheckedShr + Shl <u32, Output = Self> + Shr <u32, Output = Self> +
  Debug {}
impl <T: 'static + num::PrimInt + num::Integer + num::FromPrimitive + AddAssign <Self> + SubAssign <Self> + MulAssign <Self> + WrappingAdd + WrappingSub + WrappingMul + for<'a> Add <&'a Self, Output = Self> + for<'a> Sub <&'a Self, Output = Self> + for<'a> Mul <&'a Self, Output = Self> + CheckedShl + CheckedShr + Shl <u32, Output = Self> + Shr <u32, Output = Self> + Debug> Integer for T {}

pub trait HasCoordinates
   {
  type Coordinate: Integer + Signed + Vector + HasCoordinates <Coordinate = Self::Coordinate>;}

pub trait Vector:
  'static + Sized + Copy + Clone + HasCoordinates +
  Add <Self, Output = Self> + Sub <Self, Output = Self> + Mul <<Self as HasCoordinates>::Coordinate, Output = Self> +
  for<'a> Add <&'a Self, Output = Self> + for<'a> Sub <&'a Self, Output = Self> + //for<'a> Mul <&'a <Self as HasCoordinates>::Coordinate, Output = Self> +
  AddAssign <Self> + SubAssign <Self> + MulAssign <<Self as HasCoordinates>::Coordinate> +
  for<'a> AddAssign <&'a Self> + for<'a> SubAssign <&'a Self> + //for<'a> MulAssign <&'a <Self as HasCoordinates>::Coordinate> +
  Zero + Neg <Output = Self>
  {
  const DIMENSIONS: usize;
  fn coordinate (&self, which: usize)->Self::Coordinate;
  fn set_coordinate (&mut self, which: usize, value: Self::Coordinate);
}

pub mod impls {
  use super::*;
  use nalgebra::*;
  macro_rules! impl_vector {
    ($([$coordinates: expr, $Vector: ident],)*) => {
      $(
        impl <T: Integer + Signed + Vector + HasCoordinates <Coordinate = T>> HasCoordinates for $Vector <T> {type Coordinate = T;}
        impl <T: Integer + Signed + Vector + HasCoordinates <Coordinate = T>> Vector for $Vector <T> {
          const DIMENSIONS: usize = $coordinates;
          fn coordinate (&self, which: usize)->Self::Coordinate {self [which]}
          fn set_coordinate (&mut self, which: usize, value: Self::Coordinate) {self [which] = value}
        }
      )*
    }
  }
  macro_rules! impl_integer {
    ($($Integer: ident,)*) => {
      $(
        impl HasCoordinates for $Integer {type Coordinate = $Integer;}
        impl Vector for $Integer {
          const DIMENSIONS: usize = 1;
          fn coordinate (&self, which: usize)->Self::Coordinate {*self}
          fn set_coordinate (&mut self, which: usize, value: Self::Coordinate) {*self = value}
        }
      )*
    }
  }
  impl_vector! ([1, Vector1], [2, Vector2], [3, Vector3], [4, Vector4], [5, Vector5], [6, Vector6],);
  impl_integer! (i8, i16, i32, i64, isize,);
}

/// Right-shift an integer, but round to nearest, with ties rounding to even.
///
/// This minimizes error, and avoids a directional bias.
pub fn shr_nicely_rounded <T: Integer> (input: T, shift: u32)->T {
  if shift == 0 {return input}
  let divisor = match T::one().checked_shl ( shift ) {Some (value) => value, None => return T::zero()};
  let mask = divisor.wrapping_sub (&T::one());
  let shifted = input >> shift;
  let half_shift = shift - 1;
  let half = T::one() << half_shift;
  if (input & mask) == half {
    shifted + (shifted & T::one())
  } else {
    shifted + ((input & half) >> half_shift)
  }
}

/// Right-shift an integer, but round to even.
///
/// This avoids a directional bias.
pub fn shr_round_to_even <T: Integer> (input: T, shift: u32)->T {
  let divisor = match T::one().checked_shl ( shift ) {Some (value) => value, None => return T::zero()};
  let mask = divisor.wrapping_sub (&T::one());
  let shifted = input >> shift;
  if (input & mask) != T::zero() {
    shifted + (shifted & T::one())
  } else {
    shifted
  }
}

/// Right-shift an integer, but round towards positive infinity.
pub fn shr_ceil <T: Integer> (input: T, shift: u32)->T {
  let divisor = match T::one().checked_shl ( shift ) {Some (value) => value, None => return T::zero()};
  let mask = divisor.wrapping_sub (&T::one());
  (input >> shift) + if input & mask != T::zero() {T::one()} else {T::zero()}
}

/// Left-shift an integer, returning Some(input*(2^shift)) if it fits within the type, None otherwise.
pub fn overflow_checked_shl <T: Integer> (input: T, shift: u32)->Option <T> {
  if input == T::zero() {return Some (T::zero())}
  let maximum = match T::max_value().checked_shr (shift) {
    None => return None,
    Some (value) => value,
  };
  if input > maximum {return None}
  let minimum = T::min_value() >> shift;
  if input < minimum {return None}
  Some (input << shift)
}

/// Compute the arithmetic mean of two integers, rounded towards negative infinity. Never overflows.
pub fn mean_floor <T: Integer> (first: T, second: T)->T {
  (first >> 1u32) + (second >> 1u32) + (first & second & T::one())
}

/// Compute the arithmetic mean of two integers, rounded towards positive infinity. Never overflows.
pub fn mean_ceil <T: Integer> (first: T, second: T)->T {
  (first >> 1u32) + (second >> 1u32) + ((first | second) & T::one())
}

pub mod polynomial;

#[cfg (test)]
mod tests {
  use super::*;
  use num::{One, ToPrimitive, Integer};
  use num::bigint::BigInt;
  use num::rational::{Ratio};
  use std::cmp::Ordering;

  fn perfect_shr_nicely_rounded <T: Integer> (input: T, shift: u32)->BigInt where BigInt: From <T> {
    let perfect_result = Ratio::new (BigInt::from (input), BigInt::one() << shift as usize);
    let rounded_down = perfect_result.floor();
    let fraction = & perfect_result - & rounded_down;
    let rounded_down = rounded_down.to_integer();
    match fraction.cmp (& Ratio::new (BigInt::one(), BigInt::one() << 1)) {
      Ordering::Less => rounded_down, Ordering::Greater => rounded_down + BigInt::one() ,
      Ordering::Equal => & rounded_down + rounded_down.mod_floor (& (BigInt::one() << 1)),
    }
  }

  fn perfect_shr_round_to_even <T: Integer> (input: T, shift: u32)->BigInt where BigInt: From <T> {
    let perfect_result = Ratio::new (BigInt::from (input), BigInt::one() << shift as usize);
    let rounded_down = perfect_result.floor();
    if perfect_result == rounded_down {rounded_down.to_integer()}
    else {
      let rounded_down = rounded_down.to_integer();
      if &rounded_down >> 1 << 1 == rounded_down {
        rounded_down
      }
      else {rounded_down + 1}
    }
  }

  #[test]
  fn test_shr_nicely_rounded() {
    let inputs: Vec<(i64, u32, i64)> = vec![
      (0, 0, 0), (0, 5, 0), (5, 0, 5), (1, 3, 0), (4, 3, 0), (5, 3, 1),
      (999, 1, 500), (998, 1, 499), (997, 1, 498)
    ];
    for (input, shift, result) in inputs {
      assert_eq!(shr_nicely_rounded (input, shift), result);
      assert_eq!(shr_nicely_rounded (-input, shift), -result);
    }
  }

  #[test]
  fn test_shr_round_to_even() {
    let inputs: Vec<(i64, u32, i64)> = vec![
      (0, 0, 0), (0, 5, 0), (5, 0, 5), (1, 3, 0), (4, 3, 0), (5, 3, 0),
      (999, 1, 500), (998, 1, 499), (997, 1, 498)
    ];
    for (input, shift, result) in inputs {
      assert_eq!(shr_round_to_even (input, shift), result);
      assert_eq!(shr_round_to_even (-input, shift), -result);
    }
  }

  quickcheck! {
    fn quickcheck_shr_nicely_rounded_signed (input: i32, shift: u8)->bool {
      let result = shr_nicely_rounded (input, shift as u32);
      let perfect_result = perfect_shr_nicely_rounded (input, shift as u32);
      println!( "{:?}", (result, & perfect_result.to_str_radix (10)));
      perfect_result == BigInt::from (result)
    }

    fn quickcheck_shr_nicely_rounded_unsigned (input: u32, shift: u8)->bool {
      let result = shr_nicely_rounded (input, shift as u32);
      let perfect_result = perfect_shr_nicely_rounded (input, shift as u32);
      println!( "{:?}", (result, & perfect_result.to_str_radix (10)));
      perfect_result == BigInt::from (result)
    }

    fn quickcheck_shr_round_to_even_signed (input: i32, shift: u8)->bool {
      let result = shr_round_to_even (input, shift as u32);
      let perfect_result = perfect_shr_round_to_even (input, shift as u32);
      println!( "{:?}", (result, & perfect_result.to_str_radix (10)));
      perfect_result == BigInt::from (result)
    }

    fn quickcheck_shr_round_to_even_unsigned (input: u32, shift: u8)->bool {
      let result = shr_round_to_even (input, shift as u32);
      let perfect_result = perfect_shr_round_to_even (input, shift as u32);
      println!( "{:?}", (result, & perfect_result.to_str_radix (10)));
      perfect_result == BigInt::from (result)
    }

    fn quickcheck_overflow_checked_shl (input: i32, shift: u8)->bool {
      let result = overflow_checked_shl (input, shift as u32);
      let perfect_result = BigInt::from (input) << shift as usize;
      result == perfect_result.to_i32()
    }
  }
}
<commit_msg>Rewrote the shr functions a bit<commit_after>use num::{self};
use num::traits::{Zero, WrappingAdd, WrappingSub, WrappingMul, CheckedShl, CheckedShr, Signed};
use std::mem;
use std::cmp::{min};
use std::ops::{Add, Sub, Mul, AddAssign, SubAssign, MulAssign, Shl, Shr, Neg, Index};
use std::fmt::Debug;

pub trait Integer:
  'static + num::PrimInt + num::Integer + num::FromPrimitive +
  AddAssign <Self> + SubAssign <Self> + MulAssign <Self> +
  WrappingAdd + WrappingSub + WrappingMul +
  for<'a> Add <&'a Self, Output = Self> + for<'a> Sub <&'a Self, Output = Self> + for<'a> Mul <&'a Self, Output = Self> +
  CheckedShl + CheckedShr + Shl <u32, Output = Self> + Shr <u32, Output = Self> +
  Debug {}
impl <T: 'static + num::PrimInt + num::Integer + num::FromPrimitive + AddAssign <Self> + SubAssign <Self> + MulAssign <Self> + WrappingAdd + WrappingSub + WrappingMul + for<'a> Add <&'a Self, Output = Self> + for<'a> Sub <&'a Self, Output = Self> + for<'a> Mul <&'a Self, Output = Self> + CheckedShl + CheckedShr + Shl <u32, Output = Self> + Shr <u32, Output = Self> + Debug> Integer for T {}

pub trait HasCoordinates
   {
  type Coordinate: Integer + Signed + Vector + HasCoordinates <Coordinate = Self::Coordinate>;}

pub trait Vector:
  'static + Sized + Copy + Clone + HasCoordinates +
  Add <Self, Output = Self> + Sub <Self, Output = Self> + Mul <<Self as HasCoordinates>::Coordinate, Output = Self> +
  for<'a> Add <&'a Self, Output = Self> + for<'a> Sub <&'a Self, Output = Self> + //for<'a> Mul <&'a <Self as HasCoordinates>::Coordinate, Output = Self> +
  AddAssign <Self> + SubAssign <Self> + MulAssign <<Self as HasCoordinates>::Coordinate> +
  for<'a> AddAssign <&'a Self> + for<'a> SubAssign <&'a Self> + //for<'a> MulAssign <&'a <Self as HasCoordinates>::Coordinate> +
  Zero + Neg <Output = Self>
  {
  const DIMENSIONS: usize;
  fn coordinate (&self, which: usize)->Self::Coordinate;
  fn set_coordinate (&mut self, which: usize, value: Self::Coordinate);
}

pub mod impls {
  use super::*;
  use nalgebra::*;
  macro_rules! impl_vector {
    ($([$coordinates: expr, $Vector: ident],)*) => {
      $(
        impl <T: Integer + Signed + Vector + HasCoordinates <Coordinate = T>> HasCoordinates for $Vector <T> {type Coordinate = T;}
        impl <T: Integer + Signed + Vector + HasCoordinates <Coordinate = T>> Vector for $Vector <T> {
          const DIMENSIONS: usize = $coordinates;
          fn coordinate (&self, which: usize)->Self::Coordinate {self [which]}
          fn set_coordinate (&mut self, which: usize, value: Self::Coordinate) {self [which] = value}
        }
      )*
    }
  }
  macro_rules! impl_integer {
    ($($Integer: ident,)*) => {
      $(
        impl HasCoordinates for $Integer {type Coordinate = $Integer;}
        impl Vector for $Integer {
          const DIMENSIONS: usize = 1;
          fn coordinate (&self, which: usize)->Self::Coordinate {*self}
          fn set_coordinate (&mut self, which: usize, value: Self::Coordinate) {*self = value}
        }
      )*
    }
  }
  impl_vector! ([1, Vector1], [2, Vector2], [3, Vector3], [4, Vector4], [5, Vector5], [6, Vector6],);
  impl_integer! (i8, i16, i32, i64, isize,);
}

/// Right-shift an integer, but round to nearest, with ties rounding to even.
///
/// This minimizes error, and avoids a directional bias.
pub fn shr_nicely_rounded <T: Integer> (input: T, shift: u32)->T {
  if shift == 0 {return input}
  let divisor = match T::one().checked_shl ( shift ) {Some (value) => value, None => return T::zero()};
  let mask = divisor.wrapping_sub (&T::one());
  let shifted = input >> shift;
  let half_shift = shift - 1;
  let half = T::one() << half_shift;
  shifted + if (input & mask)+(shifted & T::one()) > half {T::one()} else {T::zero()}
}

/// Right-shift an integer, but round to even.
///
/// This avoids a directional bias.
pub fn shr_round_to_even <T: Integer> (input: T, shift: u32)->T {
  let divisor = match T::one().checked_shl ( shift ) {Some (value) => value, None => return T::zero()};
  let mask = divisor.wrapping_sub (&T::one());
  let shifted = input >> shift;
  shifted + if (input & mask) != T::zero() {shifted & T::one()} else {T::zero()}
}

/// Right-shift an integer, but round towards positive infinity.
pub fn shr_ceil <T: Integer> (input: T, shift: u32)->T {
  let divisor = match T::one().checked_shl ( shift ) {Some (value) => value, None => return T::zero()};
  let mask = divisor.wrapping_sub (&T::one());
  (input >> shift) + if input & mask != T::zero() {T::one()} else {T::zero()}
}

/// Left-shift an integer, returning Some(input*(2^shift)) if it fits within the type, None otherwise.
pub fn overflow_checked_shl <T: Integer> (input: T, shift: u32)->Option <T> {
  if input == T::zero() {return Some (T::zero())}
  let maximum = match T::max_value().checked_shr (shift) {
    None => return None,
    Some (value) => value,
  };
  if input > maximum {return None}
  let minimum = T::min_value() >> shift;
  if input < minimum {return None}
  Some (input << shift)
}

/// Compute the arithmetic mean of two integers, rounded towards negative infinity. Never overflows.
pub fn mean_floor <T: Integer> (first: T, second: T)->T {
  (first >> 1u32) + (second >> 1u32) + (first & second & T::one())
}

/// Compute the arithmetic mean of two integers, rounded towards positive infinity. Never overflows.
pub fn mean_ceil <T: Integer> (first: T, second: T)->T {
  (first >> 1u32) + (second >> 1u32) + ((first | second) & T::one())
}

pub mod polynomial;

#[cfg (test)]
mod tests {
  use super::*;
  use num::{One, ToPrimitive, Integer};
  use num::bigint::BigInt;
  use num::rational::{Ratio};
  use std::cmp::Ordering;

  fn perfect_shr_nicely_rounded <T: Integer> (input: T, shift: u32)->BigInt where BigInt: From <T> {
    let perfect_result = Ratio::new (BigInt::from (input), BigInt::one() << shift as usize);
    let rounded_down = perfect_result.floor();
    let fraction = & perfect_result - & rounded_down;
    let rounded_down = rounded_down.to_integer();
    match fraction.cmp (& Ratio::new (BigInt::one(), BigInt::one() << 1)) {
      Ordering::Less => rounded_down, Ordering::Greater => rounded_down + BigInt::one() ,
      Ordering::Equal => & rounded_down + rounded_down.mod_floor (& (BigInt::one() << 1)),
    }
  }

  fn perfect_shr_round_to_even <T: Integer> (input: T, shift: u32)->BigInt where BigInt: From <T> {
    let perfect_result = Ratio::new (BigInt::from (input), BigInt::one() << shift as usize);
    let rounded_down = perfect_result.floor();
    if perfect_result == rounded_down {rounded_down.to_integer()}
    else {
      let rounded_down = rounded_down.to_integer();
      if &rounded_down >> 1 << 1 == rounded_down {
        rounded_down
      }
      else {rounded_down + 1}
    }
  }

  #[test]
  fn test_shr_nicely_rounded() {
    let inputs: Vec<(i64, u32, i64)> = vec![
      (0, 0, 0), (0, 5, 0), (5, 0, 5), (1, 3, 0), (4, 3, 0), (5, 3, 1),
      (999, 1, 500), (998, 1, 499), (997, 1, 498)
    ];
    for (input, shift, result) in inputs {
      println!( "{:?}", (input, shift, result));
      assert_eq!(shr_nicely_rounded (input, shift), result);
      assert_eq!(shr_nicely_rounded (-input, shift), -result);
    }
  }

  #[test]
  fn test_shr_round_to_even() {
    let inputs: Vec<(i64, u32, i64)> = vec![
      (0, 0, 0), (0, 5, 0), (5, 0, 5), (1, 3, 0), (4, 3, 0), (5, 3, 0),
      (999, 1, 500), (998, 1, 499), (997, 1, 498)
    ];
    for (input, shift, result) in inputs {
      println!( "{:?}", (input, shift, result));
      assert_eq!(shr_round_to_even (input, shift), result);
      assert_eq!(shr_round_to_even (-input, shift), -result);
    }
  }

  quickcheck! {
    fn quickcheck_shr_nicely_rounded_signed (input: i32, shift: u8)->bool {
      let result = shr_nicely_rounded (input, shift as u32);
      let perfect_result = perfect_shr_nicely_rounded (input, shift as u32);
      println!( "{:?}", (result, & perfect_result.to_str_radix (10)));
      perfect_result == BigInt::from (result)
    }

    fn quickcheck_shr_nicely_rounded_unsigned (input: u32, shift: u8)->bool {
      let result = shr_nicely_rounded (input, shift as u32);
      let perfect_result = perfect_shr_nicely_rounded (input, shift as u32);
      println!( "{:?}", (result, & perfect_result.to_str_radix (10)));
      perfect_result == BigInt::from (result)
    }

    fn quickcheck_shr_round_to_even_signed (input: i32, shift: u8)->bool {
      let result = shr_round_to_even (input, shift as u32);
      let perfect_result = perfect_shr_round_to_even (input, shift as u32);
      println!( "{:?}", (result, & perfect_result.to_str_radix (10)));
      perfect_result == BigInt::from (result)
    }

    fn quickcheck_shr_round_to_even_unsigned (input: u32, shift: u8)->bool {
      let result = shr_round_to_even (input, shift as u32);
      let perfect_result = perfect_shr_round_to_even (input, shift as u32);
      println!( "{:?}", (result, & perfect_result.to_str_radix (10)));
      perfect_result == BigInt::from (result)
    }

    fn quickcheck_overflow_checked_shl (input: i32, shift: u8)->bool {
      let result = overflow_checked_shl (input, shift as u32);
      let perfect_result = BigInt::from (input) << shift as usize;
      result == perfect_result.to_i32()
    }
  }
}
<|endoftext|>


<commit_before>// Refer:
// https://www.ietf.org/rfc/rfc2388.txt:  Returning Values from Forms:  multipart/form-data
// https://www.ietf.org/rfc/rfc2183.txt:  The Content-Disposition Header Field

use std::fmt;
use std::ascii::AsciiExt;

use hyper::header::{Header, HeaderFormat, parsing};

/// We define a Content-Disposition form-data only header, which is found within
/// the mime multipart sections.  NOT FOR GENERAL USE
#[derive(Debug,Clone,PartialEq)]
pub struct ContentDispositionFormData {
    pub name: Option<String>,
    pub filename: Option<String>,
}

impl Header for ContentDispositionFormData {
    fn header_name() -> &'static str {
        "Content-Disposition"
    }

    fn parse_header(raw: &[Vec<u8>]) -> Option<ContentDispositionFormData> {
        parsing::from_one_raw_str(raw).and_then(|s: String| {
            let mut sections = s.split(';');
            match sections.next() {
                None => return None,
                Some(s) => {
                    if &s.trim().to_ascii_lowercase() != "form-data" {
                        return None
                    }
                }
            };
            let mut cd = ContentDispositionFormData { name: None, filename: None };
            for section in sections {
                let mut parts = section.split('=');
                if parts.clone().count() != 2 { continue; }
                let key = parts.next().unwrap().trim().to_ascii_lowercase();
                let mut val = parts.next().unwrap().trim();
                if val.chars().next()==Some('"') && val.chars().rev().next()==Some('"') {
                    val = &val[1..val.len()-1]; // unwrap quotes
                }
                match &*key {
                    "name" => cd.name = Some(val.to_string()),
                    "filename" => cd.filename = Some(val.to_string()),
                    _ => {}
                }
            }
            Some(cd)
        })
    }
}

impl HeaderFormat for ContentDispositionFormData {
    fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("form-data")
    }
}

#[cfg(test)]
mod tests {
    use super::ContentDispositionFormData;
    use hyper::header::Header;

    #[test]
    fn parse_header() {
        let a: ContentDispositionFormData =
            ContentDispositionFormData::parse_header(
                [b"form-data; dummy=3; name=upload;\r\n filename=\"sample.png\"".to_vec()].as_ref() )
            .unwrap();
        let b = ContentDispositionFormData {
            name: Some("upload".to_string()),
            filename: Some("sample.png".to_string()),
        };
        assert_eq!(a, b);

        let e: Option<ContentDispositionFormData> = Header::parse_header([b"".to_vec()].as_ref());
        assert_eq!(e, None);
    }

    #[test]
    fn parse_header_test_rfc_2184() {
        let a: ContentDispositionFormData =
            ContentDispositionFormData::parse_header(
                [b"form-data; dummy=3;\r\n filename*0=\"sample%20music\"; filename*1=\".png\"".to_vec()].as_ref() )
            .unwrap();
        let b = ContentDispositionFormData {
            name: None,
            filename: Some("sample music.png".to_string()),
        };
        assert_eq!(a, b);
    }
}
<commit_msg>Disable test for rfc 2231 (not supported, see issue #3)<commit_after>// Refer:
// https://www.ietf.org/rfc/rfc2388.txt:  Returning Values from Forms:  multipart/form-data
// https://www.ietf.org/rfc/rfc2183.txt:  The Content-Disposition Header Field

use std::fmt;
use std::ascii::AsciiExt;

use hyper::header::{Header, HeaderFormat, parsing};

/// We define a Content-Disposition form-data only header, which is found within
/// the mime multipart sections.  NOT FOR GENERAL USE
#[derive(Debug,Clone,PartialEq)]
pub struct ContentDispositionFormData {
    pub name: Option<String>,
    pub filename: Option<String>,
}

impl Header for ContentDispositionFormData {
    fn header_name() -> &'static str {
        "Content-Disposition"
    }

    fn parse_header(raw: &[Vec<u8>]) -> Option<ContentDispositionFormData> {
        parsing::from_one_raw_str(raw).and_then(|s: String| {
            let mut sections = s.split(';');
            match sections.next() {
                None => return None,
                Some(s) => {
                    if &s.trim().to_ascii_lowercase() != "form-data" {
                        return None
                    }
                }
            };
            let mut cd = ContentDispositionFormData { name: None, filename: None };
            for section in sections {
                let mut parts = section.split('=');
                if parts.clone().count() != 2 { continue; }
                let key = parts.next().unwrap().trim().to_ascii_lowercase();
                let mut val = parts.next().unwrap().trim();
                if val.chars().next()==Some('"') && val.chars().rev().next()==Some('"') {
                    val = &val[1..val.len()-1]; // unwrap quotes
                }
                match &*key {
                    "name" => cd.name = Some(val.to_string()),
                    "filename" => cd.filename = Some(val.to_string()),
                    _ => {}
                }
            }
            Some(cd)
        })
    }
}

impl HeaderFormat for ContentDispositionFormData {
    fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("form-data")
    }
}

#[cfg(test)]
mod tests {
    use super::ContentDispositionFormData;
    use hyper::header::Header;

    #[test]
    fn parse_header() {
        let a: ContentDispositionFormData =
            ContentDispositionFormData::parse_header(
                [b"form-data; dummy=3; name=upload;\r\n filename=\"sample.png\"".to_vec()].as_ref() )
            .unwrap();
        let b = ContentDispositionFormData {
            name: Some("upload".to_string()),
            filename: Some("sample.png".to_string()),
        };
        assert_eq!(a, b);

        let e: Option<ContentDispositionFormData> = Header::parse_header([b"".to_vec()].as_ref());
        assert_eq!(e, None);
    }

    // RFC 2231 (obsoletes 2184) is NOT supported presently
    // See closed issue #3
    //
    //#[test]
    //fn parse_header_test_rfc_2231() {
    //    let a: ContentDispositionFormData =
    //        ContentDispositionFormData::parse_header(
    //            [b"form-data; dummy=3;\r\n filename*0=\"sample%20music\"; filename*1=\".png\"".to_vec()].as_ref() )
    //        .unwrap();
    //    let b = ContentDispositionFormData {
    //        name: None,
    //        filename: Some("sample music.png".to_string()),
    //    };
    //    assert_eq!(a, b);
    //}
}
<|endoftext|>


<commit_before>use std::f64;
use rand::Rng;
use rand::distributions::{Sample, IndependentSample};
use statistics::*;
use distribution::{Univariate, Continuous, Distribution};
use result::Result;
use error::StatsError;

/// Implements the [Cauchy](https://en.wikipedia.org/wiki/Cauchy_distribution)
/// distribution, also known as the Lorentz distribution.
///
/// # Examples
///
/// ```
/// ```
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Cauchy {
    location: f64,
    scale: f64,
}

impl Cauchy {
    /// Constructs a new cauchy distribution with the given
    /// location and scale.
    ///
    /// # Errors
    ///
    /// Returns an error if location is `NaN` or `rate <= 0.0`
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Cauchy;
    ///
    /// let mut result = Cauchy::new(0.0, 1.0);
    /// assert!(result.is_ok());
    ///
    /// result = Cauchy::new(0.0, -1.0);
    /// assert!(result.is_err());
    /// ```
    pub fn new(location: f64, scale: f64) -> Result<Cauchy> {
        if location.is_nan() || scale <= 0.0 {
            Err(StatsError::BadParams)
        } else {
            Ok(Cauchy {
                location: location,
                scale: scale,
            })
        }
    }

    /// Returns the location of the cauchy distribution
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Cauchy;
    ///
    /// let n = Cauchy::new(0.0, 1.0).unwrap();
    /// assert_eq!(n.location(), 0.0);
    /// ```
    pub fn location(&self) -> f64 {
        self.location
    }

    /// Returns the scale of the cauchy distribution
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Cauchy;
    ///
    /// let n = Cauchy::new(0.0, 1.0).unwrap();
    /// assert_eq!(n.scale(), 1.0);
    /// ```
    pub fn scale(&self) -> f64 {
        self.scale
    }
}

impl Sample<f64> for Cauchy {
    /// Generate a random sample from a cauchy
    /// distribution using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details
    fn sample<R: Rng>(&mut self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl IndependentSample<f64> for Cauchy {
    /// Generate a random independent sample from a cauchy
    /// distribution using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details
    fn ind_sample<R: Rng>(&self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl Distribution<f64> for Cauchy {
    /// Generate a random sample from the cauchy distribution
    /// using `r` as the source of randomness
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate rand;
    /// # extern crate statrs;
    /// use rand::StdRng;
    /// use statrs::distribution::{Cauchy, Distribution};
    ///
    /// # fn main() {
    /// let mut r = rand::StdRng::new().unwrap();
    /// let n = Cauchy.new(0.0, 1.0).unwrap();
    /// print!("{}", n.sample::<StdRng>(&mut r));
    /// # }
    /// ```
    fn sample<R: Rng>(&self, r: &mut R) -> f64 {
        self.location + self.scale * (f64::consts::PI * (r.next_f64() - 0.5)).tan()
    }
}

impl Univariate<f64, f64> for Cauchy {
    /// Calculates the cumulative distribution function for the
    /// cauchy distribution at `x`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// (1 / π) * arctan((x - x_0) / γ) + 0.5
    /// ```
    /// where `x_0` is the location and `γ` is the scale
    fn cdf(&self, x: f64) -> f64 {
        (1.0 / f64::consts::PI) * ((x - self.location) / self.scale).atan() + 0.5
    }
}

impl Min<f64> for Cauchy {
    /// Returns the minimum value in the domain of the cauchy
    /// distribution representable by a double precision float
    ///
    /// # Formula
    ///
    /// ```ignore
    /// NEG_INF
    /// ```
    fn min(&self) -> f64 {
        f64::NEG_INFINITY
    }
}

impl Max<f64> for Cauchy {
    /// Returns the maximum value in the domain of the cauchy
    /// distribution representable by a double precision float
    ///
    /// # Formula
    ///
    /// ```ignore
    /// INF
    /// ```
    fn max(&self) -> f64 {
        f64::INFINITY
    }
}
<commit_msg>wip: complete cauchy untested<commit_after>use std::f64;
use rand::Rng;
use rand::distributions::{Sample, IndependentSample};
use statistics::*;
use distribution::{Univariate, Continuous, Distribution};
use result::Result;
use error::StatsError;

/// Implements the [Cauchy](https://en.wikipedia.org/wiki/Cauchy_distribution)
/// distribution, also known as the Lorentz distribution.
///
/// # Examples
///
/// ```
/// ```
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Cauchy {
    location: f64,
    scale: f64,
}

impl Cauchy {
    /// Constructs a new cauchy distribution with the given
    /// location and scale.
    ///
    /// # Errors
    ///
    /// Returns an error if location is `NaN` or `rate <= 0.0`
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Cauchy;
    ///
    /// let mut result = Cauchy::new(0.0, 1.0);
    /// assert!(result.is_ok());
    ///
    /// result = Cauchy::new(0.0, -1.0);
    /// assert!(result.is_err());
    /// ```
    pub fn new(location: f64, scale: f64) -> Result<Cauchy> {
        if location.is_nan() || scale <= 0.0 {
            Err(StatsError::BadParams)
        } else {
            Ok(Cauchy {
                location: location,
                scale: scale,
            })
        }
    }

    /// Returns the location of the cauchy distribution
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Cauchy;
    ///
    /// let n = Cauchy::new(0.0, 1.0).unwrap();
    /// assert_eq!(n.location(), 0.0);
    /// ```
    pub fn location(&self) -> f64 {
        self.location
    }

    /// Returns the scale of the cauchy distribution
    ///
    /// # Examples
    ///
    /// ```
    /// use statrs::distribution::Cauchy;
    ///
    /// let n = Cauchy::new(0.0, 1.0).unwrap();
    /// assert_eq!(n.scale(), 1.0);
    /// ```
    pub fn scale(&self) -> f64 {
        self.scale
    }
}

impl Sample<f64> for Cauchy {
    /// Generate a random sample from a cauchy
    /// distribution using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details
    fn sample<R: Rng>(&mut self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl IndependentSample<f64> for Cauchy {
    /// Generate a random independent sample from a cauchy
    /// distribution using `r` as the source of randomness.
    /// Refer [here](#method.sample-1) for implementation details
    fn ind_sample<R: Rng>(&self, r: &mut R) -> f64 {
        super::Distribution::sample(self, r)
    }
}

impl Distribution<f64> for Cauchy {
    /// Generate a random sample from the cauchy distribution
    /// using `r` as the source of randomness
    ///
    /// # Examples
    ///
    /// ```
    /// # extern crate rand;
    /// # extern crate statrs;
    /// use rand::StdRng;
    /// use statrs::distribution::{Cauchy, Distribution};
    ///
    /// # fn main() {
    /// let mut r = rand::StdRng::new().unwrap();
    /// let n = Cauchy.new(0.0, 1.0).unwrap();
    /// print!("{}", n.sample::<StdRng>(&mut r));
    /// # }
    /// ```
    fn sample<R: Rng>(&self, r: &mut R) -> f64 {
        self.location + self.scale * (f64::consts::PI * (r.next_f64() - 0.5)).tan()
    }
}

impl Univariate<f64, f64> for Cauchy {
    /// Calculates the cumulative distribution function for the
    /// cauchy distribution at `x`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// (1 / π) * arctan((x - x_0) / γ) + 0.5
    /// ```
    ///
    /// where `x_0` is the location and `γ` is the scale
    fn cdf(&self, x: f64) -> f64 {
        (1.0 / f64::consts::PI) * ((x - self.location) / self.scale).atan() + 0.5
    }
}

impl Min<f64> for Cauchy {
    /// Returns the minimum value in the domain of the cauchy
    /// distribution representable by a double precision float
    ///
    /// # Formula
    ///
    /// ```ignore
    /// NEG_INF
    /// ```
    fn min(&self) -> f64 {
        f64::NEG_INFINITY
    }
}

impl Max<f64> for Cauchy {
    /// Returns the maximum value in the domain of the cauchy
    /// distribution representable by a double precision float
    ///
    /// # Formula
    ///
    /// ```ignore
    /// INF
    /// ```
    fn max(&self) -> f64 {
        f64::INFINITY
    }
}

impl Entropy<f64> for Cauchy {
    /// Returns the entropy of the cauchy distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// ln(γ) + ln(4π)
    /// ```
    ///
    /// where `γ` is the scale
    fn entropy(&self) -> f64 {
        (4.0 * f64::consts::PI * self.scale).ln()
    }
}

impl Median<f64> for Cauchy {
    /// Returns the median of the cauchy distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// x_0
    /// ```
    ///
    /// where `x_0` is the location
    fn median(&self) -> f64 {
        self.location
    }
}

impl Mode<f64> for Cauchy {
    /// Returns the mode of the cauchy distribution
    ///
    /// # Formula
    ///
    /// ```ignore
    /// x_0
    /// ```
    ///
    /// where `x_0` is the location
    fn mode(&self) -> f64 {
        self.location
    }
}

impl Continuous<f64, f64> for Exponential {
    /// Calculates the probability density function for the cauchy
    /// distribution at `x`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// 1 / (πγ * (1 + ((x - x_0) / γ)^2))
    /// ```
    ///
    /// where `x_0` is the location and `γ` is the scale
    fn pdf(&self, x: f64) -> f64 {
        1.0 /
        (f64::consts::PI * self.scale *
         (1.0 + ((x - self.location) / self.scale) * ((x - self.location) / self.scale)))
    }

    /// Calculates the log probability density function for the cauchy
    /// distribution at `x`
    ///
    /// # Formula
    ///
    /// ```ignore
    /// ln(1 / (πγ * (1 + ((x - x_0) / γ)^2)))
    /// ```
    ///
    /// where `x_0` is the location and `γ` is the scale
    fn ln_pdf(&self, x: f64) -> f64 {
        -(f64::consts::PI * self.scale *
          (1.0 + ((x - self.location) / self.scale) * ((x - self.location) / self.scale)))
            .ln()
    }
}<|endoftext|>


<commit_before>//! File holding the GenericError type
//!
//! Author: [Boris](mailto:boris@humanenginuity.com)
//! Version: 1.0
//!
//! ## Release notes
//! - v1.0 : creation

// =======================================================================
// LIBRARY IMPORTS
// =======================================================================
use std::boxed::Box;
use std::error::Error;
use std::fmt;
use std::io::Error as IOError;

use hyper::error::Error as HyperError;
use rocket::Error as RocketError;
use serde_json::Error as SerdeError;

// =======================================================================
// STRUCT DEFINITION
// =======================================================================
#[derive(Debug)]
pub enum GenericError {
    Hyper(HyperError),
    Io(IOError),
    Rocket(RocketError),
    Serde(SerdeError),
    Compound((String, Box<GenericError>)),
    Basic(String),
}

// =======================================================================
// STRUCT IMPLEMENTATION
// =======================================================================
impl GenericError {
    pub fn new_compound<T: ToString>(desc: T, err: GenericError) -> GenericError {
        let mut description = desc.to_string();
        description.push_str(" caused by ");
        description.push_str(err.description());
        GenericError::Compound((description, Box::new(err)))
    }
}

impl Error for GenericError {
    fn description(&self) -> &str {
        match *self {
            GenericError::Hyper(ref err) => err.description(),
            GenericError::Io(ref err) => err.description(),
            GenericError::Serde(ref err) => err.description(),
            GenericError::Rocket(_) => "Rocket Error - not implementing Error yet",
            GenericError::Compound((ref description, _)) => description,
            GenericError::Basic(ref err) => err.as_ref(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            GenericError::Hyper(ref err) => err.cause(),
            GenericError::Io(ref err) => err.cause(),
            GenericError::Rocket(_) => None, // Rocket Error doesn't implement Error trait yet
            GenericError::Serde(ref err) => err.cause(),
            GenericError::Compound((_,ref err)) => Some(err),
            GenericError::Basic(_) => None,
        }
    }
}

impl fmt::Display for GenericError{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GenericError::Hyper(ref err) => fmt::Display::fmt(err, f),
            GenericError::Io(ref err) => fmt::Display::fmt(err, f),
            GenericError::Serde(ref err) => fmt::Display::fmt(err, f),
            // GenericError::Rocket(ref err) => fmt::Display::fmt(err, f),
            _ => f.write_str(self.description()),
        }
    }
}

// =======================================================================
// UNIT TESTS
// =======================================================================
#[cfg(test)]
mod tests {
    #![allow(non_snake_case)]

    use std::error::Error;
    use super::GenericError;

    #[test]
    fn GenericError_test_compound() {
        let err = GenericError::new_compound("test description", GenericError::Basic("Test error".to_string()));
        assert_eq!(err.description(), "test description caused by Test error");

        match err.cause() {
            Some(err) => {
                assert_eq!(err.description(), "Test error");
                assert!(err.cause().is_none());
            },
            _ => panic!("invalid cause"),
        }
    }
}<commit_msg>added From implementation (as per book guideline to use with the `try!` macro)<commit_after>//! File holding the GenericError type
//!
//! Author: [Boris](mailto:boris@humanenginuity.com)
//! Version: 1.1
//!
//! ## Release notes
//! - v1.1 : added From implementation (as per book guideline to use with the `try!` macro)
//! - v1.0 : creation

// =======================================================================
// LIBRARY IMPORTS
// =======================================================================
use std::boxed::Box;
use std::error::Error;
use std::fmt;
use std::io::Error as IOError;

use hyper::error::Error as HyperError;
use rocket::Error as RocketError;
use serde_json::Error as SerdeError;

// =======================================================================
// STRUCT DEFINITION
// =======================================================================
#[derive(Debug)]
pub enum GenericError {
    Hyper(HyperError),
    Io(IOError),
    Rocket(RocketError),
    Serde(SerdeError),
    Compound((String, Box<GenericError>)),
    Basic(String),
}

// =======================================================================
// STRUCT IMPLEMENTATION
// =======================================================================
impl GenericError {
    pub fn new_compound<T: ToString>(desc: T, err: GenericError) -> GenericError {
        let mut description = desc.to_string();
        description.push_str(" caused by ");
        description.push_str(err.description());
        GenericError::Compound((description, Box::new(err)))
    }
}

impl Error for GenericError {
    fn description(&self) -> &str {
        match *self {
            GenericError::Hyper(ref err) => err.description(),
            GenericError::Io(ref err) => err.description(),
            GenericError::Serde(ref err) => err.description(),
            GenericError::Rocket(_) => "Rocket Error - not implementing Error yet",
            GenericError::Compound((ref description, _)) => description,
            GenericError::Basic(ref err) => err.as_ref(),
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            GenericError::Hyper(ref err) => err.cause(),
            GenericError::Io(ref err) => err.cause(),
            GenericError::Rocket(_) => None, // Rocket Error doesn't implement Error trait yet
            GenericError::Serde(ref err) => err.cause(),
            GenericError::Compound((_,ref err)) => Some(err),
            GenericError::Basic(_) => None,
        }
    }
}

impl fmt::Display for GenericError{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GenericError::Hyper(ref err) => fmt::Display::fmt(err, f),
            GenericError::Io(ref err) => fmt::Display::fmt(err, f),
            GenericError::Serde(ref err) => fmt::Display::fmt(err, f),
            // GenericError::Rocket(ref err) => fmt::Display::fmt(err, f),
            _ => f.write_str(self.description()),
        }
    }
}

// Implement `From` as per book guideline -> https://doc.rust-lang.org/book/error-handling.html#the-from-trait
impl From<HyperError> for GenericError {
    fn from(err: HyperError) -> GenericError {
        GenericError::Hyper(err)
    }
}

impl From<IOError> for GenericError {
    fn from(err: IOError) -> GenericError {
        GenericError::Io(err)
    }
}

impl From<RocketError> for GenericError {
    fn from(err: RocketError) -> GenericError {
        GenericError::Rocket(err)
    }
}

impl From<SerdeError> for GenericError {
    fn from(err: SerdeError) -> GenericError {
        GenericError::Serde(err)
    }
}

impl From<String> for GenericError {
    fn from(err: String) -> GenericError {
        GenericError::Basic(err)
    }
}

// =======================================================================
// UNIT TESTS
// =======================================================================
#[cfg(test)]
mod tests {
    #![allow(non_snake_case)]

    use std::error::Error;
    use super::GenericError;

    #[test]
    fn GenericError_test_compound() {
        let err = GenericError::new_compound("test description", GenericError::Basic("Test error".to_string()));
        assert_eq!(err.description(), "test description caused by Test error");

        match err.cause() {
            Some(err) => {
                assert_eq!(err.description(), "Test error");
                assert!(err.cause().is_none());
            },
            _ => panic!("invalid cause"),
        }
    }
}<|endoftext|>


<commit_before>use crate::shapes::{IntegPointData, Shape, StateOfShape};
use crate::StrError;
use russell_lab::Vector;

/// Implements the shape(N) times scalar(S) integration case
///
/// Interpolation functions times scalar field:
///
/// ```text
///      ⌠    → →     →
/// aᵐ = │ Nᵐ(x(ξ)) s(x) tₕ dΩ
///      ⌡
///      Ωₑ
/// ```
///
/// or, for lines in multi-dimensions:
///
/// ```text
///      ⌠
/// aᵐ = │ Nᵐ(ℓ(ξ)) s(ℓ) tₕ dℓ
///      ⌡
///      Γₑ
/// ```
///
/// The numerical integration is:
///
/// ```text
///      nip-1     →     →          →
/// aᵐ ≈   Σ    Nᵐ(ιᵖ) s(ιᵖ) tₕ |J|(ιᵖ) wᵖ
///       p=0
/// ```
///
/// # Output
///
/// ```text
///     ┌     ┐
///     |  a⁰ |
///     |  a¹ |
/// a = |  a² |
///     | ··· |
///     |  aᵐ |
///     └     ┘
/// ```
///
/// * `a` -- A vector containing all `aᵐ` values, one after another, and
///          sequentially placed as shown above. `m` is the index of the node.
///          The length of `a` must be equal to `nnode`.
///
/// # Updated
///
/// * `state` -- Will be updated by the Shape functions
///
/// # Input
///
/// * `shape` -- Shape functions
/// * `ips` -- Integration points (n_integ_point)
/// * `erase_a` -- Fills `a` vector with zeros, otherwise accumulate values into `a`
/// * `th` -- The out-of-plane thickness (`tₕ`) in 2D. Use 1.0 for 3D or for plane-stress models.
/// * `fn_s` -- Function `f(p)` corresponding to `s(x(ιᵖ))` with `0 ≤ p ≤ n_integ_point`
pub fn shape_times_scalar<F>(
    a: &mut Vector,
    state: &mut StateOfShape,
    shape: &Shape,
    ips: IntegPointData,
    th: f64,
    erase_a: bool,
    fn_s: F,
) -> Result<(), StrError>
where
    F: Fn(usize) -> Result<f64, StrError>,
{
    // check
    if a.dim() != shape.nnode {
        return Err("a.len() must be equal to nnode");
    }

    // clear output vector
    if erase_a {
        a.fill(0.0);
    }

    // loop over integration points
    for p in 0..ips.len() {
        // ksi coordinates and weight
        let iota = &ips[p];
        let weight = ips[p][3];

        // calculate interpolation functions and Jacobian
        shape.calc_interp(state, iota)?;
        let det_jac = shape.calc_jacobian(state, iota)?;

        // calculate s
        let s = fn_s(p)?;

        // loop over nodes and perform sum
        let val = s * th * det_jac * weight;
        for m in 0..shape.nnode {
            a[m] += state.interp[m] * val;
        }
    }
    Ok(())
}

/// Implements the the shape(N) times vector(V) integration case
///
/// Interpolation functions times vector field:
///
/// ```text
/// →    ⌠    → →   → →
/// bᵐ = │ Nᵐ(x(ξ)) v(x) tₕ dΩ
///      ⌡
///      Ωₑ
/// ```
///
/// The numerical integration is:
///
/// ```text
/// →    nip-1     →   → →          →
/// bᵐ ≈   Σ    Nᵐ(ιᵖ) v(ιᵖ) tₕ |J|(ιᵖ) wᵖ
///       p=0
/// ```
///
/// # Output
///
/// ```text
///     ┌     ┐
///     | b⁰₀ |
///     | b⁰₁ |
///     | b¹₀ |
/// b = | b¹₁ |
///     | b²₀ |
///     | b²₁ |
///     | ··· |
///     | bᵐᵢ |  ⟸  ii := i + m * space_ndim
///     └     ┘
///
/// m = ii / space_ndim
/// i = ii % space_ndim
/// ```
///
/// * `b` -- A vector containing all `bᵐᵢ` values, one after another, and sequentially placed
///          as shown above (in 2D). `m` is the index of the node and `i` corresponds to `space_ndim`.
///          The length of `b` must be equal to `nnode * space_ndim`.
///
/// # Updated
///
/// * `state` -- Will be updated by the Shape functions
///
/// # Input
///
/// * `shape` -- Shape functions
/// * `ips` -- Integration points (n_integ_point)
/// * `v` -- All values produced by `v(x(ιᵖ))` (n_integ_point); each v has len = space_ndim
/// * `erase_b` -- fills `b` vector with zeros, otherwise accumulate values into `b`
/// * `th` -- tₕ the out-of-plane thickness in 2D or 1.0 otherwise (e.g., for plane-stress models)
pub fn shape_times_vector(
    b: &mut Vector,
    state: &mut StateOfShape,
    shape: &Shape,
    ips: IntegPointData,
    v: &Vec<Vector>,
    th: f64,
    erase_b: bool,
) -> Result<(), StrError> {
    // check
    if b.dim() != shape.nnode * shape.space_ndim {
        return Err("b.len() must be equal to nnode * space_ndim");
    }

    // clear output vector
    if erase_b {
        b.fill(0.0);
    }

    // loop over integration points
    for index in 0..ips.len() {
        // ksi coordinates and weight
        let iota = &ips[index];
        let weight = ips[index][3];

        // calculate interpolation functions and Jacobian
        shape.calc_interp(state, iota)?;
        let det_jac = shape.calc_jacobian(state, iota)?;

        // add contribution to b vector
        let coef = th * det_jac * weight;
        let nn = &state.interp;
        if shape.space_ndim == 1 {
            for m in 0..shape.nnode {
                b[m] += coef * nn[m] * v[index][0];
            }
        } else if shape.space_ndim == 2 {
            for m in 0..shape.nnode {
                b[0 + m * 2] += coef * nn[m] * v[index][0];
                b[1 + m * 2] += coef * nn[m] * v[index][1];
            }
        } else {
            for m in 0..shape.nnode {
                b[0 + m * 3] += coef * nn[m] * v[index][0];
                b[1 + m * 3] += coef * nn[m] * v[index][1];
                b[2 + m * 3] += coef * nn[m] * v[index][2];
            }
        }
    }
    Ok(())
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use super::{shape_times_scalar, shape_times_vector};
    use crate::shapes::{Shape, StateOfShape, Verification, IP_LIN_LEGENDRE_2, IP_TRI_INTERNAL_1};
    use crate::StrError;
    use russell_chk::assert_vec_approx_eq;
    use russell_lab::Vector;

    // to test if variables are cleared before sum
    const NOISE: f64 = 1234.56;

    #[test]
    fn capture_some_errors() {
        let shape = Shape::new(2, 1, 2).unwrap();
        let mut state = StateOfShape::new(shape.geo_ndim, &[[0.0, 0.0], [1.0, 0.0]]).unwrap();
        let mut a = Vector::new(3);
        assert_eq!(
            shape_times_scalar(&mut a, &mut state, &shape, &[], 1.0, false, |_| Ok(0.0)).err(),
            Some("a.len() must be equal to nnode")
        );
    }

    #[test]
    fn shape_times_scalar_works_lin2() -> Result<(), StrError> {
        // lin2 with linear source term:
        //
        // s(x) = x
        //
        // solution:
        //
        //        ┌           ┐
        //      l │ 2 xa + xb │
        // Fₛ = — │           │
        //      6 │ xa + 2 xb │
        //        └           ┘
        let l = 6.0;
        let (shape, mut state) = Verification::line_segment_lin2(l);
        let ips = &IP_LIN_LEGENDRE_2;
        let x_ips = shape.calc_integ_points_coords(&mut state, ips)?;
        let mut a = Vector::filled(shape.nnode, NOISE);
        shape_times_scalar(&mut a, &mut state, &shape, ips, 1.0, true, |p| Ok(x_ips[p][0]))?;
        let cf = l / 6.0;
        let (xa, xb) = (state.coords_transp[0][0], state.coords_transp[0][1]);
        let a_correct = &[cf * (2.0 * xa + xb), cf * (xa + 2.0 * xb)];
        assert_vec_approx_eq!(a.as_data(), a_correct, 1e-15);
        Ok(())
    }

    #[test]
    fn shape_times_scalar_works_tri3() -> Result<(), StrError> {
        // tri3 with a constant source term:
        //
        // s(x) = cₛ
        //
        // solution:
        //           ┌   ┐
        //      cₛ A │ 1 │
        // Fₛ = ———— │ 1 │
        //        3  │ 1 │
        //           └   ┘
        let l = 5.0;
        let (shape, mut state, area) = Verification::equilateral_triangle_tri3(l);
        let ips = &IP_TRI_INTERNAL_1;
        const CS: f64 = 3.0;
        let mut a = Vector::filled(shape.nnode, NOISE);
        shape_times_scalar(&mut a, &mut state, &shape, ips, 1.0, true, |_| Ok(CS))?;
        let cf = CS * area / 3.0;
        let a_correct = &[cf, cf, cf];
        assert_vec_approx_eq!(a.as_data(), a_correct, 1e-14);
        Ok(())
    }

    #[test]
    fn shape_times_vector_works_lin2() -> Result<(), StrError> {
        // This test is similar to the shape_times_scalar with lin2, however using a vector
        // So, each component of `b` equals `Fₛ`
        let l = 6.0;
        let (shape, mut state) = Verification::line_segment_lin2(l);
        let ips = &IP_LIN_LEGENDRE_2;
        let x_ips = shape.calc_integ_points_coords(&mut state, ips)?;
        let v: Vec<_> = x_ips.iter().map(|x| Vector::filled(shape.space_ndim, x[0])).collect();
        let mut b = Vector::filled(shape.nnode * shape.space_ndim, NOISE);
        shape_times_vector(&mut b, &mut state, &shape, ips, &v, 1.0, true)?;
        let cf = l / 6.0;
        let (xa, xb) = (state.coords_transp[0][0], state.coords_transp[0][1]);
        let b_correct = &[
            cf * (2.0 * xa + xb),
            cf * (2.0 * xa + xb),
            cf * (xa + 2.0 * xb),
            cf * (xa + 2.0 * xb),
        ];
        assert_vec_approx_eq!(b.as_data(), b_correct, 1e-15);
        Ok(())
    }

    #[test]
    fn shape_times_vector_works_tri3() -> Result<(), StrError> {
        // This test is similar to the shape_times_scalar with tri3, however using a vector
        // So, each component of `b` equals `Fₛ`
        let l = 5.0;
        let (shape, mut state, area) = Verification::equilateral_triangle_tri3(l);
        let ips = &IP_TRI_INTERNAL_1;
        const CS: f64 = 3.0;
        let v: Vec<_> = (0..ips.len()).map(|_| Vector::filled(shape.space_ndim, CS)).collect();
        let mut b = Vector::filled(shape.nnode * shape.space_ndim, NOISE);
        shape_times_vector(&mut b, &mut state, &shape, ips, &v, 1.0, true)?;
        let cf = CS * area / 3.0;
        let b_correct = &[cf, cf, cf, cf, cf, cf];
        assert_vec_approx_eq!(b.as_data(), b_correct, 1e-14);
        Ok(())
    }
}
<commit_msg>Fix comment<commit_after>use crate::shapes::{IntegPointData, Shape, StateOfShape};
use crate::StrError;
use russell_lab::Vector;

/// Implements the shape(N) times scalar(S) integration case
///
/// Interpolation functions times scalar field:
///
/// ```text
///      ⌠    → →     →
/// aᵐ = │ Nᵐ(x(ξ)) s(x) tₕ dΩ
///      ⌡
///      Ωₑ
/// ```
///
/// or, for lines in multi-dimensions:
///
/// ```text
///      ⌠
/// aᵐ = │ Nᵐ(ℓ(ξ)) s(ℓ) tₕ dℓ
///      ⌡
///      Γₑ
/// ```
///
/// The numerical integration is:
///
/// ```text
///      nip-1     →     →          →
/// aᵐ ≈   Σ    Nᵐ(ιᵖ) s(ιᵖ) tₕ |J|(ιᵖ) wᵖ
///       p=0
/// ```
///
/// # Output
///
/// ```text
///     ┌     ┐
///     |  a⁰ |
///     |  a¹ |
/// a = |  a² |
///     | ··· |
///     |  aᵐ |
///     └     ┘
/// ```
///
/// * `a` -- A vector containing all `aᵐ` values, one after another, and
///          sequentially placed as shown above. `m` is the index of the node.
///          The length of `a` must be equal to `nnode`.
///
/// # Updated
///
/// * `state` -- Will be updated by the Shape functions
///
/// # Input
///
/// * `shape` -- Shape functions
/// * `ips` -- Integration points (n_integ_point)
/// * `th` -- The out-of-plane thickness (`tₕ`) in 2D. Use 1.0 for 3D or for plane-stress models.
/// * `erase_a` -- Fills `a` vector with zeros, otherwise accumulate values into `a`
/// * `fn_s` -- Function `f(p)` corresponding to `s(x(ιᵖ))` with `0 ≤ p ≤ n_integ_point`
pub fn shape_times_scalar<F>(
    a: &mut Vector,
    state: &mut StateOfShape,
    shape: &Shape,
    ips: IntegPointData,
    th: f64,
    erase_a: bool,
    fn_s: F,
) -> Result<(), StrError>
where
    F: Fn(usize) -> Result<f64, StrError>,
{
    // check
    if a.dim() != shape.nnode {
        return Err("a.len() must be equal to nnode");
    }

    // clear output vector
    if erase_a {
        a.fill(0.0);
    }

    // loop over integration points
    for p in 0..ips.len() {
        // ksi coordinates and weight
        let iota = &ips[p];
        let weight = ips[p][3];

        // calculate interpolation functions and Jacobian
        shape.calc_interp(state, iota)?;
        let det_jac = shape.calc_jacobian(state, iota)?;

        // calculate s
        let s = fn_s(p)?;

        // loop over nodes and perform sum
        let val = s * th * det_jac * weight;
        for m in 0..shape.nnode {
            a[m] += state.interp[m] * val;
        }
    }
    Ok(())
}

/// Implements the the shape(N) times vector(V) integration case
///
/// Interpolation functions times vector field:
///
/// ```text
/// →    ⌠    → →   → →
/// bᵐ = │ Nᵐ(x(ξ)) v(x) tₕ dΩ
///      ⌡
///      Ωₑ
/// ```
///
/// The numerical integration is:
///
/// ```text
/// →    nip-1     →   → →          →
/// bᵐ ≈   Σ    Nᵐ(ιᵖ) v(ιᵖ) tₕ |J|(ιᵖ) wᵖ
///       p=0
/// ```
///
/// # Output
///
/// ```text
///     ┌     ┐
///     | b⁰₀ |
///     | b⁰₁ |
///     | b¹₀ |
/// b = | b¹₁ |
///     | b²₀ |
///     | b²₁ |
///     | ··· |
///     | bᵐᵢ |  ⟸  ii := i + m * space_ndim
///     └     ┘
///
/// m = ii / space_ndim
/// i = ii % space_ndim
/// ```
///
/// * `b` -- A vector containing all `bᵐᵢ` values, one after another, and sequentially placed
///          as shown above (in 2D). `m` is the index of the node and `i` corresponds to `space_ndim`.
///          The length of `b` must be equal to `nnode * space_ndim`.
///
/// # Updated
///
/// * `state` -- Will be updated by the Shape functions
///
/// # Input
///
/// * `shape` -- Shape functions
/// * `ips` -- Integration points (n_integ_point)
/// * `v` -- All values produced by `v(x(ιᵖ))` (n_integ_point); each v has len = space_ndim
/// * `erase_b` -- fills `b` vector with zeros, otherwise accumulate values into `b`
/// * `th` -- tₕ the out-of-plane thickness in 2D or 1.0 otherwise (e.g., for plane-stress models)
pub fn shape_times_vector(
    b: &mut Vector,
    state: &mut StateOfShape,
    shape: &Shape,
    ips: IntegPointData,
    v: &Vec<Vector>,
    th: f64,
    erase_b: bool,
) -> Result<(), StrError> {
    // check
    if b.dim() != shape.nnode * shape.space_ndim {
        return Err("b.len() must be equal to nnode * space_ndim");
    }

    // clear output vector
    if erase_b {
        b.fill(0.0);
    }

    // loop over integration points
    for index in 0..ips.len() {
        // ksi coordinates and weight
        let iota = &ips[index];
        let weight = ips[index][3];

        // calculate interpolation functions and Jacobian
        shape.calc_interp(state, iota)?;
        let det_jac = shape.calc_jacobian(state, iota)?;

        // add contribution to b vector
        let coef = th * det_jac * weight;
        let nn = &state.interp;
        if shape.space_ndim == 1 {
            for m in 0..shape.nnode {
                b[m] += coef * nn[m] * v[index][0];
            }
        } else if shape.space_ndim == 2 {
            for m in 0..shape.nnode {
                b[0 + m * 2] += coef * nn[m] * v[index][0];
                b[1 + m * 2] += coef * nn[m] * v[index][1];
            }
        } else {
            for m in 0..shape.nnode {
                b[0 + m * 3] += coef * nn[m] * v[index][0];
                b[1 + m * 3] += coef * nn[m] * v[index][1];
                b[2 + m * 3] += coef * nn[m] * v[index][2];
            }
        }
    }
    Ok(())
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use super::{shape_times_scalar, shape_times_vector};
    use crate::shapes::{Shape, StateOfShape, Verification, IP_LIN_LEGENDRE_2, IP_TRI_INTERNAL_1};
    use crate::StrError;
    use russell_chk::assert_vec_approx_eq;
    use russell_lab::Vector;

    // to test if variables are cleared before sum
    const NOISE: f64 = 1234.56;

    #[test]
    fn capture_some_errors() {
        let shape = Shape::new(2, 1, 2).unwrap();
        let mut state = StateOfShape::new(shape.geo_ndim, &[[0.0, 0.0], [1.0, 0.0]]).unwrap();
        let mut a = Vector::new(3);
        assert_eq!(
            shape_times_scalar(&mut a, &mut state, &shape, &[], 1.0, false, |_| Ok(0.0)).err(),
            Some("a.len() must be equal to nnode")
        );
    }

    #[test]
    fn shape_times_scalar_works_lin2() -> Result<(), StrError> {
        // lin2 with linear source term:
        //
        // s(x) = x
        //
        // solution:
        //
        //        ┌           ┐
        //      l │ 2 xa + xb │
        // Fₛ = — │           │
        //      6 │ xa + 2 xb │
        //        └           ┘
        let l = 6.0;
        let (shape, mut state) = Verification::line_segment_lin2(l);
        let ips = &IP_LIN_LEGENDRE_2;
        let x_ips = shape.calc_integ_points_coords(&mut state, ips)?;
        let mut a = Vector::filled(shape.nnode, NOISE);
        shape_times_scalar(&mut a, &mut state, &shape, ips, 1.0, true, |p| Ok(x_ips[p][0]))?;
        let cf = l / 6.0;
        let (xa, xb) = (state.coords_transp[0][0], state.coords_transp[0][1]);
        let a_correct = &[cf * (2.0 * xa + xb), cf * (xa + 2.0 * xb)];
        assert_vec_approx_eq!(a.as_data(), a_correct, 1e-15);
        Ok(())
    }

    #[test]
    fn shape_times_scalar_works_tri3() -> Result<(), StrError> {
        // tri3 with a constant source term:
        //
        // s(x) = cₛ
        //
        // solution:
        //           ┌   ┐
        //      cₛ A │ 1 │
        // Fₛ = ———— │ 1 │
        //        3  │ 1 │
        //           └   ┘
        let l = 5.0;
        let (shape, mut state, area) = Verification::equilateral_triangle_tri3(l);
        let ips = &IP_TRI_INTERNAL_1;
        const CS: f64 = 3.0;
        let mut a = Vector::filled(shape.nnode, NOISE);
        shape_times_scalar(&mut a, &mut state, &shape, ips, 1.0, true, |_| Ok(CS))?;
        let cf = CS * area / 3.0;
        let a_correct = &[cf, cf, cf];
        assert_vec_approx_eq!(a.as_data(), a_correct, 1e-14);
        Ok(())
    }

    #[test]
    fn shape_times_vector_works_lin2() -> Result<(), StrError> {
        // This test is similar to the shape_times_scalar with lin2, however using a vector
        // So, each component of `b` equals `Fₛ`
        let l = 6.0;
        let (shape, mut state) = Verification::line_segment_lin2(l);
        let ips = &IP_LIN_LEGENDRE_2;
        let x_ips = shape.calc_integ_points_coords(&mut state, ips)?;
        let v: Vec<_> = x_ips.iter().map(|x| Vector::filled(shape.space_ndim, x[0])).collect();
        let mut b = Vector::filled(shape.nnode * shape.space_ndim, NOISE);
        shape_times_vector(&mut b, &mut state, &shape, ips, &v, 1.0, true)?;
        let cf = l / 6.0;
        let (xa, xb) = (state.coords_transp[0][0], state.coords_transp[0][1]);
        let b_correct = &[
            cf * (2.0 * xa + xb),
            cf * (2.0 * xa + xb),
            cf * (xa + 2.0 * xb),
            cf * (xa + 2.0 * xb),
        ];
        assert_vec_approx_eq!(b.as_data(), b_correct, 1e-15);
        Ok(())
    }

    #[test]
    fn shape_times_vector_works_tri3() -> Result<(), StrError> {
        // This test is similar to the shape_times_scalar with tri3, however using a vector
        // So, each component of `b` equals `Fₛ`
        let l = 5.0;
        let (shape, mut state, area) = Verification::equilateral_triangle_tri3(l);
        let ips = &IP_TRI_INTERNAL_1;
        const CS: f64 = 3.0;
        let v: Vec<_> = (0..ips.len()).map(|_| Vector::filled(shape.space_ndim, CS)).collect();
        let mut b = Vector::filled(shape.nnode * shape.space_ndim, NOISE);
        shape_times_vector(&mut b, &mut state, &shape, ips, &v, 1.0, true)?;
        let cf = CS * area / 3.0;
        let b_correct = &[cf, cf, cf, cf, cf, cf];
        assert_vec_approx_eq!(b.as_data(), b_correct, 1e-14);
        Ok(())
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))]

extern crate libc;

use std::io;
use std::mem;
use std::os::unix::io::RawFd;

use hidproto::*;
use util::{from_unix_result, io_err};
use super::hidwrapper::{_HIDIOCGRDESCSIZE, _HIDIOCGRDESC};

#[allow(non_camel_case_types)]
#[repr(C)]
pub struct LinuxReportDescriptor {
    size: ::libc::c_int,
    value: [u8; 4096],
}

const HID_MAX_DESCRIPTOR_SIZE: usize = 4096;

#[cfg(not(target_env = "musl"))]
type IocType = libc::c_ulong;
#[cfg(target_env = "musl")]
type IocType = libc::c_int;

pub unsafe fn hidiocgrdescsize(
    fd: libc::c_int,
    val: *mut ::libc::c_int
) -> io::Result<libc::c_int> {
    from_unix_result(libc::ioctl(fd, _HIDIOCGRDESCSIZE as IocType, val))
}

pub unsafe fn hidiocgrdesc(
    fd: libc::c_int,
    val: *mut LinuxReportDescriptor
) -> io::Result<libc::c_int> {
    from_unix_result(libc::ioctl(fd, _HIDIOCGRDESC as IocType, val))
}

pub fn is_u2f_device(fd: RawFd) -> bool {
    match read_report_descriptor(fd) {
        Ok(desc) => has_fido_usage(desc),
        Err(_) => false, // Upon failure, just say it's not a U2F device.
    }
}

fn read_report_descriptor(fd: RawFd) -> io::Result<ReportDescriptor> {
    let mut desc = LinuxReportDescriptor {
        size: 0,
        value: [0; HID_MAX_DESCRIPTOR_SIZE],
    };

    let _ = unsafe { hidiocgrdescsize(fd, &mut desc.size)? };
    if desc.size == 0 || desc.size as usize > desc.value.len() {
        return Err(io_err("unexpected hidiocgrdescsize() result"));
    }

    let _ = unsafe { hidiocgrdesc(fd, &mut desc)? };
    let mut value = Vec::from(&desc.value[..]);
    value.truncate(desc.size as usize);
    Ok(ReportDescriptor { value })
}
<commit_msg>remove unused std::mem<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))]

extern crate libc;

use std::io;
use std::os::unix::io::RawFd;

use hidproto::*;
use util::{from_unix_result, io_err};
use super::hidwrapper::{_HIDIOCGRDESCSIZE, _HIDIOCGRDESC};

#[allow(non_camel_case_types)]
#[repr(C)]
pub struct LinuxReportDescriptor {
    size: ::libc::c_int,
    value: [u8; 4096],
}

const HID_MAX_DESCRIPTOR_SIZE: usize = 4096;

#[cfg(not(target_env = "musl"))]
type IocType = libc::c_ulong;
#[cfg(target_env = "musl")]
type IocType = libc::c_int;

pub unsafe fn hidiocgrdescsize(
    fd: libc::c_int,
    val: *mut ::libc::c_int
) -> io::Result<libc::c_int> {
    from_unix_result(libc::ioctl(fd, _HIDIOCGRDESCSIZE as IocType, val))
}

pub unsafe fn hidiocgrdesc(
    fd: libc::c_int,
    val: *mut LinuxReportDescriptor
) -> io::Result<libc::c_int> {
    from_unix_result(libc::ioctl(fd, _HIDIOCGRDESC as IocType, val))
}

pub fn is_u2f_device(fd: RawFd) -> bool {
    match read_report_descriptor(fd) {
        Ok(desc) => has_fido_usage(desc),
        Err(_) => false, // Upon failure, just say it's not a U2F device.
    }
}

fn read_report_descriptor(fd: RawFd) -> io::Result<ReportDescriptor> {
    let mut desc = LinuxReportDescriptor {
        size: 0,
        value: [0; HID_MAX_DESCRIPTOR_SIZE],
    };

    let _ = unsafe { hidiocgrdescsize(fd, &mut desc.size)? };
    if desc.size == 0 || desc.size as usize > desc.value.len() {
        return Err(io_err("unexpected hidiocgrdescsize() result"));
    }

    let _ = unsafe { hidiocgrdesc(fd, &mut desc)? };
    let mut value = Vec::from(&desc.value[..]);
    value.truncate(desc.size as usize);
    Ok(ReportDescriptor { value })
}
<|endoftext|>