<commit_before>/* Copyright 2016 Mark Haines
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
use readhex::*;

const HEX : [u8 ; 16] = *b"0123456789ABCDEF";

pub fn compact_vector(input: &[u8], output: &mut Vec<u8>) -> Result<(),()> {
    if compact_vector_(input, output) {
        Ok(())
    } else {
        Err(())
    }
}

fn compact_vector_(input: &[u8], output: &mut Vec<u8>) -> bool {
    let mut iter = input.iter();

    loop {
        let input_char = match iter.next() {
            None => return true,
            Some(value) => *value,
        };
        if input_char <= b' ' { // Whitespace '\n', '\r', '\t', ' '
            continue;
        }
        output.push(input_char);
        if input_char == b'\"' { // Double Quote '\"'
            loop {
                let input_char = match iter.next() {
                    None => return false,
                    Some(value) => *value,
                };
                if input_char == b'\\' { // Back Slash '\\'
                    let input_char = match iter.next() {
                        None => return false,
                        Some(value) => *value,
                    };
                    if input_char == b'u' { // Unicode escape "u"
                        let h0 = match iter.next() {
                            None => return false,
                            Some(value) => *value
                        };
                        let h1 = match iter.next() {
                            None => return false,
                            Some(value) => *value
                        };
                        let h2 = match iter.next() {
                            None => return false,
                            Some(value) => *value
                        };
                        let h3 = match iter.next() {
                            None => return false,
                            Some(value) => *value
                        };
                        let escaped = read_hexdigits(h0, h1, h2, h3);
                        if escaped < 0x20 {
                            output.push(b'\\');
                            match escaped {
                                0x08 => output.push(b'b'),
                                0x09 => output.push(b't'),
                                0x0A => output.push(b'n'),
                                0x0C => output.push(b'f'),
                                0x0D => output.push(b'r'),
                                _ => {
                                    output.push(b'u');
                                    output.push(b'0');
                                    output.push(b'0');
                                    output.push(b'0' + (escaped as u8 >> 4));
                                    output.push(HEX[(escaped & 0xF) as usize]);
                                },
                            }
                        } else if escaped < 0x80 {
                            if escaped as u8 == b'\"' || escaped as u8 == b'\\' {
                                output.push(b'\\');
                            }
                            output.push(escaped as u8);
                        } else if escaped < 0x800 {
                            output.push((escaped >> 6) as u8 | 0xC0);
                            output.push((escaped as u8 & 0x3F) | 0x80);
                        } else {
                            if escaped < 0xD800 || escaped >= 0xE000 {
                                output.push((escaped >> 12) as u8 | 0xE0);
                                output.push(((escaped >> 6) & 0x3F) as u8 | 0x80);
                                output.push((escaped as u8 & 0x3F) | 0x80);
                            } else {
                                // surrogate pair
                                match iter.next() {
                                    None => return false,
                                    _ => {;}
                                }
                                match iter.next() {
                                    None => return false,
                                    _ => {;}
                                }
                                let h0 = match iter.next() {
                                    None => return false,
                                    Some(value) => *value
                                };
                                let h1 = match iter.next() {
                                    None => return false,
                                    Some(value) => *value
                                };
                                let h2 = match iter.next() {
                                    None => return false,
                                    Some(value) => *value
                                };
                                let h3 = match iter.next() {
                                    None => return false,
                                    Some(value) => *value
                                };
                                let surrogate = read_hexdigits(h0, h1, h2, h3);
                                let codepoint = 0x10000 + (
                                    ((escaped & 0x3FF) << 10) | (surrogate & 0x3FF)
                                );
                                output.push((codepoint >> 18) as u8 | 0xF0);
                                output.push(((codepoint >> 12) & 0x3F) as u8 | 0x80);
                                output.push(((codepoint >> 6) & 0x3F) as u8 | 0x80);
                                output.push((codepoint as u8 & 0x3F) | 0x80);
                            }
                        }

                    } else if input_char == b'/' { // Forward Slash '/'
                        output.push(input_char);
                    } else {
                        output.push(b'\\');
                        output.push(input_char);
                    }
                } else {
                    output.push(input_char);
                }
                if input_char == b'\"' {
                    break;
                }
            }
        }
    }
}

pub fn compact(input_json: &str) -> String {
    let mut output : Vec<u8> = Vec::with_capacity(input_json.as_bytes().len());
    compact_vector(input_json.as_bytes(), &mut output).unwrap();
    return String::from_utf8(output).unwrap();
}

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

    #[test]
    fn compact_json_object() {
        assert_eq!("{}", compact("{ }"));
    }

    #[test]
    fn compact_json_string() {
        assert_eq!(
            r#"{"key":"\"hello / world\""}"#,
            compact(r#" { "key" : "\"hello \/ world\"" } "#)
        );
    }

    #[test]
    fn compact_unicode_escapes() {
        assert_eq!(
            r#"["\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007"]"#,
            compact(r#"["\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007"]"#)
        );
        assert_eq!(
            r#"["\b\t\n\u000B\f\r\u000E\u000F"]"#,
            compact(r#"["\u0008\u0009\u000A\u000B\u000C\u000D\u000E\u000F"]"#)
        );
        assert_eq!(
            r#"["\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017"]"#,
            compact(r#"["\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017"]"#)
        );
        assert_eq!(
            r#"["\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F"]"#,
            compact(r#"["\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F"]"#)
        );
    }

    #[test]
    fn compact_unicode_utf8() {
        assert_eq!(
            "[\"a\\\\B\\\"\"]",
            compact("[\"\\u0061\\u005C\\u0042\\u0022\"]")
        );
        assert_eq!("[\"\u{120}\"]", compact("[\"\\u0120\"]"));
        assert_eq!("[\"\u{FFF}\"]", compact("[\"\\u0FFF\"]"));
        assert_eq!("[\"\u{1820}\"]", compact("[\"\\u1820\"]"));
        assert_eq!("[\"\u{FFFF}\"]", compact("[\"\\uFFFF\"]"));
        assert_eq!("[\"\u{20820}\"]", compact("[\"\\uD842\\uDC20\"]"));
        assert_eq!("[\"\u{10FFFF}\"]", compact("[\"\\uDBFF\\uDFFF\"]"));
    }
}
<commit_msg>Split out compacting unicode into a separate fn<commit_after>/* Copyright 2016 Mark Haines
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
use readhex::*;

const HEX : [u8 ; 16] = *b"0123456789ABCDEF";

pub fn compact_vector(input: &[u8], output: &mut Vec<u8>) -> Result<(),()> {
    if compact_vector_(input, output) {
        Ok(())
    } else {
        Err(())
    }
}

fn compact_vector_(input: &[u8], output: &mut Vec<u8>) -> bool {
    let mut iter = input.iter();

    loop {
        let input_char = match iter.next() {
            None => return true,
            Some(value) => *value,
        };
        if input_char <= b' ' { // Whitespace '\n', '\r', '\t', ' '
            continue;
        }
        output.push(input_char);
        if input_char == b'\"' { // Double Quote '\"'
            loop {
                let input_char = match iter.next() {
                    None => return false,
                    Some(value) => *value,
                };
                if input_char == b'\\' { // Back Slash '\\'
                    let input_char = match iter.next() {
                        None => return false,
                        Some(value) => *value,
                    };
                    if input_char == b'u' { // Unicode escape "u"
                        if !compact_unicode_escape(&mut iter, output) {
                            return false
                        }
                    } else if input_char == b'/' { // Forward Slash '/'
                        output.push(input_char);
                    } else {
                        output.push(b'\\');
                        output.push(input_char);
                    }
                } else {
                    output.push(input_char);
                }
                if input_char == b'\"' {
                    break;
                }
            }
        }
    }
}

fn compact_unicode_escape<'a, T: Iterator<Item=&'a u8>>(iter: &mut T, output: &mut Vec<u8>) -> bool {
    let h0 = match iter.next() {
        None => return false,
        Some(value) => *value
    };
    let h1 = match iter.next() {
        None => return false,
        Some(value) => *value
    };
    let h2 = match iter.next() {
        None => return false,
        Some(value) => *value
    };
    let h3 = match iter.next() {
        None => return false,
        Some(value) => *value
    };
    let escaped = read_hexdigits(h0, h1, h2, h3);
    if escaped < 0x20 {
        output.push(b'\\');
        match escaped {
            0x08 => output.push(b'b'),
            0x09 => output.push(b't'),
            0x0A => output.push(b'n'),
            0x0C => output.push(b'f'),
            0x0D => output.push(b'r'),
            _ => {
                output.push(b'u');
                output.push(b'0');
                output.push(b'0');
                output.push(b'0' + (escaped as u8 >> 4));
                output.push(HEX[(escaped & 0xF) as usize]);
            },
        }
    } else if escaped < 0x80 {
        if escaped as u8 == b'\"' || escaped as u8 == b'\\' {
            output.push(b'\\');
        }
        output.push(escaped as u8);
    } else if escaped < 0x800 {
        output.push((escaped >> 6) as u8 | 0xC0);
        output.push((escaped as u8 & 0x3F) | 0x80);
    } else if escaped < 0xD800 || escaped >= 0xE000 {
        output.push((escaped >> 12) as u8 | 0xE0);
        output.push(((escaped >> 6) & 0x3F) as u8 | 0x80);
        output.push((escaped as u8 & 0x3F) | 0x80);
    } else {
        // surrogate pair
        if iter.next() == None {
            return false
        }
        if iter.next() == None {
            return false
        }
        let h0 = match iter.next() {
            None => return false,
            Some(value) => *value
        };
        let h1 = match iter.next() {
            None => return false,
            Some(value) => *value
        };
        let h2 = match iter.next() {
            None => return false,
            Some(value) => *value
        };
        let h3 = match iter.next() {
            None => return false,
            Some(value) => *value
        };
        let surrogate = read_hexdigits(h0, h1, h2, h3);
        let codepoint = 0x10000 + (
            ((escaped & 0x3FF) << 10) | (surrogate & 0x3FF)
        );
        output.push((codepoint >> 18) as u8 | 0xF0);
        output.push(((codepoint >> 12) & 0x3F) as u8 | 0x80);
        output.push(((codepoint >> 6) & 0x3F) as u8 | 0x80);
        output.push((codepoint as u8 & 0x3F) | 0x80);
    }
    return true;
}

pub fn compact(input_json: &str) -> String {
    let mut output : Vec<u8> = Vec::with_capacity(input_json.as_bytes().len());
    compact_vector(input_json.as_bytes(), &mut output).unwrap();
    return String::from_utf8(output).unwrap();
}

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

    #[test]
    fn compact_json_object() {
        assert_eq!("{}", compact("{ }"));
    }

    #[test]
    fn compact_json_string() {
        assert_eq!(
            r#"{"key":"\"hello / world\""}"#,
            compact(r#" { "key" : "\"hello \/ world\"" } "#)
        );
    }

    #[test]
    fn compact_unicode_escapes() {
        assert_eq!(
            r#"["\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007"]"#,
            compact(r#"["\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007"]"#)
        );
        assert_eq!(
            r#"["\b\t\n\u000B\f\r\u000E\u000F"]"#,
            compact(r#"["\u0008\u0009\u000A\u000B\u000C\u000D\u000E\u000F"]"#)
        );
        assert_eq!(
            r#"["\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017"]"#,
            compact(r#"["\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017"]"#)
        );
        assert_eq!(
            r#"["\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F"]"#,
            compact(r#"["\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F"]"#)
        );
    }

    #[test]
    fn compact_unicode_utf8() {
        assert_eq!(
            "[\"a\\\\B\\\"\"]",
            compact("[\"\\u0061\\u005C\\u0042\\u0022\"]")
        );
        assert_eq!("[\"\u{120}\"]", compact("[\"\\u0120\"]"));
        assert_eq!("[\"\u{FFF}\"]", compact("[\"\\u0FFF\"]"));
        assert_eq!("[\"\u{1820}\"]", compact("[\"\\u1820\"]"));
        assert_eq!("[\"\u{FFFF}\"]", compact("[\"\\uFFFF\"]"));
        assert_eq!("[\"\u{20820}\"]", compact("[\"\\uD842\\uDC20\"]"));
        assert_eq!("[\"\u{10FFFF}\"]", compact("[\"\\uDBFF\\uDFFF\"]"));
    }
}
<|endoftext|>


<commit_before>extern crate term;

use matcher::Match;
use std::io;
use std::io::Write;
use std::process;
use term::{Terminal, StdoutTerminal, StderrTerminal};

// ---------------------------------------------------------------------------------------------------------------------
// Console
// ---------------------------------------------------------------------------------------------------------------------

pub enum ConsoleTextKind {
    Filename ,
    Text     ,
    MatchText,
    Other    ,
    Info     ,
    Error    ,
}

pub struct Console {
    pub is_color: bool,
    term_stdout: Box<StdoutTerminal>,
    term_stderr: Box<StderrTerminal>,
}

impl Console {
    pub fn new() -> Self {
        Console {
            term_stdout: term::stdout().unwrap_or_else( || { process::exit( 1 ); } ),
            term_stderr: term::stderr().unwrap_or_else( || { process::exit( 1 ); } ),
            is_color   : true,
        }
    }

    pub fn carriage_return( &mut self ) {
        let _ = self.term_stdout.carriage_return();
    }

    pub fn cursor_up( &mut self ) {
        let _ = self.term_stdout.cursor_up();
    }

    pub fn delete_line( &mut self ) {
        let _ = self.term_stdout.delete_line();
    }

    pub fn write_with_clear( &mut self, kind: ConsoleTextKind, val: &str ) {
        self.carriage_return();
        self.delete_line();
        self.write( kind, val );
    }

    pub fn write( &mut self, kind: ConsoleTextKind, val: &str ) {
        if self.is_color {
            let color = match kind {
                ConsoleTextKind::Filename  => term::color::BRIGHT_GREEN,
                ConsoleTextKind::Text      => term::color::WHITE,
                ConsoleTextKind::MatchText => term::color::BRIGHT_YELLOW,
                ConsoleTextKind::Other     => term::color::BRIGHT_CYAN,
                ConsoleTextKind::Info      => term::color::BRIGHT_CYAN,
                ConsoleTextKind::Error     => term::color::BRIGHT_RED,
            };
            self.term_stdout.fg( color ).unwrap_or_else( |_| { process::exit( 1 ); } );
            self.term_stderr.fg( color ).unwrap_or_else( |_| { process::exit( 1 ); } );
        }

        match kind {
            ConsoleTextKind::Error => write!( self.term_stderr, "{}", val ).unwrap_or_else( |_| { process::exit( 1 ); } ),
            ConsoleTextKind::Info  => write!( self.term_stderr, "{}", val ).unwrap_or_else( |_| { process::exit( 1 ); } ),
            _                      => write!( self.term_stdout, "{}", val ).unwrap_or_else( |_| { process::exit( 1 ); } ),
        }

        if self.is_color {
            self.term_stdout.reset().unwrap_or_else( |_| { process::exit( 1 ); } );
            self.term_stderr.reset().unwrap_or_else( |_| { process::exit( 1 ); } );
        }
        let _ = io::stdout().flush();
        let _ = io::stderr().flush();
    }

    pub fn write_match_line( &mut self, src: &[u8], m: &Match ) {
        let mut beg = m.beg;
        let mut end = m.end;
        while beg > 0 {
            if src[beg] == 0x0d || src[beg] == 0x0a { beg += 1; break; }
            beg -= 1;
        }
        while src.len() > end {
            if src[end] == 0x0d || src[end] == 0x0a { end -= 1; break; }
            end += 1;
        }
        if src.len() <= end { end = src.len() } else { end += 1 };

        if beg < m.beg {
            self.write( ConsoleTextKind::Text, &String::from_utf8_lossy( &src[beg..m.beg] ) );
        }
        self.write( ConsoleTextKind::MatchText, &String::from_utf8_lossy( &src[m.beg..m.end] ) );
        if m.end < end {
            self.write( ConsoleTextKind::Text, &String::from_utf8_lossy( &src[m.end..end] ) );
        }
        self.write( ConsoleTextKind::Other, "\n" );
    }
}
<commit_msg>fix unnecessary outputs to stdout/stderr<commit_after>extern crate term;

use matcher::Match;
use std::io;
use std::io::Write;
use std::process;
use term::{Terminal, StdoutTerminal, StderrTerminal};
use term::color::Color;

// ---------------------------------------------------------------------------------------------------------------------
// Console
// ---------------------------------------------------------------------------------------------------------------------

pub enum ConsoleTextKind {
    Filename ,
    Text     ,
    MatchText,
    Other    ,
    Info     ,
    Error    ,
}

pub struct Console {
    pub is_color: bool,
    term_stdout: Box<StdoutTerminal>,
    term_stderr: Box<StderrTerminal>,
}

impl Console {
    pub fn new() -> Self {
        Console {
            term_stdout: term::stdout().unwrap_or_else( || { process::exit( 1 ); } ),
            term_stderr: term::stderr().unwrap_or_else( || { process::exit( 1 ); } ),
            is_color   : true,
        }
    }

    pub fn carriage_return( &mut self ) {
        let _ = self.term_stdout.carriage_return();
    }

    pub fn cursor_up( &mut self ) {
        let _ = self.term_stdout.cursor_up();
    }

    pub fn delete_line( &mut self ) {
        let _ = self.term_stdout.delete_line();
    }

    pub fn write_with_clear( &mut self, kind: ConsoleTextKind, val: &str ) {
        self.carriage_return();
        self.delete_line();
        self.write( kind, val );
    }

    pub fn write( &mut self, kind: ConsoleTextKind, val: &str ) {
        let color = match kind {
            ConsoleTextKind::Filename  => term::color::BRIGHT_GREEN,
            ConsoleTextKind::Text      => term::color::WHITE,
            ConsoleTextKind::MatchText => term::color::BRIGHT_YELLOW,
            ConsoleTextKind::Other     => term::color::BRIGHT_CYAN,
            ConsoleTextKind::Info      => term::color::BRIGHT_CYAN,
            ConsoleTextKind::Error     => term::color::BRIGHT_RED,
        };

        match kind {
            ConsoleTextKind::Error => self.write_stderr( val, color ),
            ConsoleTextKind::Info  => self.write_stderr( val, color ),
            _                      => self.write_stdout( val, color ),
        }
    }

    pub fn write_match_line( &mut self, src: &[u8], m: &Match ) {
        let mut beg = m.beg;
        let mut end = m.end;
        while beg > 0 {
            if src[beg] == 0x0d || src[beg] == 0x0a { beg += 1; break; }
            beg -= 1;
        }
        while src.len() > end {
            if src[end] == 0x0d || src[end] == 0x0a { end -= 1; break; }
            end += 1;
        }
        if src.len() <= end { end = src.len() } else { end += 1 };

        if beg < m.beg {
            self.write( ConsoleTextKind::Text, &String::from_utf8_lossy( &src[beg..m.beg] ) );
        }
        self.write( ConsoleTextKind::MatchText, &String::from_utf8_lossy( &src[m.beg..m.end] ) );
        if m.end < end {
            self.write( ConsoleTextKind::Text, &String::from_utf8_lossy( &src[m.end..end] ) );
        }
        self.write( ConsoleTextKind::Other, "\n" );
    }

    fn write_stdout( &mut self, val: &str, color: Color ) {
        if self.is_color {
            self.term_stdout.fg( color ).unwrap_or_else( |_| { process::exit( 1 ); } );
        }

        write!( self.term_stdout, "{}", val ).unwrap_or_else( |_| { process::exit( 1 ); } );

        if self.is_color {
            self.term_stdout.reset().unwrap_or_else( |_| { process::exit( 1 ); } );
        }

        let _ = io::stdout().flush();
    }

    fn write_stderr( &mut self, val: &str, color: Color ) {
        if self.is_color {
            self.term_stderr.fg( color ).unwrap_or_else( |_| { process::exit( 1 ); } );
        }

        write!( self.term_stderr, "{}", val ).unwrap_or_else( |_| { process::exit( 1 ); } );

        if self.is_color {
            self.term_stderr.reset().unwrap_or_else( |_| { process::exit( 1 ); } );
        }

        let _ = io::stderr().flush();
    }

}
<|endoftext|>


<commit_before>use crate::callback::Identity0Consumer;
use crate::executor;
use crate::futures;
use crate::result::TockResult;
use crate::syscalls;
use core::cell::Cell;
use core::fmt;
use core::mem;

// Global console
static mut CONSOLE: Option<Console> = None;

const DRIVER_NUMBER: usize = 1;

mod command_nr {
    pub const WRITE: usize = 1;
}

mod subscribe_nr {
    pub const SET_ALARM: usize = 1;
}

mod allow_nr {
    pub const SHARE_BUFFER: usize = 1;
}

#[non_exhaustive]
pub struct ConsoleDriver;

impl ConsoleDriver {
    pub fn create_console(self) {
        let console = Console {
            allow_buffer: [0; 64],
        };

        console.set_global_console();
    }
}

pub struct Console {
    allow_buffer: [u8; 64],
}

pub fn get_global_console() -> Option<&'static mut Console> {
    unsafe { CONSOLE.as_mut() }
}

impl Console {
    pub fn write<S: AsRef<[u8]>>(&mut self, text: S) -> TockResult<()> {
        let mut not_written_yet = text.as_ref();
        while !not_written_yet.is_empty() {
            let num_bytes_to_print = self.allow_buffer.len().min(not_written_yet.len());
            self.allow_buffer[..num_bytes_to_print]
                .copy_from_slice(&not_written_yet[..num_bytes_to_print]);
            self.flush(num_bytes_to_print)?;
            not_written_yet = &not_written_yet[num_bytes_to_print..];
        }
        Ok(())
    }

    fn flush(&mut self, num_bytes_to_print: usize) -> TockResult<()> {
        let shared_memory = syscalls::allow(
            DRIVER_NUMBER,
            allow_nr::SHARE_BUFFER,
            &mut self.allow_buffer[..num_bytes_to_print],
        )?;

        let is_written = Cell::new(false);
        let mut is_written_alarm = || is_written.set(true);
        let subscription = syscalls::subscribe::<Identity0Consumer, _>(
            DRIVER_NUMBER,
            subscribe_nr::SET_ALARM,
            &mut is_written_alarm,
        )?;

        syscalls::command(DRIVER_NUMBER, command_nr::WRITE, num_bytes_to_print, 0)?;

        unsafe { executor::block_on(futures::wait_until(|| is_written.get())) };

        mem::drop(subscription);
        mem::drop(shared_memory);

        Ok(())
    }

    fn set_global_console(self) {
        unsafe {
            CONSOLE = Some(self);
        }
    }
}

impl fmt::Write for Console {
    fn write_str(&mut self, string: &str) -> Result<(), fmt::Error> {
        self.write(string).map_err(|_| fmt::Error)
    }
}

#[macro_export]
macro_rules! println {
    () => ({
        // Allow an empty println!() to print the location when hit
        println!("")
    });
    ($msg:expr) => ({
        if let Some(console) = $crate::console::get_global_console() {
            use core::fmt::Write;
            let _ = writeln!(console, $msg);
        }
    });
    ($fmt:expr, $($arg:tt)+) => ({
        if let Some(console) = $crate::console::get_global_console() {
            use core::fmt::Write;
            let _ = writeln!(console, "{}", format_args!($fmt, $($arg)+));
        }
    });
}

#[macro_export]
macro_rules! print {
    () => ({
        // Allow an empty print!() to print the location when hit
        print!("")
    });
    ($msg:expr) => ({
        if let Some(console) = $crate::console::get_global_console() {
            use core::fmt::Write;
            let _ =  write!(console, $msg);
        }
    });
    ($fmt:expr, $($arg:tt)+) => ({
        if let Some(console) = $crate::console::get_global_console() {
            use core::fmt::Write;
            let _ = write!(console, "{}", format_args!($fmt, $($arg)+));
        }
    });
}
<commit_msg>console: Ensure only 1 console exists at a time<commit_after>use crate::callback::Identity0Consumer;
use crate::executor;
use crate::futures;
use crate::result::TockResult;
use crate::syscalls;
use core::cell::Cell;
use core::fmt;
use core::mem;

// Global console
static mut CONSOLE: Option<Console> = None;

const DRIVER_NUMBER: usize = 1;

mod command_nr {
    pub const WRITE: usize = 1;
}

mod subscribe_nr {
    pub const SET_ALARM: usize = 1;
}

mod allow_nr {
    pub const SHARE_BUFFER: usize = 1;
}

#[non_exhaustive]
pub struct ConsoleDriver;

impl ConsoleDriver {
    pub fn create_console(self) {
        let console = Console {
            allow_buffer: [0; 64],
        };

        console.set_global_console();
    }
}

pub struct Console {
    allow_buffer: [u8; 64],
}

pub fn get_global_console() -> Option<Console> {
    unsafe {
        if let Some(con) = CONSOLE.take() {
            Some(con)
        } else {
            None
        }
    }
}

impl Console {
    pub fn write<S: AsRef<[u8]>>(&mut self, text: S) -> TockResult<()> {
        let mut not_written_yet = text.as_ref();
        while !not_written_yet.is_empty() {
            let num_bytes_to_print = self.allow_buffer.len().min(not_written_yet.len());
            self.allow_buffer[..num_bytes_to_print]
                .copy_from_slice(&not_written_yet[..num_bytes_to_print]);
            self.flush(num_bytes_to_print)?;
            not_written_yet = &not_written_yet[num_bytes_to_print..];
        }
        Ok(())
    }

    fn flush(&mut self, num_bytes_to_print: usize) -> TockResult<()> {
        let shared_memory = syscalls::allow(
            DRIVER_NUMBER,
            allow_nr::SHARE_BUFFER,
            &mut self.allow_buffer[..num_bytes_to_print],
        )?;

        let is_written = Cell::new(false);
        let mut is_written_alarm = || is_written.set(true);
        let subscription = syscalls::subscribe::<Identity0Consumer, _>(
            DRIVER_NUMBER,
            subscribe_nr::SET_ALARM,
            &mut is_written_alarm,
        )?;

        syscalls::command(DRIVER_NUMBER, command_nr::WRITE, num_bytes_to_print, 0)?;

        unsafe { executor::block_on(futures::wait_until(|| is_written.get())) };

        mem::drop(subscription);
        mem::drop(shared_memory);

        Ok(())
    }

    pub fn set_global_console(self) {
        unsafe {
            CONSOLE = Some(self);
        }
    }
}

impl fmt::Write for Console {
    fn write_str(&mut self, string: &str) -> Result<(), fmt::Error> {
        self.write(string).map_err(|_| fmt::Error)
    }
}

#[macro_export]
macro_rules! println {
    () => ({
        // Allow an empty println!() to print the location when hit
        println!("")
    });
    ($msg:expr) => ({
        if let Some(mut console) = $crate::console::get_global_console() {
            use core::fmt::Write;
            let _ = writeln!(console, $msg);
            console.set_global_console();
        }
    });
    ($fmt:expr, $($arg:tt)+) => ({
        if let Some(mut console) = $crate::console::get_global_console() {
            use core::fmt::Write;
            let _ = writeln!(console, "{}", format_args!($fmt, $($arg)+));
            console.set_global_console();
        }
    });
}

#[macro_export]
macro_rules! print {
    () => ({
        // Allow an empty print!() to print the location when hit
        print!("")
    });
    ($msg:expr) => ({
        if let Some(mut console) = $crate::console::get_global_console() {
            use core::fmt::Write;
            let _ =  write!(console, $msg);
            console.set_global_console();
        }
    });
    ($fmt:expr, $($arg:tt)+) => ({
        if let Some(mut console) = $crate::console::get_global_console() {
            use core::fmt::Write;
            let _ = write!(console, "{}", format_args!($fmt, $($arg)+));
            console.set_global_console();
        }
    });
}
<|endoftext|>


<commit_before>use sdl2::{self, Sdl};
use sdl2::surface;
use sdl2::pixels;
use image::{self, GenericImage};

use std::fmt;
use std::io::Read;

use audio;
use conf;
use event;
use filesystem::Filesystem;
use graphics;
use input;
use mouse;
use timer;
use GameError;
use GameResult;

/// A `Context` is an object that holds on to global resources.
/// It basically tracks hardware state such as the screen, audio
/// system, timers, and so on.  Generally this type is **not** thread-
/// safe and only one `Context` can exist at a time.  Trying to create
/// another one will fail.
///
/// Most functions that interact with the hardware, for instance
/// drawing things, playing sounds, or loading resources (which then
/// need to be transformed into a format the hardware likes) will need
/// to access the `Context`.
pub struct Context {
    /// The Conf object the Context was created with
    pub conf: conf::Conf,
    /// SDL context
    pub sdl_context: Sdl,
    /// Filesystem state
    pub filesystem: Filesystem,
    /// Graphics state
    pub(crate) gfx_context: graphics::GraphicsContext,
    /// Event context
    pub event_context: sdl2::EventSubsystem,
    /// Timer state
    pub timer_context: timer::TimeContext,
    /// Audio context
    pub audio_context: audio::AudioContext,
    /// Gamepad context
    pub gamepad_context: input::GamepadContext,
    /// Mouse context
    pub mouse_context: mouse::MouseContext,
    /// Default font
    pub default_font: graphics::Font,
}

impl fmt::Debug for Context {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<Context: {:p}>", self)
    }
}

/// Sets the window icon from the Conf `window_icon` field.
/// An empty string in the conf's `window_icon`
/// means to do nothing.
fn set_window_icon(context: &mut Context) -> GameResult<()> {
    // This clone is a little annoying, but, borrowing is inconvenient.
    let icon = &context.conf.window_setup.icon.clone();
    if !icon.is_empty() {
        let mut f = context.filesystem.open(icon)?;
        let mut buf = Vec::new();
        f.read_to_end(&mut buf)?;
        let image = image::load_from_memory(&buf)?;
        let image_data = &mut image.to_rgba();
        // The "pitch" parameter here is not the count
        // between pixels, but the count between rows.
        // For some retarded reason.
        // Also SDL seems to have strange ideas of what
        // "RGBA" means.
        let surface = surface::Surface::from_data(
            image_data,
            image.width(),
            image.height(),
            image.width() * 4,
            pixels::PixelFormatEnum::ABGR8888,
        )?;
        let window = graphics::get_window_mut(context);
        window.set_icon(surface);
    };
    Ok(())
}

impl Context {
    /// Tries to create a new Context using settings from the given config file.
    /// Usually called by `Context::load_from_conf()`.
    fn from_conf(conf: conf::Conf, fs: Filesystem, sdl_context: Sdl) -> GameResult<Context> {
        let video = sdl_context.video()?;

        let audio_context = audio::AudioContext::new()?;
        let event_context = sdl_context.event()?;
        let timer_context = timer::TimeContext::new();
        let font = graphics::Font::default_font()?;
        let backend_spec = graphics::GlBackendSpec::from(conf.backend);
        let graphics_context = graphics::GraphicsContext::new(
            &video,
            &conf.window_setup,
            conf.window_mode,
            backend_spec,
        )?;
        let gamepad_context = input::GamepadContext::new(&sdl_context)?;
        let mouse_context = mouse::MouseContext::new();

        let mut ctx = Context {
            conf,
            sdl_context,
            filesystem: fs,
            gfx_context: graphics_context,
            event_context,
            timer_context,
            audio_context,
            gamepad_context,
            mouse_context,

            default_font: font,
        };

        set_window_icon(&mut ctx)?;

        Ok(ctx)
    }

    /// Tries to create a new Context by loading a config
    /// file from its default path, using the given `Conf`
    /// object as a default if none is found.
    ///
    /// The `game_id` and `author` are game-specific strings that
    /// are used to locate the default storage locations for the
    /// platform it looks in, as documented in the `filesystem`
    /// module.  You can also always debug-print the
    /// `Context::filesystem` field to see what paths it is
    /// searching.
    pub fn load_from_conf(
        game_id: &'static str,
        author: &'static str,
        default_config: conf::Conf,
    ) -> GameResult<Context> {
        let sdl_context = sdl2::init()?;
        let mut fs = Filesystem::new(game_id, author)?;

        let config = fs.read_config().unwrap_or(default_config);

        Context::from_conf(config, fs, sdl_context)
    }

    /// Prints out information on the resources subsystem.
    pub fn print_resource_stats(&mut self) {
        self.filesystem.print_all();
    }

    /// Triggers a Quit event.
    pub fn quit(&mut self) -> GameResult<()> {
        let now_dur = timer::get_time_since_start(self);
        let now = timer::duration_to_f64(now_dur);
        let e = sdl2::event::Event::Quit {
            timestamp: now as u32,
        };
        // println!("Pushing event {:?}", e);
        self.event_context.push_event(e).map_err(GameError::from)
    }

    /// Feeds an `Event` into the `Context` so it can update any internal
    /// state it needs to, such as detecting window resizes.  If you are
    /// rolling your own event loop, you should call this on the events
    /// you receive before processing them yourself.
    pub fn process_event(&mut self, event: &event::Event) {
        match *event {
            event::Event::MouseMotion { x, y, .. } => {
                // Keeping the mouse state info in the Context is a bit of a hack, see issue #283.
                // Seems the best workaround though.
                use graphics::Point2;
                self.mouse_context
                    .set_last_position(Point2::new(x as f32, y as f32));
            }
            event::Event::Window {
                win_event: sdl2::event::WindowEvent::Resized(_, _),
                ..
            } => {
                self.gfx_context.resize_viewport();
            }
            _ => {}
        }
    }
}

use std::path;

/// A builder object for creating a context.
///
/// Can do everything the `Context::load_from_conf()` method does, plus you can
/// also specify new paths to add to the resource path list at build time instead
/// of using `filesystem::mount()`.
#[derive(Debug)]
pub struct ContextBuilder {
    game_id: &'static str,
    author: &'static str,
    conf: conf::Conf,
    paths: Vec<path::PathBuf>,
    load_conf_file: bool,
}

impl ContextBuilder {
    /// Create a new ContextBuilder
    pub fn new(game_id: &'static str, author: &'static str) -> Self {
        Self {
            game_id,
            author,
            conf: conf::Conf::default(),
            paths: vec![],
            load_conf_file: true,
        }
    }

    /// Sets the window setup settings
    pub fn window_setup(mut self, setup: conf::WindowSetup) -> Self {
        self.conf.window_setup = setup;
        self
    }

    /// Sets the window mode settings
    pub fn window_mode(mut self, mode: conf::WindowMode) -> Self {
        self.conf.window_mode = mode;
        self
    }

    /// Sets the graphics backend
    pub fn backend(mut self, backend: conf::Backend) -> Self {
        self.conf.backend = backend;
        self
    }

    /// Add a new read-only filesystem path to the places to search
    /// for resources.
    pub fn add_resource_path<T>(mut self, path: T) -> Self
    where
        T: Into<path::PathBuf>,
    {
        self.paths.push(path.into());
        self
    }

    /// Specifies whether or not to load the `conf.toml` file if it
    /// exists and use its settings to override the provided values.
    /// Defaults to `true` which is usually what you want, but being
    /// able to fiddle with it is sometimes useful for debugging.
    pub fn with_conf_file(mut self, load_conf_file: bool) -> Self {
        self.load_conf_file = load_conf_file;
        self
    }

    /// Build the Context.
    pub fn build(self) -> GameResult<Context> {
        let sdl_context = sdl2::init()?;
        let mut fs = Filesystem::new(self.game_id, self.author)?;

        let config = if self.load_conf_file {
            fs.read_config().unwrap_or(self.conf)
        } else {
            self.conf
        };

        for path in &self.paths {
            fs.mount(path, true);
        }

        Context::from_conf(config, fs, sdl_context)
    }
}
<commit_msg>Added a note on logging to Context::print_resource_stats().<commit_after>use sdl2::{self, Sdl};
use sdl2::surface;
use sdl2::pixels;
use image::{self, GenericImage};

use std::fmt;
use std::io::Read;

use audio;
use conf;
use event;
use filesystem::Filesystem;
use graphics;
use input;
use mouse;
use timer;
use GameError;
use GameResult;

/// A `Context` is an object that holds on to global resources.
/// It basically tracks hardware state such as the screen, audio
/// system, timers, and so on.  Generally this type is **not** thread-
/// safe and only one `Context` can exist at a time.  Trying to create
/// another one will fail.
///
/// Most functions that interact with the hardware, for instance
/// drawing things, playing sounds, or loading resources (which then
/// need to be transformed into a format the hardware likes) will need
/// to access the `Context`.
pub struct Context {
    /// The Conf object the Context was created with
    pub conf: conf::Conf,
    /// SDL context
    pub sdl_context: Sdl,
    /// Filesystem state
    pub filesystem: Filesystem,
    /// Graphics state
    pub(crate) gfx_context: graphics::GraphicsContext,
    /// Event context
    pub event_context: sdl2::EventSubsystem,
    /// Timer state
    pub timer_context: timer::TimeContext,
    /// Audio context
    pub audio_context: audio::AudioContext,
    /// Gamepad context
    pub gamepad_context: input::GamepadContext,
    /// Mouse context
    pub mouse_context: mouse::MouseContext,
    /// Default font
    pub default_font: graphics::Font,
}

impl fmt::Debug for Context {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "<Context: {:p}>", self)
    }
}

/// Sets the window icon from the Conf `window_icon` field.
/// An empty string in the conf's `window_icon`
/// means to do nothing.
fn set_window_icon(context: &mut Context) -> GameResult<()> {
    // This clone is a little annoying, but, borrowing is inconvenient.
    let icon = &context.conf.window_setup.icon.clone();
    if !icon.is_empty() {
        let mut f = context.filesystem.open(icon)?;
        let mut buf = Vec::new();
        f.read_to_end(&mut buf)?;
        let image = image::load_from_memory(&buf)?;
        let image_data = &mut image.to_rgba();
        // The "pitch" parameter here is not the count
        // between pixels, but the count between rows.
        // For some retarded reason.
        // Also SDL seems to have strange ideas of what
        // "RGBA" means.
        let surface = surface::Surface::from_data(
            image_data,
            image.width(),
            image.height(),
            image.width() * 4,
            pixels::PixelFormatEnum::ABGR8888,
        )?;
        let window = graphics::get_window_mut(context);
        window.set_icon(surface);
    };
    Ok(())
}

impl Context {
    /// Tries to create a new Context using settings from the given config file.
    /// Usually called by `Context::load_from_conf()`.
    fn from_conf(conf: conf::Conf, fs: Filesystem, sdl_context: Sdl) -> GameResult<Context> {
        let video = sdl_context.video()?;

        let audio_context = audio::AudioContext::new()?;
        let event_context = sdl_context.event()?;
        let timer_context = timer::TimeContext::new();
        let font = graphics::Font::default_font()?;
        let backend_spec = graphics::GlBackendSpec::from(conf.backend);
        let graphics_context = graphics::GraphicsContext::new(
            &video,
            &conf.window_setup,
            conf.window_mode,
            backend_spec,
        )?;
        let gamepad_context = input::GamepadContext::new(&sdl_context)?;
        let mouse_context = mouse::MouseContext::new();

        let mut ctx = Context {
            conf,
            sdl_context,
            filesystem: fs,
            gfx_context: graphics_context,
            event_context,
            timer_context,
            audio_context,
            gamepad_context,
            mouse_context,

            default_font: font,
        };

        set_window_icon(&mut ctx)?;

        Ok(ctx)
    }

    /// Tries to create a new Context by loading a config
    /// file from its default path, using the given `Conf`
    /// object as a default if none is found.
    ///
    /// The `game_id` and `author` are game-specific strings that
    /// are used to locate the default storage locations for the
    /// platform it looks in, as documented in the `filesystem`
    /// module.  You can also always debug-print the
    /// `Context::filesystem` field to see what paths it is
    /// searching.
    pub fn load_from_conf(
        game_id: &'static str,
        author: &'static str,
        default_config: conf::Conf,
    ) -> GameResult<Context> {
        let sdl_context = sdl2::init()?;
        let mut fs = Filesystem::new(game_id, author)?;

        let config = fs.read_config().unwrap_or(default_config);

        Context::from_conf(config, fs, sdl_context)
    }

    /// Prints out information on the resources subsystem.
    pub fn print_resource_stats(&mut self) {
        // TODO: consider using logging macros.
        self.filesystem.print_all();
    }

    /// Triggers a Quit event.
    pub fn quit(&mut self) -> GameResult<()> {
        let now_dur = timer::get_time_since_start(self);
        let now = timer::duration_to_f64(now_dur);
        let e = sdl2::event::Event::Quit {
            timestamp: now as u32,
        };
        // println!("Pushing event {:?}", e);
        self.event_context.push_event(e).map_err(GameError::from)
    }

    /// Feeds an `Event` into the `Context` so it can update any internal
    /// state it needs to, such as detecting window resizes.  If you are
    /// rolling your own event loop, you should call this on the events
    /// you receive before processing them yourself.
    pub fn process_event(&mut self, event: &event::Event) {
        match *event {
            event::Event::MouseMotion { x, y, .. } => {
                // Keeping the mouse state info in the Context is a bit of a hack, see issue #283.
                // Seems the best workaround though.
                use graphics::Point2;
                self.mouse_context
                    .set_last_position(Point2::new(x as f32, y as f32));
            }
            event::Event::Window {
                win_event: sdl2::event::WindowEvent::Resized(_, _),
                ..
            } => {
                self.gfx_context.resize_viewport();
            }
            _ => {}
        }
    }
}

use std::path;

/// A builder object for creating a context.
///
/// Can do everything the `Context::load_from_conf()` method does, plus you can
/// also specify new paths to add to the resource path list at build time instead
/// of using `filesystem::mount()`.
#[derive(Debug)]
pub struct ContextBuilder {
    game_id: &'static str,
    author: &'static str,
    conf: conf::Conf,
    paths: Vec<path::PathBuf>,
    load_conf_file: bool,
}

impl ContextBuilder {
    /// Create a new ContextBuilder
    pub fn new(game_id: &'static str, author: &'static str) -> Self {
        Self {
            game_id,
            author,
            conf: conf::Conf::default(),
            paths: vec![],
            load_conf_file: true,
        }
    }

    /// Sets the window setup settings
    pub fn window_setup(mut self, setup: conf::WindowSetup) -> Self {
        self.conf.window_setup = setup;
        self
    }

    /// Sets the window mode settings
    pub fn window_mode(mut self, mode: conf::WindowMode) -> Self {
        self.conf.window_mode = mode;
        self
    }

    /// Sets the graphics backend
    pub fn backend(mut self, backend: conf::Backend) -> Self {
        self.conf.backend = backend;
        self
    }

    /// Add a new read-only filesystem path to the places to search
    /// for resources.
    pub fn add_resource_path<T>(mut self, path: T) -> Self
    where
        T: Into<path::PathBuf>,
    {
        self.paths.push(path.into());
        self
    }

    /// Specifies whether or not to load the `conf.toml` file if it
    /// exists and use its settings to override the provided values.
    /// Defaults to `true` which is usually what you want, but being
    /// able to fiddle with it is sometimes useful for debugging.
    pub fn with_conf_file(mut self, load_conf_file: bool) -> Self {
        self.load_conf_file = load_conf_file;
        self
    }

    /// Build the Context.
    pub fn build(self) -> GameResult<Context> {
        let sdl_context = sdl2::init()?;
        let mut fs = Filesystem::new(self.game_id, self.author)?;

        let config = if self.load_conf_file {
            fs.read_config().unwrap_or(self.conf)
        } else {
            self.conf
        };

        for path in &self.paths {
            fs.mount(path, true);
        }

        Context::from_conf(config, fs, sdl_context)
    }
}
<|endoftext|>


<commit_before>use gl;
use gl::types::*;
use types::{Color, Viewport, BufferBits, GLError};
use buffer::{ArrayBufferBinder, ElementArrayBufferBinder};
use program::{ProgramBinder, ProgramAttrib};
use texture_units::{TextureUnits};

pub struct Context {
    pub array_buffer: ArrayBufferBinder,
    pub element_array_buffer: ElementArrayBufferBinder,
    pub program: ProgramBinder,
    pub tex_units: TextureUnits
}

impl Context {
    pub unsafe fn current_context() -> Self {
        Context {
            array_buffer: ArrayBufferBinder,
            element_array_buffer: ElementArrayBufferBinder,
            program: ProgramBinder,
            tex_units: TextureUnits::current()
        }
    }

    pub fn clear_color(&mut self, color: Color) {
        unsafe {
            gl::ClearColor(color.r, color.g, color.b, color.a);
        }
    }

    pub fn clear(&mut self, buffers: BufferBits) {
        unsafe {
            gl::Clear(buffers.bits());
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`mask` includes a bit other than an allowed value",
                _ => "Unkown error"
            }
        }
    }

    pub fn enable_vertex_attrib_array(&self, attrib: ProgramAttrib) {
        unsafe {
            gl::EnableVertexAttribArray(attrib.gl_index);
            dbg_gl_error! {
                GLError::InvalidValue => "`index` is >= GL_MAX_VERTEX_ATTRIBS",
                _ => "Unknown error"
            }
        }
    }

    pub fn viewport(&self, viewport: Viewport) {
        unsafe {
            gl::Viewport(viewport.x as GLint,
                         viewport.y as GLint,
                         viewport.width as GLsizei,
                         viewport.height as GLsizei);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`width` or `height` is negative",
                _ => "Unknown error"
            }
        }
    }

    pub fn get_error() -> Option<GLError> {
        unsafe {
            match gl::GetError() {
                gl::INVALID_ENUM =>
                    Some(GLError::InvalidEnum),
                gl::INVALID_VALUE =>
                    Some(GLError::InvalidValue),
                gl::INVALID_OPERATION =>
                    Some(GLError::InvalidOperation),
                gl::INVALID_FRAMEBUFFER_OPERATION =>
                    Some(GLError::InvalidFramebufferOperation),
                gl::OUT_OF_MEMORY =>
                    Some(GLError::OutOfMemory),
                _ =>
                    None
            }
        }
    }
}

#[macro_export]
macro_rules! bind_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.array_buffer.bind($buffer)
    }
}

#[macro_export]
macro_rules! bind_element_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.element_array_buffer.bind($buffer)
    }
}

#[macro_export]
macro_rules! use_program {
    ($gl:expr, $program:expr) => {
        $gl.program.bind($program)
    }
}
<commit_msg>Add `active_texture!` macro<commit_after>use gl;
use gl::types::*;
use types::{Color, Viewport, BufferBits, GLError};
use buffer::{ArrayBufferBinder, ElementArrayBufferBinder};
use program::{ProgramBinder, ProgramAttrib};
use texture_units::{TextureUnits};

pub struct Context {
    pub array_buffer: ArrayBufferBinder,
    pub element_array_buffer: ElementArrayBufferBinder,
    pub program: ProgramBinder,
    pub tex_units: TextureUnits
}

impl Context {
    pub unsafe fn current_context() -> Self {
        Context {
            array_buffer: ArrayBufferBinder,
            element_array_buffer: ElementArrayBufferBinder,
            program: ProgramBinder,
            tex_units: TextureUnits::current()
        }
    }

    pub fn clear_color(&mut self, color: Color) {
        unsafe {
            gl::ClearColor(color.r, color.g, color.b, color.a);
        }
    }

    pub fn clear(&mut self, buffers: BufferBits) {
        unsafe {
            gl::Clear(buffers.bits());
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`mask` includes a bit other than an allowed value",
                _ => "Unkown error"
            }
        }
    }

    pub fn enable_vertex_attrib_array(&self, attrib: ProgramAttrib) {
        unsafe {
            gl::EnableVertexAttribArray(attrib.gl_index);
            dbg_gl_error! {
                GLError::InvalidValue => "`index` is >= GL_MAX_VERTEX_ATTRIBS",
                _ => "Unknown error"
            }
        }
    }

    pub fn viewport(&self, viewport: Viewport) {
        unsafe {
            gl::Viewport(viewport.x as GLint,
                         viewport.y as GLint,
                         viewport.width as GLsizei,
                         viewport.height as GLsizei);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`width` or `height` is negative",
                _ => "Unknown error"
            }
        }
    }

    pub fn get_error() -> Option<GLError> {
        unsafe {
            match gl::GetError() {
                gl::INVALID_ENUM =>
                    Some(GLError::InvalidEnum),
                gl::INVALID_VALUE =>
                    Some(GLError::InvalidValue),
                gl::INVALID_OPERATION =>
                    Some(GLError::InvalidOperation),
                gl::INVALID_FRAMEBUFFER_OPERATION =>
                    Some(GLError::InvalidFramebufferOperation),
                gl::OUT_OF_MEMORY =>
                    Some(GLError::OutOfMemory),
                _ =>
                    None
            }
        }
    }
}

#[macro_export]
macro_rules! bind_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.array_buffer.bind($buffer)
    }
}

#[macro_export]
macro_rules! bind_element_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.element_array_buffer.bind($buffer)
    }
}

#[macro_export]
macro_rules! use_program {
    ($gl:expr, $program:expr) => {
        $gl.program.bind($program)
    }
}

// HACK: Workaround for issue described here:
// https://www.reddit.com/r/rust/comments/339yj3/tuple_indexing_in_a_macro/cqiyv4n
#[macro_export]
macro_rules! _glitter_expr {
    ($x:expr) => ($x)
}

#[macro_export]
macro_rules! active_texture {
    ($gl:expr, $idx:tt) => {
        _glitter_expr!($gl.tex_units.$idx.active())
    }
}
<|endoftext|>


<commit_before>use std::convert::From;

use binding::string::{from_value, new};
use types::Value;

use super::traits::Object;

pub struct RString {
    value: Value
}

impl RString {
    pub fn new(string: &str) -> Self {
        RString {
            value: new(string)
        }
    }

    pub fn to_string(&self) -> String {
        from_value(self.value)
    }
}

impl From<Value> for RString {
    fn from(value: Value) -> Self {
        RString {
            value: value
        }
    }
}

impl Object for RString {
    fn value(&self) -> Value {
        self.value
    }
}
<commit_msg>Create documentation for String<commit_after>use std::convert::From;

use binding::string::{from_value, new};
use types::Value;

use super::traits::Object;

/// `String`
pub struct RString {
    value: Value
}

impl RString {
    /// Creates a new instance of Ruby `String` containing given `string`
    ///
    /// # Examples
    ///
    /// ```
    /// use ruru::{RString, VM};
    /// # VM::init();
    ///
    /// let string = RString::new("Hello, World!");
    ///
    /// assert_eq!(string.to_string(), "Hello, World!".to_string());
    /// ```
    pub fn new(string: &str) -> Self {
        RString {
            value: new(string)
        }
    }

    /// Retrieves underlying Rust `String` from Ruby `String` object
    ///
    /// # Examples
    ///
    /// ```
    /// use ruru::{RString, VM};
    /// # VM::init();
    ///
    /// let string = RString::new("Hello, World!");
    ///
    /// assert_eq!(string.to_string(), "Hello, World!".to_string());
    /// ```
    pub fn to_string(&self) -> String {
        from_value(self.value)
    }
}

impl From<Value> for RString {
    fn from(value: Value) -> Self {
        RString {
            value: value
        }
    }
}

impl Object for RString {
    fn value(&self) -> Value {
        self.value
    }
}
<|endoftext|>


<commit_before>use crate::Error;
use std::convert::Infallible;
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display};

#[cfg(backtrace)]
use std::backtrace::Backtrace;

/// Provides the `context` method for `Result`.
///
/// This trait is sealed and cannot be implemented for types outside of
/// `anyhow`.
///
/// # Example
///
/// ```
/// use anyhow::{Context, Result};
/// use std::fs;
/// use std::path::PathBuf;
///
/// pub struct ImportantThing {
///     path: PathBuf,
/// }
///
/// impl ImportantThing {
///     # const IGNORE: &'static str = stringify! {
///     pub fn detach(&mut self) -> Result<()> {...}
///     # };
///     # fn detach(&mut self) -> Result<()> {
///     #     unimplemented!()
///     # }
/// }
///
/// pub fn do_it(mut it: ImportantThing) -> Result<Vec<u8>> {
///     it.detach().context("failed to detach the important thing")?;
///
///     let path = &it.path;
///     let content = fs::read(path)
///         .with_context(|| format!("failed to read instrs from {}", path.display()))?;
///
///     Ok(content)
/// }
/// ```
///
/// When printed, the outermost context would be printed first and the lower
/// level underlying causes would be enumerated below.
///
/// ```console
/// Error: failed to read instrs from ./path/to/instrs.jsox
///
/// caused by:
///     No such file or directory (os error 2)
/// ```
pub trait Context<T, E>: private::Sealed {
    /// Wrap the error value with additional context.
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static;

    /// Wrap the error value with additional context that is evaluated lazily
    /// only once an error does occur.
    fn with_context<C, F>(self, f: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C;
}

impl<T, E> Context<T, E> for Result<T, E>
where
    E: StdError + Send + Sync + 'static,
{
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
    {
        self.map_err(|error| Error::new(ContextError { error, context }))
    }

    fn with_context<C, F>(self, context: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C,
    {
        self.map_err(|error| {
            Error::new(ContextError {
                error,
                context: context(),
            })
        })
    }
}

impl<T> Context<T, Error> for Result<T, Error> {
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
    {
        self.map_err(|error| error.context(context))
    }

    fn with_context<C, F>(self, context: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C,
    {
        self.map_err(|error| error.context(context()))
    }
}

/// ```
/// # type T = ();
/// #
/// use anyhow::{Context, Result};
///
/// fn maybe_get() -> Option<T> {
///     # const IGNORE: &str = stringify! {
///     ...
///     # };
///     # unimplemented!()
/// }
///
/// fn demo() -> Result<()> {
///     let t = maybe_get().context("there is no T")?;
///     # const IGNORE: &str = stringify! {
///     ...
///     # };
///     # unimplemented!()
/// }
/// ```
impl<T> Context<T, Infallible> for Option<T> {
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
    {
        self.ok_or_else(|| Error::from_display(context, backtrace!()))
    }

    fn with_context<C, F>(self, context: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C,
    {
        self.ok_or_else(|| Error::from_display(context(), backtrace!()))
    }
}

pub(crate) struct ContextError<E, C> {
    pub error: E,
    pub context: C,
}

impl<E, C> Debug for ContextError<E, C>
where
    E: Debug,
    C: Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}\n\n{}", self.error, self.context)
    }
}

impl<E, C> Display for ContextError<E, C>
where
    C: Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&self.context, f)
    }
}

impl<E, C> StdError for ContextError<E, C>
where
    E: StdError + 'static,
    C: Display,
{
    #[cfg(backtrace)]
    fn backtrace(&self) -> Option<&Backtrace> {
        self.error.backtrace()
    }

    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        Some(&self.error)
    }
}

impl<C> StdError for ContextError<Error, C>
where
    C: Display,
{
    #[cfg(backtrace)]
    fn backtrace(&self) -> Option<&Backtrace> {
        Some(self.error.backtrace())
    }

    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        Some(&*self.error)
    }
}

mod private {
    use crate::Error;
    use std::error::Error as StdError;

    pub trait Sealed {}

    impl<T, E> Sealed for Result<T, E> where E: StdError + Send + Sync + 'static {}
    impl<T> Sealed for Result<T, Error> {}
    impl<T> Sealed for Option<T> {}
}
<commit_msg>Consolidate to one Context impl for Result to improve inference<commit_after>use crate::Error;
use std::convert::Infallible;
use std::error::Error as StdError;
use std::fmt::{self, Debug, Display};

#[cfg(backtrace)]
use std::backtrace::Backtrace;

/// Provides the `context` method for `Result`.
///
/// This trait is sealed and cannot be implemented for types outside of
/// `anyhow`.
///
/// # Example
///
/// ```
/// use anyhow::{Context, Result};
/// use std::fs;
/// use std::path::PathBuf;
///
/// pub struct ImportantThing {
///     path: PathBuf,
/// }
///
/// impl ImportantThing {
///     # const IGNORE: &'static str = stringify! {
///     pub fn detach(&mut self) -> Result<()> {...}
///     # };
///     # fn detach(&mut self) -> Result<()> {
///     #     unimplemented!()
///     # }
/// }
///
/// pub fn do_it(mut it: ImportantThing) -> Result<Vec<u8>> {
///     it.detach().context("failed to detach the important thing")?;
///
///     let path = &it.path;
///     let content = fs::read(path)
///         .with_context(|| format!("failed to read instrs from {}", path.display()))?;
///
///     Ok(content)
/// }
/// ```
///
/// When printed, the outermost context would be printed first and the lower
/// level underlying causes would be enumerated below.
///
/// ```console
/// Error: failed to read instrs from ./path/to/instrs.jsox
///
/// caused by:
///     No such file or directory (os error 2)
/// ```
pub trait Context<T, E>: private::Sealed {
    /// Wrap the error value with additional context.
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static;

    /// Wrap the error value with additional context that is evaluated lazily
    /// only once an error does occur.
    fn with_context<C, F>(self, f: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C;
}

mod ext {
    use super::*;

    pub trait StdError {
        fn ext_context<C>(self, context: C) -> Error
        where
            C: Display + Send + Sync + 'static;
    }

    impl<E> StdError for E
    where
        E: std::error::Error + Send + Sync + 'static,
    {
        fn ext_context<C>(self, context: C) -> Error
        where
            C: Display + Send + Sync + 'static,
        {
            Error::new(ContextError {
                error: self,
                context,
            })
        }
    }

    impl StdError for Error {
        fn ext_context<C>(self, context: C) -> Error
        where
            C: Display + Send + Sync + 'static,
        {
            self.context(context)
        }
    }
}

impl<T, E> Context<T, E> for Result<T, E>
where
    E: ext::StdError + Send + Sync + 'static,
{
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
    {
        self.map_err(|error| error.ext_context(context))
    }

    fn with_context<C, F>(self, context: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C,
    {
        self.map_err(|error| error.ext_context(context()))
    }
}

/// ```
/// # type T = ();
/// #
/// use anyhow::{Context, Result};
///
/// fn maybe_get() -> Option<T> {
///     # const IGNORE: &str = stringify! {
///     ...
///     # };
///     # unimplemented!()
/// }
///
/// fn demo() -> Result<()> {
///     let t = maybe_get().context("there is no T")?;
///     # const IGNORE: &str = stringify! {
///     ...
///     # };
///     # unimplemented!()
/// }
/// ```
impl<T> Context<T, Infallible> for Option<T> {
    fn context<C>(self, context: C) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
    {
        self.ok_or_else(|| Error::from_display(context, backtrace!()))
    }

    fn with_context<C, F>(self, context: F) -> Result<T, Error>
    where
        C: Display + Send + Sync + 'static,
        F: FnOnce() -> C,
    {
        self.ok_or_else(|| Error::from_display(context(), backtrace!()))
    }
}

pub(crate) struct ContextError<E, C> {
    pub error: E,
    pub context: C,
}

impl<E, C> Debug for ContextError<E, C>
where
    E: Debug,
    C: Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}\n\n{}", self.error, self.context)
    }
}

impl<E, C> Display for ContextError<E, C>
where
    C: Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Display::fmt(&self.context, f)
    }
}

impl<E, C> StdError for ContextError<E, C>
where
    E: StdError + 'static,
    C: Display,
{
    #[cfg(backtrace)]
    fn backtrace(&self) -> Option<&Backtrace> {
        self.error.backtrace()
    }

    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        Some(&self.error)
    }
}

impl<C> StdError for ContextError<Error, C>
where
    C: Display,
{
    #[cfg(backtrace)]
    fn backtrace(&self) -> Option<&Backtrace> {
        Some(self.error.backtrace())
    }

    fn source(&self) -> Option<&(dyn StdError + 'static)> {
        Some(&*self.error)
    }
}

mod private {
    use super::*;

    pub trait Sealed {}

    impl<T, E> Sealed for Result<T, E> where E: ext::StdError {}
    impl<T> Sealed for Option<T> {}
}
<|endoftext|>


<commit_before>use ndarray::*;

use super::error::*;
use super::layout::*;

pub fn into_col<S>(a: ArrayBase<S, Ix1>) -> ArrayBase<S, Ix2>
where
    S: Data,
{
    let n = a.len();
    a.into_shape((n, 1)).unwrap()
}

pub fn into_row<S>(a: ArrayBase<S, Ix1>) -> ArrayBase<S, Ix2>
where
    S: Data,
{
    let n = a.len();
    a.into_shape((1, n)).unwrap()
}

pub fn flatten<S>(a: ArrayBase<S, Ix2>) -> ArrayBase<S, Ix1>
where
    S: Data,
{
    let n = a.len();
    a.into_shape((n)).unwrap()
}

pub fn into_matrix<A, S>(l: MatrixLayout, a: Vec<A>) -> Result<ArrayBase<S, Ix2>>
where
    S: DataOwned<Elem = A>,
{
    Ok(ArrayBase::from_shape_vec(l.as_shape(), a)?)
}

fn uninitialized<A, S>(l: MatrixLayout) -> ArrayBase<S, Ix2>
where
    A: Copy,
    S: DataOwned<Elem = A>,
{
    unsafe { ArrayBase::uninitialized(l.as_shape()) }
}

pub fn replicate<A, Sv, So, D>(a: &ArrayBase<Sv, D>) -> ArrayBase<So, D>
where
    A: Copy,
    Sv: Data<Elem = A>,
    So: DataOwned<Elem = A> + DataMut,
    D: Dimension,
{
    let mut b = unsafe { ArrayBase::uninitialized(a.dim()) };
    b.assign(a);
    b
}

fn clone_with_layout<A, Si, So>(l: MatrixLayout, a: &ArrayBase<Si, Ix2>) -> ArrayBase<So, Ix2>
where
    A: Copy,
    Si: Data<Elem = A>,
    So: DataOwned<Elem = A> + DataMut,
{
    let mut b = uninitialized(l);
    b.assign(a);
    b
}

pub fn transpose_data<A, S>(a: &mut ArrayBase<S, Ix2>) -> Result<&mut ArrayBase<S, Ix2>>
where
    A: Copy,
    S: DataOwned<Elem = A> + DataMut,
{
    let l = a.layout()?.toggle_order();
    let new = clone_with_layout(l, a);
    ::std::mem::replace(a, new);
    Ok(a)
}

pub fn generalize<A, S, D>(a: Array<A, D>) -> ArrayBase<S, D>
where
    S: DataOwned<Elem = A>,
    D: Dimension,
{
    if a.is_standard_layout() {
        ArrayBase::from_shape_vec(a.dim(), a.into_raw_vec()).unwrap()
    } else {
        ArrayBase::from_shape_vec(a.dim().f(), a.into_raw_vec()).unwrap()
    }
}
<commit_msg>Add error check and link<commit_after>use ndarray::*;

use super::error::*;
use super::layout::*;

pub fn into_col<S>(a: ArrayBase<S, Ix1>) -> ArrayBase<S, Ix2>
where
    S: Data,
{
    let n = a.len();
    a.into_shape((n, 1)).unwrap()
}

pub fn into_row<S>(a: ArrayBase<S, Ix1>) -> ArrayBase<S, Ix2>
where
    S: Data,
{
    let n = a.len();
    a.into_shape((1, n)).unwrap()
}

pub fn flatten<S>(a: ArrayBase<S, Ix2>) -> ArrayBase<S, Ix1>
where
    S: Data,
{
    let n = a.len();
    a.into_shape((n)).unwrap()
}

pub fn into_matrix<A, S>(l: MatrixLayout, a: Vec<A>) -> Result<ArrayBase<S, Ix2>>
where
    S: DataOwned<Elem = A>,
{
    Ok(ArrayBase::from_shape_vec(l.as_shape(), a)?)
}

fn uninitialized<A, S>(l: MatrixLayout) -> ArrayBase<S, Ix2>
where
    A: Copy,
    S: DataOwned<Elem = A>,
{
    unsafe { ArrayBase::uninitialized(l.as_shape()) }
}

pub fn replicate<A, Sv, So, D>(a: &ArrayBase<Sv, D>) -> ArrayBase<So, D>
where
    A: Copy,
    Sv: Data<Elem = A>,
    So: DataOwned<Elem = A> + DataMut,
    D: Dimension,
{
    let mut b = unsafe { ArrayBase::uninitialized(a.dim()) };
    b.assign(a);
    b
}

fn clone_with_layout<A, Si, So>(l: MatrixLayout, a: &ArrayBase<Si, Ix2>) -> ArrayBase<So, Ix2>
where
    A: Copy,
    Si: Data<Elem = A>,
    So: DataOwned<Elem = A> + DataMut,
{
    let mut b = uninitialized(l);
    b.assign(a);
    b
}

pub fn transpose_data<A, S>(a: &mut ArrayBase<S, Ix2>) -> Result<&mut ArrayBase<S, Ix2>>
where
    A: Copy,
    S: DataOwned<Elem = A> + DataMut,
{
    let l = a.layout()?.toggle_order();
    let new = clone_with_layout(l, a);
    ::std::mem::replace(a, new);
    Ok(a)
}

pub fn generalize<A, S, D>(a: Array<A, D>) -> ArrayBase<S, D>
where
    S: DataOwned<Elem = A>,
    D: Dimension,
{
    // FIXME
    // https://github.com/bluss/rust-ndarray/issues/325
    let strides: Vec<isize> = a.strides().to_vec();
    let new = if a.is_standard_layout() {
        ArrayBase::from_shape_vec(a.dim(), a.into_raw_vec()).unwrap()
    } else {
        ArrayBase::from_shape_vec(a.dim().f(), a.into_raw_vec()).unwrap()
    };
    assert_eq!(
        new.strides(),
        strides.as_slice(),
        "Custom stride is not supported"
    );
    new
}
<|endoftext|>


<commit_before>use crate::discord_client::CommandHandler;
use rusqlite::Connection;
use rusqlite::NO_PARAMS;

trait TagRepository {
    fn create_tag(&self, tag_name: &str, tag_body: &str) -> Result<(), Box<std::error::Error>>;
    fn read_tag(&self, tag_name: &str) -> Result<String, Box<std::error::Error>>;
    fn update_tag(&self, tag_name: &str, tag_body: &str) -> Result<(), Box<std::error::Error>>;
    fn delete_tag(&self, tag_name: &str) -> Result<(), Box<std::error::Error>>;
}

pub struct TagCommand {
    tag_repository: Box<TagRepository>,
}
pub struct SqliteTagRepository {
    db_connection: Connection,
}

struct Tag {
    name: String,
    body: String,
}

fn parse_ntag(command: &str) -> Option<Tag> {
    let mut result: Option<Tag> = None;

    let mut broken_down_command = command.split_whitespace().skip(1);
    let name = broken_down_command.next();
    let body: Vec<&str> = broken_down_command.collect();
    let body: String = body.join(" ");
    let body: Option<String> = if body.is_empty() { None } else { Some(body) };

    if let Some(name) = name {
        if let Some(body) = body {
            result = Some(Tag {
                name: String::from(name),
                body,
            });
        }
    }

    result
}

impl TagCommand {
    fn new() -> Result<TagCommand, Box<std::error::Error>> {
        let tag_repository = Box::new(SqliteTagRepository::new()?);

        Ok(TagCommand { tag_repository })
    }
}

impl CommandHandler for TagCommand {
    fn process_command(
        &self,
        command: &str,
        send_message_callback: &Fn(&str) -> (),
    ) -> Result<(), Box<std::error::Error>> {
        if command.starts_with("ntag") {
            match parse_ntag(command) {
                Some(new_tag) => {
                    self.tag_repository.create_tag(&new_tag.name, &new_tag.body)?;
                    send_message_callback(&format!(
                        "Created new tag {} with body {}",
                        &new_tag.name, &new_tag.body
                    ));
                }
                None => send_message_callback("Syntax error, could not create tag"),
            }
        } else if command.starts_with("atags") {

        } else {

        }

        Ok(())
    }
}

impl SqliteTagRepository {
    fn new() -> Result<SqliteTagRepository, Box<std::error::Error>> {
        let db_connection = Connection::open("tags.db")?;

        db_connection.execute(
            "CREATE TABLE IF NOT EXISTS tags (
            id INTEGER PRIMARY KEY,
            name TEXT NOT NULL UNIQUE,
            body TEXT NOT NULL
        )",
            NO_PARAMS,
        )?;

        Ok(SqliteTagRepository { db_connection })
    }
}

impl TagRepository for SqliteTagRepository {
    fn create_tag(&self, tag_name: &str, tag_body: &str) -> Result<(), Box<std::error::Error>> {
        self.db_connection.execute(
            "INSERT INTO tags
            (name, body) VALUES (?1, ?1)",
            &[tag_name, tag_body],
        )?;
        Ok(())
    }

    fn read_tag(&self, tag_name: &str) -> Result<String, Box<std::error::Error>> {
        Ok(self
            .db_connection
            .prepare(
                "SELECT body
                FROM tags
                WHERE name = (?1)",
            )?
            .query_row(&[tag_name], |row| Ok(row.get(0)?))?)
    }

    fn update_tag(&self, tag_name: &str, tag_body: &str) -> Result<(), Box<std::error::Error>> {
        self.db_connection.execute(
            "UPDATE tags
                SET body = (?2)
                WHERE name = (?1)",
            &[tag_name, tag_body],
        )?;

        Ok(())
    }

    fn delete_tag(&self, tag_name: &str) -> Result<(), Box<std::error::Error>> {
        self.db_connection.execute(
            "DELETE FROM tags
                WHERE name = (?1)",
            &[tag_name],
        )?;

        Ok(())
    }
}

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

    #[test]
    fn test_parse_ntag() {
        let result = parse_ntag("ntag tag_name tag_body").unwrap();
        assert_eq!("tag_name", result.name);
        assert_eq!("tag_body", result.body);

        let result =
            parse_ntag("ntag tag_name long tag body with whitespace and 日本語").unwrap();
        assert_eq!("tag_name", result.name);
        assert_eq!("long tag body with whitespace and 日本語", result.body);
    }
}
<commit_msg>run cargo fmt<commit_after>use crate::discord_client::CommandHandler;
use rusqlite::Connection;
use rusqlite::NO_PARAMS;

trait TagRepository {
    fn create_tag(&self, tag_name: &str, tag_body: &str) -> Result<(), Box<std::error::Error>>;
    fn read_tag(&self, tag_name: &str) -> Result<String, Box<std::error::Error>>;
    fn update_tag(&self, tag_name: &str, tag_body: &str) -> Result<(), Box<std::error::Error>>;
    fn delete_tag(&self, tag_name: &str) -> Result<(), Box<std::error::Error>>;
}

pub struct TagCommand {
    tag_repository: Box<TagRepository>,
}
pub struct SqliteTagRepository {
    db_connection: Connection,
}

struct Tag {
    name: String,
    body: String,
}

fn parse_ntag(command: &str) -> Option<Tag> {
    let mut result: Option<Tag> = None;

    let mut broken_down_command = command.split_whitespace().skip(1);
    let name = broken_down_command.next();
    let body: Vec<&str> = broken_down_command.collect();
    let body: String = body.join(" ");
    let body: Option<String> = if body.is_empty() { None } else { Some(body) };

    if let Some(name) = name {
        if let Some(body) = body {
            result = Some(Tag {
                name: String::from(name),
                body,
            });
        }
    }

    result
}

impl TagCommand {
    fn new() -> Result<TagCommand, Box<std::error::Error>> {
        let tag_repository = Box::new(SqliteTagRepository::new()?);

        Ok(TagCommand { tag_repository })
    }
}

impl CommandHandler for TagCommand {
    fn process_command(
        &self,
        command: &str,
        send_message_callback: &Fn(&str) -> (),
    ) -> Result<(), Box<std::error::Error>> {
        if command.starts_with("ntag") {
            match parse_ntag(command) {
                Some(new_tag) => {
                    self.tag_repository
                        .create_tag(&new_tag.name, &new_tag.body)?;
                    send_message_callback(&format!(
                        "Created new tag {} with body {}",
                        &new_tag.name, &new_tag.body
                    ));
                }
                None => send_message_callback("Syntax error, could not create tag"),
            }
        } else if command.starts_with("atags") {

        } else {

        }

        Ok(())
    }
}

impl SqliteTagRepository {
    fn new() -> Result<SqliteTagRepository, Box<std::error::Error>> {
        let db_connection = Connection::open("tags.db")?;

        db_connection.execute(
            "CREATE TABLE IF NOT EXISTS tags (
            id INTEGER PRIMARY KEY,
            name TEXT NOT NULL UNIQUE,
            body TEXT NOT NULL
        )",
            NO_PARAMS,
        )?;

        Ok(SqliteTagRepository { db_connection })
    }
}

impl TagRepository for SqliteTagRepository {
    fn create_tag(&self, tag_name: &str, tag_body: &str) -> Result<(), Box<std::error::Error>> {
        self.db_connection.execute(
            "INSERT INTO tags
            (name, body) VALUES (?1, ?1)",
            &[tag_name, tag_body],
        )?;
        Ok(())
    }

    fn read_tag(&self, tag_name: &str) -> Result<String, Box<std::error::Error>> {
        Ok(self
            .db_connection
            .prepare(
                "SELECT body
                FROM tags
                WHERE name = (?1)",
            )?
            .query_row(&[tag_name], |row| Ok(row.get(0)?))?)
    }

    fn update_tag(&self, tag_name: &str, tag_body: &str) -> Result<(), Box<std::error::Error>> {
        self.db_connection.execute(
            "UPDATE tags
                SET body = (?2)
                WHERE name = (?1)",
            &[tag_name, tag_body],
        )?;

        Ok(())
    }

    fn delete_tag(&self, tag_name: &str) -> Result<(), Box<std::error::Error>> {
        self.db_connection.execute(
            "DELETE FROM tags
                WHERE name = (?1)",
            &[tag_name],
        )?;

        Ok(())
    }
}

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

    #[test]
    fn test_parse_ntag() {
        let result = parse_ntag("ntag tag_name tag_body").unwrap();
        assert_eq!("tag_name", result.name);
        assert_eq!("tag_body", result.body);

        let result =
            parse_ntag("ntag tag_name long tag body with whitespace and 日本語").unwrap();
        assert_eq!("tag_name", result.name);
        assert_eq!("long tag body with whitespace and 日本語", result.body);
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

#[cfg(target_os = "linux")]
extern crate i2cdev;
extern crate termion;

#[cfg(target_os = "linux")]
use self::i2cdev::core::I2CDevice;
#[cfg(target_os = "linux")]
use self::i2cdev::linux::LinuxI2CDevice;

use std;
use shared::*;

const MODE_REGISTER: u8 = 0x00;
const FRAME_REGISTER: u8 = 0x01;
const AUTOPLAY1_REGISTER: u8 = 0x02;
const AUTOPLAY2_REGISTER: u8 = 0x03;
const BLINK_REGISTER: u8 = 0x05;
const AUDIOSYNC_REGISTER: u8 = 0x06;
const BREATH1_REGISTER: u8 = 0x08;
const BREATH2_REGISTER: u8 = 0x09;
const SHUTDOWN_REGISTER: u8 = 0x0A;
const GAIN_REGISTER: u8 = 0x0B;
const ADC_REGISTER: u8 = 0x0C;

const CONFIG_BANK: u8 = 0x0B;
const BANK_ADDRESS: u8 = 0xFD;

const PICTURE_MODE: u8 = 0x00;
const AUTOPLAY_MODE: u8 = 0x08;
const AUDIOPLAY_MODE: u8 = 0x18;

const ENABLE_OFFSET: u8 = 0x00;
const BLINK_OFFSET: u8 = 0x12;
const COLOR_OFFSET: u8 = 0x24;

const ADDRESS: u16 = 0x74;

/// Represents a device capable of displaying a rectangular bitmap buffer.
pub trait Display {
    fn show(&mut self, buffer: &[Column]);
}

#[cfg(target_os = "linux")]
/// A Scroll pHAT HD device connected over I2C bus (e.g. on a Raspberry Pi).
pub struct I2CDisplay {
    device: LinuxI2CDevice,
    frame: u8,
}

#[cfg(target_os = "linux")]
impl I2CDisplay {
    /// Creates a new I2CDisplay device using the I2C device identified by the provided
    /// `device_id` (normally 1 or 2).
    pub fn new(device_id: u8) -> I2CDisplay {
        let device_path = format!("/dev/i2c-{}", device_id);
        let d = LinuxI2CDevice::new(device_path, ADDRESS).unwrap();
        let mut display = I2CDisplay {
            device: d,
            frame: 0,
        };

        // Display initialization
        display.reset();

        display.device.smbus_write_byte_data(BANK_ADDRESS, CONFIG_BANK);
        // Switch to Picture Mode
        display.device.smbus_write_byte_data(MODE_REGISTER, PICTURE_MODE);
        // Disable audio sync
        display.device.smbus_write_byte_data(AUDIOSYNC_REGISTER, 0);

        // Initialize frame 1
        display.device.smbus_write_byte_data(BANK_ADDRESS, 1);
        // Turn off blinking for all LEDs
        for i in 0..17 {
            display.device.smbus_write_byte_data(BLINK_OFFSET + i, 0);
        }
        // Set the PWM duty cycle for all LEDs to 0%
        for i in 0..17 {
            for j in 0..7 {
                display.device.smbus_write_byte_data(COLOR_OFFSET + (i * 8) + j, 0);
            }
        }
        // Turn all LEDs "on"
        for i in 0..17 {
            display.device.smbus_write_byte_data(ENABLE_OFFSET + i, 127);
        }

        // Initialize frame 0
        display.device.smbus_write_byte_data(BANK_ADDRESS, 0);
        // Turn off blinking for all LEDs
        for i in 0..17 {
            display.device.smbus_write_byte_data(BLINK_OFFSET + i, 0);
        }
        // Set the PWM duty cycle for all LEDs to 0%
        for i in 0..17 {
            for j in 0..7 {
                display.device.smbus_write_byte_data(COLOR_OFFSET + (i * 8) + j, 0);
            }
        }
        // Turn all LEDs "on"
        for i in 0..17 {
            display.device.smbus_write_byte_data(ENABLE_OFFSET + i, 127);
        }

        display
    }

    fn bank(&mut self, bank: u8) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.device.smbus_write_byte_data(BANK_ADDRESS, bank)
    }

    fn register(
        &mut self,
        bank: u8,
        register: u8,
        value: u8,
    ) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.bank(bank);
        self.device.smbus_write_byte_data(register, value)
    }

    fn frame(&mut self, frame: u8) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.register(CONFIG_BANK, FRAME_REGISTER, frame)
    }

    fn reset(&mut self) {
        self.sleep(true);
        std::thread::sleep(std::time::Duration::from_millis(10));
        self.sleep(false);
    }

    fn sleep(&mut self, value: bool) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.register(CONFIG_BANK, SHUTDOWN_REGISTER, if value { 0 } else { 1 })
    }
}

#[cfg(target_os = "linux")]
impl Display for I2CDisplay {
    fn show(&mut self, buffer: &[Column]) {
        // TODO(tzn): Double buffering.
        // let new_frame = (self.frame + 1) % 2;
        let new_frame = 1;
        self.bank(new_frame);
        for y in 0..DISPLAY_HEIGHT {
            for x in 0..DISPLAY_WIDTH {
                let offset = if x >= 8 {
                    (x - 8) * 16 + y
                } else {
                    (8 - x) * 16 - (y + 2)
                };
                let value = match buffer.get(x as usize) {
                    Some(column) => column[y as usize],
                    None => 0,
                };
                self.device
                    .smbus_write_byte_data(COLOR_OFFSET + offset as u8, value);
            }
        }
        self.frame(new_frame);
        self.frame = new_frame;
    }
}

/// A virtual display that outputs its buffer to the terminal from which the binary is attached.
///
/// Useful for debugging or prototyping, as it does not require a physical display to be connected.
pub struct TermDisplay {}

impl TermDisplay {
    pub fn new() -> TermDisplay {
        TermDisplay {}
    }
}

impl Display for TermDisplay {
    fn show(&mut self, buffer: &[Column]) {
        print!("{}", termion::clear::All);
        for x in 0..buffer.len() {
            let col = &buffer[x];
            for y in 0..col.len() {
                let c = col[y];
                let v = if c == 0 { ' ' } else { '#' };
                println!("{}{}", termion::cursor::Goto(x as u16 + 1, y as u16 + 1), v);
            }
        }
    }
}

/// A virtual display that outputs its buffer to the terminal from which the binary is attached.
///
/// Useful for debugging or prototyping, as it does not require a physical display to be connected.
pub struct UnicodeDisplay {}

impl UnicodeDisplay {
    pub fn new() -> UnicodeDisplay {
        UnicodeDisplay {}
    }
}

impl Display for UnicodeDisplay {
    fn show(&mut self, buffer: &[Column]) {
        print!("{}", termion::clear::All);

        let col = &buffer[0];

        println!("{}╔", termion::cursor::Goto(1, 1));
        for y in 0..col.len() {
            println!("{}║", termion::cursor::Goto(1, y as u16 + 2));
        }
        println!("{}╚", termion::cursor::Goto(1, col.len() as u16 + 2));

        for x in 0..buffer.len() {
            let col = &buffer[x];
            println!("{}═", termion::cursor::Goto(x as u16 + 2, 1));
            for y in 0..col.len() {
                let c = col[y];
                let v = if c == 0 { '░' } else { '▓' };
                println!("{}{}", termion::cursor::Goto(x as u16 + 2, y as u16 + 2), v);
            }
            println!(
                "{}═",
                termion::cursor::Goto(x as u16 + 2, col.len() as u16 + 2)
            );
        }

        println!("{}╗", termion::cursor::Goto(buffer.len() as u16 + 1, 1));
        for y in 0..col.len() {
            println!(
                "{}║",
                termion::cursor::Goto(buffer.len() as u16 + 1, y as u16 + 2)
            );
        }
        println!(
            "{}╝",
            termion::cursor::Goto(buffer.len() as u16 + 1, col.len() as u16 + 2)
        );
    }
}
<commit_msg>Enable double-buffered rendering to the display<commit_after>#![allow(dead_code)]

#[cfg(target_os = "linux")]
extern crate i2cdev;
extern crate termion;

#[cfg(target_os = "linux")]
use self::i2cdev::core::I2CDevice;
#[cfg(target_os = "linux")]
use self::i2cdev::linux::LinuxI2CDevice;

use std;
use shared::*;

const MODE_REGISTER: u8 = 0x00;
const FRAME_REGISTER: u8 = 0x01;
const AUTOPLAY1_REGISTER: u8 = 0x02;
const AUTOPLAY2_REGISTER: u8 = 0x03;
const BLINK_REGISTER: u8 = 0x05;
const AUDIOSYNC_REGISTER: u8 = 0x06;
const BREATH1_REGISTER: u8 = 0x08;
const BREATH2_REGISTER: u8 = 0x09;
const SHUTDOWN_REGISTER: u8 = 0x0A;
const GAIN_REGISTER: u8 = 0x0B;
const ADC_REGISTER: u8 = 0x0C;

const CONFIG_BANK: u8 = 0x0B;
const BANK_ADDRESS: u8 = 0xFD;

const PICTURE_MODE: u8 = 0x00;
const AUTOPLAY_MODE: u8 = 0x08;
const AUDIOPLAY_MODE: u8 = 0x18;

const ENABLE_OFFSET: u8 = 0x00;
const BLINK_OFFSET: u8 = 0x12;
const COLOR_OFFSET: u8 = 0x24;

const ADDRESS: u16 = 0x74;

/// Represents a device capable of displaying a rectangular bitmap buffer.
pub trait Display {
    fn show(&mut self, buffer: &[Column]);
}

#[cfg(target_os = "linux")]
/// A Scroll pHAT HD device connected over I2C bus (e.g. on a Raspberry Pi).
pub struct I2CDisplay {
    device: LinuxI2CDevice,
    frame: u8,
}

#[cfg(target_os = "linux")]
impl I2CDisplay {
    /// Creates a new I2CDisplay device using the I2C device identified by the provided
    /// `device_id` (normally 1 or 2).
    pub fn new(device_id: u8) -> I2CDisplay {
        let device_path = format!("/dev/i2c-{}", device_id);
        let d = LinuxI2CDevice::new(device_path, ADDRESS).unwrap();
        let mut display = I2CDisplay {
            device: d,
            frame: 0,
        };

        // Display initialization
        display.reset();

        display.device.smbus_write_byte_data(BANK_ADDRESS, CONFIG_BANK);
        // Switch to Picture Mode
        display.device.smbus_write_byte_data(MODE_REGISTER, PICTURE_MODE);
        // Disable audio sync
        display.device.smbus_write_byte_data(AUDIOSYNC_REGISTER, 0);

        // Initialize frame 1
        display.device.smbus_write_byte_data(BANK_ADDRESS, 1);
        // Turn off blinking for all LEDs
        for i in 0..17 {
            display.device.smbus_write_byte_data(BLINK_OFFSET + i, 0);
        }
        // Set the PWM duty cycle for all LEDs to 0%
        for i in 0..17 {
            for j in 0..7 {
                display.device.smbus_write_byte_data(COLOR_OFFSET + (i * 8) + j, 0);
            }
        }
        // Turn all LEDs "on"
        for i in 0..17 {
            display.device.smbus_write_byte_data(ENABLE_OFFSET + i, 127);
        }

        // Initialize frame 0
        display.device.smbus_write_byte_data(BANK_ADDRESS, 0);
        // Turn off blinking for all LEDs
        for i in 0..17 {
            display.device.smbus_write_byte_data(BLINK_OFFSET + i, 0);
        }
        // Set the PWM duty cycle for all LEDs to 0%
        for i in 0..17 {
            for j in 0..7 {
                display.device.smbus_write_byte_data(COLOR_OFFSET + (i * 8) + j, 0);
            }
        }
        // Turn all LEDs "on"
        for i in 0..17 {
            display.device.smbus_write_byte_data(ENABLE_OFFSET + i, 127);
        }

        display
    }

    fn bank(&mut self, bank: u8) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.device.smbus_write_byte_data(BANK_ADDRESS, bank)
    }

    fn register(
        &mut self,
        bank: u8,
        register: u8,
        value: u8,
    ) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.bank(bank);
        self.device.smbus_write_byte_data(register, value)
    }

    fn frame(&mut self, frame: u8) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.register(CONFIG_BANK, FRAME_REGISTER, frame)
    }

    fn reset(&mut self) {
        self.sleep(true);
        std::thread::sleep(std::time::Duration::from_millis(10));
        self.sleep(false);
    }

    fn sleep(&mut self, value: bool) -> Result<(), i2cdev::linux::LinuxI2CError> {
        self.register(CONFIG_BANK, SHUTDOWN_REGISTER, if value { 0 } else { 1 })
    }
}

#[cfg(target_os = "linux")]
impl Display for I2CDisplay {
    fn show(&mut self, buffer: &[Column]) {
        let new_frame = (self.frame + 1) % 2;
        self.bank(new_frame);
        for y in 0..DISPLAY_HEIGHT {
            for x in 0..DISPLAY_WIDTH {
                let offset = if x >= 8 {
                    (x - 8) * 16 + y
                } else {
                    (8 - x) * 16 - (y + 2)
                };
                let value = match buffer.get(x as usize) {
                    Some(column) => column[y as usize],
                    None => 0,
                };
                self.device
                    .smbus_write_byte_data(COLOR_OFFSET + offset as u8, value);
            }
        }
        self.frame(new_frame);
        self.frame = new_frame;
    }
}

/// A virtual display that outputs its buffer to the terminal from which the binary is attached.
///
/// Useful for debugging or prototyping, as it does not require a physical display to be connected.
pub struct TermDisplay {}

impl TermDisplay {
    pub fn new() -> TermDisplay {
        TermDisplay {}
    }
}

impl Display for TermDisplay {
    fn show(&mut self, buffer: &[Column]) {
        print!("{}", termion::clear::All);
        for x in 0..buffer.len() {
            let col = &buffer[x];
            for y in 0..col.len() {
                let c = col[y];
                let v = if c == 0 { ' ' } else { '#' };
                println!("{}{}", termion::cursor::Goto(x as u16 + 1, y as u16 + 1), v);
            }
        }
    }
}

/// A virtual display that outputs its buffer to the terminal from which the binary is attached.
///
/// Useful for debugging or prototyping, as it does not require a physical display to be connected.
pub struct UnicodeDisplay {}

impl UnicodeDisplay {
    pub fn new() -> UnicodeDisplay {
        UnicodeDisplay {}
    }
}

impl Display for UnicodeDisplay {
    fn show(&mut self, buffer: &[Column]) {
        print!("{}", termion::clear::All);

        let col = &buffer[0];

        println!("{}╔", termion::cursor::Goto(1, 1));
        for y in 0..col.len() {
            println!("{}║", termion::cursor::Goto(1, y as u16 + 2));
        }
        println!("{}╚", termion::cursor::Goto(1, col.len() as u16 + 2));

        for x in 0..buffer.len() {
            let col = &buffer[x];
            println!("{}═", termion::cursor::Goto(x as u16 + 2, 1));
            for y in 0..col.len() {
                let c = col[y];
                let v = if c == 0 { '░' } else { '▓' };
                println!("{}{}", termion::cursor::Goto(x as u16 + 2, y as u16 + 2), v);
            }
            println!(
                "{}═",
                termion::cursor::Goto(x as u16 + 2, col.len() as u16 + 2)
            );
        }

        println!("{}╗", termion::cursor::Goto(buffer.len() as u16 + 1, 1));
        for y in 0..col.len() {
            println!(
                "{}║",
                termion::cursor::Goto(buffer.len() as u16 + 1, y as u16 + 2)
            );
        }
        println!(
            "{}╝",
            termion::cursor::Goto(buffer.len() as u16 + 1, col.len() as u16 + 2)
        );
    }
}
<|endoftext|>