<commit_before>extern crate clap;
#[macro_use]
extern crate error_chain;
extern crate serde_json;
extern crate varlink;
extern crate varlink_parser;

use clap::{App, Arg, SubCommand};
use errors::*;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path::Path;
use std::str;
use varlink::{Connection, GetInterfaceDescriptionReply, MethodCall, OrgVarlinkServiceClient,
              OrgVarlinkServiceInterface};
use varlink_parser::Varlink;

mod errors {
    error_chain! {
        foreign_links {
            Io(::std::io::Error);
            Fmt(::std::fmt::Error);
            SerdeJson(::serde_json::Error);
            Clap(::clap::Error);
        }
        links {
            Varlink(::varlink::Error, ::varlink::ErrorKind);
            VarlinkParse(::varlink_parser::Error, ::varlink_parser::ErrorKind);
        }
        errors {
            NotImplemented(t: String) {
                display("Not yet implemented: '{}'", t)
            }
        }
    }
}

fn varlink_format(filename: &str) -> Result<()> {
    let mut buffer = String::new();
    File::open(Path::new(filename))?.read_to_string(&mut buffer)?;

    let v = Varlink::from_string(&buffer)?;
    println!("{}", v.interface);
    Ok(())
}

fn varlink_info(address: &str) -> Result<()> {
    let conn = Connection::new(address)?;
    let mut call = OrgVarlinkServiceClient::new(conn);
    let info = call.get_info()?;
    println!("Vendor: {}", info.vendor);
    println!("Product: {}", info.product);
    println!("Version: {}", info.version);
    println!("URL: {}", info.url);
    println!("Interfaces:");
    for i in info.interfaces {
        println!("  {}", i)
    }

    Ok(())
}

fn varlink_help(url: &str) -> Result<()> {
    let del = match url.rfind("/") {
        None => {
            return Err(
                ErrorKind::NotImplemented(format!("Resolver not yet implemented {}", url)).into(),
            )
        }
        Some(v) => v,
    };

    let address = &url[0..del];
    let interface = &url[(del + 1)..];

    let conn = Connection::new(address)?;
    let mut call = OrgVarlinkServiceClient::new(conn);
    match call.get_interface_description(interface.to_string())? {
        GetInterfaceDescriptionReply {
            description: Some(desc),
        } => println!("{}", desc),
        _ => {
            return Err(ErrorKind::NotImplemented(format!("No description for {}", url)).into());
        }
    };

    Ok(())
}

fn varlink_call(url: &str, args: Option<&str>, more: bool) -> Result<()> {
    let del = match url.rfind("/") {
        None => {
            return Err(
                ErrorKind::NotImplemented(format!("Resolver not yet implemented {}", url)).into(),
            )
        }
        Some(v) => v,
    };

    let address = &url[0..del];
    let method = &url[(del + 1)..];

    let conn = Connection::new(address)?;
    let args = match args {
        Some(args) => serde_json::from_str(args)?,
        None => serde_json::Value::Null,
    };

    let mut call = MethodCall::<serde_json::Value, serde_json::Value, varlink::Error>::new(
        conn.clone(),
        String::from(method),
        args,
    );

    if !more {
        let reply = call.call()?;
        println!("{}", serde_json::to_string_pretty(&reply)?);
    } else {
        for reply in call.more()? {
            println!("{}", serde_json::to_string_pretty(&reply?)?);
        }
    }

    Ok(())
}

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

fn main() -> Result<()> {
    let mut app = App::new("varlink")
        .version(VERSION)
        .arg(
            Arg::with_name("timeout")
                .short("t")
                .long("timeout")
                .value_name("SECONDS")
                .help("time in seconds to wait for a reply")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("resolver")
                .short("R")
                .long("resolver")
                .value_name("ADDRESS")
                .help("address of the resolver")
                .takes_value(true),
        )
        .subcommand(
            SubCommand::with_name("bridge")
                .about("Bridge varlink messages to services on this machine")
                .long_about(
                    "Bridge varlink messages on standard in and out to varlink services on this \
                     machine.",
                ),
        )
        .subcommand(
            SubCommand::with_name("call")
                .about("Call a method")
                .long_about("Call METHOD on INTERFACE at ADDRESS. ARGUMENTS must be valid JSON.")
                .arg(
                    Arg::with_name("more")
                        .short("m")
                        .long("more")
                        .help("wait for multiple method returns if supported"),
                )
                .arg(
                    Arg::with_name("METHOD")
                        .value_name("[ADDRESS/]INTERFACE.METHOD")
                        .required(true),
                )
                .arg(Arg::with_name("ARGUMENTS").required(false)),
        )
        .subcommand(
            SubCommand::with_name("format")
                .about("Format a varlink service file")
                .arg(
                    Arg::with_name("FILE")
                        .required(true)
                        .help("The varlink interface definition file to format"),
                ),
        )
        .subcommand(
            SubCommand::with_name("info")
                .about("Print information about a service")
                .long_about("Prints information about the service running at ADDRESS.")
                .arg(Arg::with_name("ADDRESS").required(true)),
        )
        .subcommand(
            SubCommand::with_name("help")
                .about("Print interface description or service information")
                .long_about("Prints information about INTERFACE.")
                .arg(
                    Arg::with_name("INTERFACE")
                        .value_name("[ADDRESS/]INTERFACE")
                        .required(true),
                ),
        )
        .subcommand(
            SubCommand::with_name("resolve")
                .about("Resolve an interface name to a varlink address")
                .long_about("Resolve INTERFACE to the varlink address that implements it.")
                .arg(Arg::with_name("INTERFACE").required(true)),
        )
        .subcommand(
            SubCommand::with_name("completions")
                .about("Generates completion scripts for your shell")
                .arg(
                    Arg::with_name("SHELL")
                        .required(true)
                        .possible_values(&["bash", "fish", "zsh"])
                        .help("The shell to generate the script for"),
                ),
        );
    let matches = app.clone().get_matches();

    match matches.subcommand() {
        ("completions", Some(sub_matches)) => {
            let shell = sub_matches.value_of("SHELL").unwrap();
            app.gen_completions_to("varlink", shell.parse().unwrap(), &mut io::stdout());
        }
        ("format", Some(sub_matches)) => {
            let filename = sub_matches.value_of("FILE").unwrap();
            varlink_format(filename)?
        }
        ("info", Some(sub_matches)) => {
            let address = sub_matches.value_of("ADDRESS").unwrap();
            varlink_info(address)?
        }
        ("help", Some(sub_matches)) => {
            let interface = sub_matches.value_of("INTERFACE").unwrap();
            varlink_help(interface)?
        }
        ("call", Some(sub_matches)) => {
            let method = sub_matches.value_of("METHOD").unwrap();
            let args = sub_matches.value_of("ARGUMENTS");
            let more = sub_matches.is_present("more");
            varlink_call(method, args, more)?
        }
        (_, _) => {
            app.print_help()?;
            eprintln!();
        }
    }
    Ok(())
}
<commit_msg>simplify code<commit_after>extern crate clap;
#[macro_use]
extern crate error_chain;
extern crate serde_json;
extern crate varlink;
extern crate varlink_parser;

use clap::{App, Arg, SubCommand};
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::path::Path;
use std::str;
use varlink::{Connection, GetInterfaceDescriptionReply, MethodCall, OrgVarlinkServiceClient,
              OrgVarlinkServiceInterface};
use varlink_parser::Varlink;

error_chain! {
    foreign_links {
        Io(::std::io::Error);
        Fmt(::std::fmt::Error);
        SerdeJson(::serde_json::Error);
        Clap(::clap::Error);
    }
    links {
        Varlink(::varlink::Error, ::varlink::ErrorKind);
        VarlinkParse(::varlink_parser::Error, ::varlink_parser::ErrorKind);
    }
    errors {
        NotImplemented(t: String) {
            display("Not yet implemented: '{}'", t)
        }
    }
}

fn varlink_format(filename: &str) -> Result<()> {
    let mut buffer = String::new();
    File::open(Path::new(filename))?.read_to_string(&mut buffer)?;

    let v = Varlink::from_string(&buffer)?;
    println!("{}", v.interface);
    Ok(())
}

fn varlink_info(address: &str) -> Result<()> {
    let conn = Connection::new(address)?;
    let mut call = OrgVarlinkServiceClient::new(conn);
    let info = call.get_info()?;
    println!("Vendor: {}", info.vendor);
    println!("Product: {}", info.product);
    println!("Version: {}", info.version);
    println!("URL: {}", info.url);
    println!("Interfaces:");
    for i in info.interfaces {
        println!("  {}", i)
    }

    Ok(())
}

fn varlink_help(url: &str) -> Result<()> {
    let del = url.rfind("/")
        .ok_or(Error::from(ErrorKind::NotImplemented(format!(
            "Resolver not yet implemented {}",
            url
        ))))?;

    let address = &url[0..del];
    let interface = &url[(del + 1)..];

    let conn = Connection::new(address)?;
    let mut call = OrgVarlinkServiceClient::new(conn);
    match call.get_interface_description(interface.to_string())? {
        GetInterfaceDescriptionReply {
            description: Some(desc),
        } => println!("{}", desc),
        _ => {
            return Err(ErrorKind::NotImplemented(format!("No description for {}", url)).into());
        }
    };

    Ok(())
}

fn varlink_call(url: &str, args: Option<&str>, more: bool) -> Result<()> {
    let del = url.rfind("/")
        .ok_or(Error::from(ErrorKind::NotImplemented(format!(
            "Resolver not yet implemented {}",
            url
        ))))?;

    let address = &url[0..del];
    let method = &url[(del + 1)..];

    let conn = Connection::new(address)?;
    let args = match args {
        Some(args) => serde_json::from_str(args)?,
        None => serde_json::Value::Null,
    };

    let mut call = MethodCall::<serde_json::Value, serde_json::Value, varlink::Error>::new(
        conn.clone(),
        String::from(method),
        args,
    );

    if !more {
        let reply = call.call()?;
        println!("{}", serde_json::to_string_pretty(&reply)?);
    } else {
        for reply in call.more()? {
            println!("{}", serde_json::to_string_pretty(&reply?)?);
        }
    }

    Ok(())
}

const VERSION: &'static str = env!("CARGO_PKG_VERSION");

fn main() -> Result<()> {
    let mut app = App::new("varlink")
        .version(VERSION)
        .arg(
            Arg::with_name("timeout")
                .short("t")
                .long("timeout")
                .value_name("SECONDS")
                .help("time in seconds to wait for a reply")
                .takes_value(true),
        )
        .arg(
            Arg::with_name("resolver")
                .short("R")
                .long("resolver")
                .value_name("ADDRESS")
                .help("address of the resolver")
                .takes_value(true),
        )
        .subcommand(
            SubCommand::with_name("bridge")
                .about("Bridge varlink messages to services on this machine")
                .long_about(
                    "Bridge varlink messages on standard in and out to varlink services on this \
                     machine.",
                ),
        )
        .subcommand(
            SubCommand::with_name("call")
                .about("Call a method")
                .long_about("Call METHOD on INTERFACE at ADDRESS. ARGUMENTS must be valid JSON.")
                .arg(
                    Arg::with_name("more")
                        .short("m")
                        .long("more")
                        .help("wait for multiple method returns if supported"),
                )
                .arg(
                    Arg::with_name("METHOD")
                        .value_name("[ADDRESS/]INTERFACE.METHOD")
                        .required(true),
                )
                .arg(Arg::with_name("ARGUMENTS").required(false)),
        )
        .subcommand(
            SubCommand::with_name("format")
                .about("Format a varlink service file")
                .arg(
                    Arg::with_name("FILE")
                        .required(true)
                        .help("The varlink interface definition file to format"),
                ),
        )
        .subcommand(
            SubCommand::with_name("info")
                .about("Print information about a service")
                .long_about("Prints information about the service running at ADDRESS.")
                .arg(Arg::with_name("ADDRESS").required(true)),
        )
        .subcommand(
            SubCommand::with_name("help")
                .about("Print interface description or service information")
                .long_about("Prints information about INTERFACE.")
                .arg(
                    Arg::with_name("INTERFACE")
                        .value_name("[ADDRESS/]INTERFACE")
                        .required(true),
                ),
        )
        .subcommand(
            SubCommand::with_name("resolve")
                .about("Resolve an interface name to a varlink address")
                .long_about("Resolve INTERFACE to the varlink address that implements it.")
                .arg(Arg::with_name("INTERFACE").required(true)),
        )
        .subcommand(
            SubCommand::with_name("completions")
                .about("Generates completion scripts for your shell")
                .arg(
                    Arg::with_name("SHELL")
                        .required(true)
                        .possible_values(&["bash", "fish", "zsh"])
                        .help("The shell to generate the script for"),
                ),
        );
    let matches = app.clone().get_matches();

    match matches.subcommand() {
        ("completions", Some(sub_matches)) => {
            let shell = sub_matches.value_of("SHELL").unwrap();
            app.gen_completions_to("varlink", shell.parse().unwrap(), &mut io::stdout());
        }
        ("format", Some(sub_matches)) => {
            let filename = sub_matches.value_of("FILE").unwrap();
            varlink_format(filename)?
        }
        ("info", Some(sub_matches)) => {
            let address = sub_matches.value_of("ADDRESS").unwrap();
            varlink_info(address)?
        }
        ("help", Some(sub_matches)) => {
            let interface = sub_matches.value_of("INTERFACE").unwrap();
            varlink_help(interface)?
        }
        ("call", Some(sub_matches)) => {
            let method = sub_matches.value_of("METHOD").unwrap();
            let args = sub_matches.value_of("ARGUMENTS");
            let more = sub_matches.is_present("more");
            varlink_call(method, args, more)?
        }
        (_, _) => {
            app.print_help()?;
            eprintln!();
        }
    }
    Ok(())
}
<|endoftext|>


<commit_before>//! This module implements the text entry widget.

use std::collections::VecDeque;
use rustbox::{ RustBox, Event, Key, Style, Color };

/// The IRC client's text box.
pub struct TextEntry {
    // FIXME: Store cursor position as a pair of terminal column and string index.
    cursor_pos: isize,
    hist: VecDeque<String>,
    hist_pos: usize,
    /// Queue of entries that haven't been processed yet.
    cmds: VecDeque<String>,
}

impl TextEntry {
    pub fn new() -> TextEntry {
        let mut hist = VecDeque::new();
        hist.push_front(String::new());
        TextEntry {
            cursor_pos: 0,
            hist: hist,
            hist_pos: 0,
            cmds: VecDeque::new(),
        }
    }

    /// Returns the next entry in the list of things the user has typed.
    pub fn next_entry(&mut self) -> Option<String> {
        self.cmds.pop_front()
    }

    pub fn render(&self, rb: &mut RustBox) {
        debug_assert!(self.cursor_pos >= 0);
        debug_assert!(self.cursor_pos <= self.get_text().len() as isize);

        let h = rb.height();
        rb.print(0, h - 1, Style::empty(), Color::Default, Color::Default, self.get_text());
        rb.set_cursor(self.cursor_col(), h as isize - 1);
    }

    /// Handles an event
    ///
    /// Returns true if the event was handled.
    pub fn handle(&mut self, evt: &Event) -> bool {
        let ret = match *evt {
            Event::KeyEvent(key) => self.handle_key(&key),
            _ => false,
        };
        debug_assert!(self.cursor_pos >= 0);
        debug_assert!(self.cursor_pos <= self.get_text().len() as isize);
        ret
    }

    fn handle_key(&mut self, key: &Key) -> bool {
        match *key {
            Key::Char(ch) => {
                // FIXME: This will break on multi-byte unicode characters.
                self.hist[self.hist_pos].insert(self.cursor_pos as usize, ch);
                self.move_cursor(|p| p + 1);
                true
            },
            Key::Backspace => {
                if self.cursor_pos > 0 {
                    self.hist[self.hist_pos].remove(self.cursor_pos as usize - 1);
                    self.move_cursor(|p| p - 1);
                }
                true
            },
            Key::Left => { self.move_cursor(|p| p - 1); true },
            Key::Right => { self.move_cursor(|p| p + 1); true },
            Key::Home => { self.move_cursor(|_| 0); true },
            Key::End => { self.cursor_to_end(); true },
            Key::Enter => {
                let text = self.get_text().to_owned();
                if !text.is_empty() {
                    self.cmds.push_back(text);
                    self.push_hist();
                    self.move_cursor(|_| 0);
                }
                true
            },
            Key::Up => {
                if self.hist_pos+1 < self.hist.len() {
                    self.hist_pos += 1;
                }
                self.cursor_to_end();
                true
            },
            Key::Down => {
                if self.hist_pos > 0 {
                    self.hist_pos -= 1;
                }
                self.cursor_to_end();
                true
            },
            _ => false,
        }
    }

    pub fn get_text(&self) -> &str {
        &self.hist[self.hist_pos]
    }

    fn cursor_col(&self) -> isize {
        self.cursor_pos as isize
    }

    fn move_cursor<F>(&mut self, f: F) where F : Fn(isize) -> isize {
        let new = f(self.cursor_pos);
        if new > self.get_text().len() as isize {
            self.cursor_pos = self.get_text().len() as isize
        } else if new < 0 {
            self.cursor_pos = 0;
        } else {
            self.cursor_pos = new;
        }
    }

    fn cursor_to_end(&mut self) {
        self.cursor_pos = self.get_text().len() as isize;
    }

    /// Pushes a new command history entry and resets hist_pos.
    ///
    /// This has the effect of pushing the current line up into the history and
    /// clearing the line. If hist_pos is greater than 0, pushes the current
    /// line to the front of the history.
    fn push_hist(&mut self) {
        if self.hist_pos > 0 {
            let ent = self.hist[self.hist_pos].clone();
            self.hist[0] = ent;
        }
        self.hist.push_front(String::new());
        self.hist_pos = 0;
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use rustbox::{ Event, Key };

    fn press_key(entry: &mut TextEntry, key: Key) {
        entry.handle(&Event::KeyEvent(key));
    }

    fn press_times(entry: &mut TextEntry, key: Key, times: usize) {
        for _ in 0..times {
            entry.handle(&Event::KeyEvent(key));
        }
    }

    fn press_chars(entry: &mut TextEntry, string: &str) {
        for ch in string.chars() {
            entry.handle(&Event::KeyEvent(Key::Char(ch)));
        }
    }

    #[test]
    fn basic_typing() {
        let mut entry = TextEntry::new();
        press_chars(&mut entry, "testing");
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("testing".to_owned()), entry.next_entry());
    }

    #[test]
    fn insert_typing() {
        // Tests typing in the middle of the line.
        let mut entry = TextEntry::new();
        press_chars(&mut entry, "This is test");
        assert_eq!("This is test", entry.get_text());
        press_times(&mut entry, Key::Left, 4);
        press_chars(&mut entry, "a ");
        press_key(&mut entry, Key::End);
        assert_eq!("This is a test", entry.get_text());
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("This is a test".to_owned()), entry.next_entry());
    }

    #[test]
    fn move_past_ends() {
        let mut entry = TextEntry::new();
        press_chars(&mut entry, "test");
        press_times(&mut entry, Key::Left, 40);
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("test".to_owned()), entry.next_entry());

        press_chars(&mut entry, "test");
        press_times(&mut entry, Key::Right, 40);
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("test".to_owned()), entry.next_entry());
    }

    #[test]
    fn cycle_history() {
        let mut entry = TextEntry::new();
        press_chars(&mut entry, "Entry 1");
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("Entry 1".to_owned()), entry.next_entry());
        press_chars(&mut entry, "Another entry 2");
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("Another entry 2".to_owned()), entry.next_entry());
        press_chars(&mut entry, "Entry 3");
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("Entry 3".to_owned()), entry.next_entry());

        assert_eq!("", entry.get_text());
        press_key(&mut entry, Key::Up);
        assert_eq!("Entry 3", entry.get_text());
        press_key(&mut entry, Key::Up);
        assert_eq!("Another entry 2", entry.get_text());
        press_key(&mut entry, Key::Up);
        assert_eq!("Entry 1", entry.get_text());
        press_key(&mut entry, Key::Up);
        assert_eq!("Entry 1", entry.get_text());
        press_key(&mut entry, Key::Down);
        assert_eq!("Another entry 2", entry.get_text());
        press_key(&mut entry, Key::Down);
        assert_eq!("Entry 3", entry.get_text());
        press_key(&mut entry, Key::Down);
        assert_eq!("", entry.get_text());
    }

    #[test]
    fn enter_from_history() {
        // This checks that when we enter a line from our entry history, it gets
        // placed in the history properly.
        let mut entry = TextEntry::new();
        press_chars(&mut entry, "Entry 1");
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("Entry 1".to_owned()), entry.next_entry());
        press_chars(&mut entry, "Another entry 2");
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("Another entry 2".to_owned()), entry.next_entry());
        press_chars(&mut entry, "Entry 3");
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("Entry 3".to_owned()), entry.next_entry());

        // Cycle up to "Another entry 2"
        press_times(&mut entry, Key::Up, 2);
        assert_eq!("Another entry 2", entry.get_text());
        press_key(&mut entry, Key::Backspace);
        press_chars(&mut entry, "4");
        assert_eq!("Another entry 4", entry.get_text());
        press_key(&mut entry, Key::Enter);

        assert_eq!("", entry.get_text());
        press_key(&mut entry, Key::Up);
        assert_eq!("Another entry 4", entry.get_text());
    }
}
<commit_msg>Fix entry to work properly with multi-byte chars<commit_after>//! This module implements the text entry widget.

use std::collections::VecDeque;
use rustbox::{ RustBox, Event, Key, Style, Color };

/// The IRC client's text box.
pub struct TextEntry {
    // FIXME: Store cursor position as a pair of terminal column and string index.
    cursor_idx: usize,
    cursor_col: isize,
    hist: VecDeque<String>,
    hist_pos: usize,
    /// Queue of entries that haven't been processed yet.
    cmds: VecDeque<String>,
}

impl TextEntry {
    pub fn new() -> TextEntry {
        let mut hist = VecDeque::new();
        hist.push_front(String::new());
        TextEntry {
            cursor_idx: 0,
            cursor_col: 0,
            hist: hist,
            hist_pos: 0,
            cmds: VecDeque::new(),
        }
    }

    /// Returns the next entry in the list of things the user has typed.
    pub fn next_entry(&mut self) -> Option<String> {
        self.cmds.pop_front()
    }

    pub fn render(&self, rb: &mut RustBox) {
        let h = rb.height();
        rb.print(0, h - 1, Style::empty(), Color::Default, Color::Default, self.get_text());
        rb.set_cursor(self.cursor_col(), h as isize - 1);
    }

    /// Handles an event
    ///
    /// Returns true if the event was handled.
    pub fn handle(&mut self, evt: &Event) -> bool {
        let ret = match *evt {
            Event::KeyEvent(key) => self.handle_key(&key),
            _ => false,
        };
        debug_assert!(self.cursor_col >= 0);
        debug_assert!(self.cursor_idx <= self.get_text().len());
        debug_assert!{
            // Check that cursor_col lines up with the number of the char at
            // cursor_idx.
            if let Some((idx, _)) = self.hist[self.hist_pos].char_indices().nth(self.cursor_col as usize) {
                idx == self.cursor_idx
            } else {
                self.cursor_idx == self.hist[self.hist_pos].len()
            },
            "Cursor column misaligned with cursor index"
        }
        ret
    }

    fn handle_key(&mut self, key: &Key) -> bool {
        match *key {
            Key::Char(ch) => {
                self.hist[self.hist_pos].insert(self.cursor_idx as usize, ch);
                self.move_cursor_by(1);
                true
            },
            Key::Backspace => {
                if self.cursor_col > 0 {
                    self.move_cursor_by(-1);
                    self.hist[self.hist_pos].remove(self.cursor_idx as usize);
                }
                true
            },
            Key::Left => { self.move_cursor_by(-1); true },
            Key::Right => { self.move_cursor_by(1); true },
            Key::Home => { self.move_cursor_home(); true },
            Key::End => { self.move_cursor_end(); true },
            Key::Enter => {
                let text = self.get_text().to_owned();
                if !text.is_empty() {
                    self.cmds.push_back(text);
                    self.push_hist();
                    self.move_cursor_home();
                }
                true
            },
            Key::Up => {
                if self.hist_pos+1 < self.hist.len() {
                    self.hist_pos += 1;
                }
                self.move_cursor_end();
                true
            },
            Key::Down => {
                if self.hist_pos > 0 {
                    self.hist_pos -= 1;
                }
                self.move_cursor_end();
                true
            },
            _ => false,
        }
    }

    pub fn get_text(&self) -> &str {
        &self.hist[self.hist_pos]
    }

    fn cursor_col(&self) -> isize {
        self.cursor_col
    }

    fn move_cursor_by(&mut self, by: isize) {
        let ref text = self.hist[self.hist_pos];
        if by > 0 {
            // Moving right, we slice the string from our current index to the
            // end and find the next boundary in the sub-string.
            let mut idxs = text[self.cursor_idx..].char_indices();
            if let Some((new, _)) = idxs.nth(by as usize) {
                // Add the previous cursor index to the index within the subslice.
                self.cursor_idx = self.cursor_idx + new;
                self.cursor_col += by;
            } else {
                self.cursor_idx = text.len();
                self.cursor_col = text.chars().count() as isize;
            }
        } else if by < 0 {
            let mut idxs = text[..self.cursor_idx].char_indices().rev();
            if let Some((new, _)) = idxs.nth((-by) as usize - 1) {
                self.cursor_idx = new;
                self.cursor_col += by;
            } else {
                self.cursor_idx = 0;
                self.cursor_col = 0;
            }
        }
    }

    fn move_cursor_home(&mut self) {
        self.cursor_idx = 0;
        self.cursor_col = 0;
    }

    fn move_cursor_end(&mut self) {
        self.cursor_idx = self.get_text().len();
        self.cursor_col = self.get_text().chars().count() as isize;
    }

    /// Pushes a new command history entry and resets hist_pos.
    ///
    /// This has the effect of pushing the current line up into the history and
    /// clearing the line. If hist_pos is greater than 0, pushes the current
    /// line to the front of the history.
    fn push_hist(&mut self) {
        if self.hist_pos > 0 {
            let ent = self.hist[self.hist_pos].clone();
            self.hist[0] = ent;
        }
        self.hist.push_front(String::new());
        self.hist_pos = 0;
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use rustbox::{ Event, Key };

    fn press_key(entry: &mut TextEntry, key: Key) {
        entry.handle(&Event::KeyEvent(key));
    }

    fn press_times(entry: &mut TextEntry, key: Key, times: usize) {
        for _ in 0..times {
            entry.handle(&Event::KeyEvent(key));
        }
    }

    fn press_chars(entry: &mut TextEntry, string: &str) {
        for ch in string.chars() {
            entry.handle(&Event::KeyEvent(Key::Char(ch)));
        }
    }

    #[test]
    fn basic_typing() {
        let mut entry = TextEntry::new();
        press_chars(&mut entry, "testing");
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("testing".to_owned()), entry.next_entry());
    }

    #[test]
    fn insert_typing() {
        // Tests typing in the middle of the line.
        let mut entry = TextEntry::new();
        press_chars(&mut entry, "This is test");
        assert_eq!("This is test", entry.get_text());
        press_times(&mut entry, Key::Left, 4);
        press_chars(&mut entry, "a ");
        press_key(&mut entry, Key::End);
        assert_eq!("This is a test", entry.get_text());
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("This is a test".to_owned()), entry.next_entry());
    }

    #[test]
    fn backspace() {
        // Tests typing in the middle of the line.
        let mut entry = TextEntry::new();
        press_chars(&mut entry, "IRC sucks");
        press_times(&mut entry, Key::Backspace, 5);
        press_chars(&mut entry, "is awesome!");
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("IRC is awesome!".to_owned()), entry.next_entry());
    }

    #[test]
    fn multibyte_char_basic_typing() {
        let mut entry = TextEntry::new();
        press_chars(&mut entry, "こんにちわ");
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("こんにちわ".to_owned()), entry.next_entry());
    }

    #[test]
    fn multibyte_char_insert_typing() {
        let mut entry = TextEntry::new();
        press_chars(&mut entry, "これはです");
        press_times(&mut entry, Key::Left, 2);
        press_chars(&mut entry, "テスト");
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("これはテストです".to_owned()), entry.next_entry());
    }

    #[test]
    fn cursor_move_left() {
        let mut entry = TextEntry::new();

        press_chars(&mut entry, "This is test");
        press_times(&mut entry, Key::Left, 4);
        press_chars(&mut entry, "a ");
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("This is a test".to_owned()), entry.next_entry());

        press_chars(&mut entry, "これはです");
        press_times(&mut entry, Key::Left, 2);
        press_chars(&mut entry, "テスト");
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("これはテストです".to_owned()), entry.next_entry());
    }

    #[test]
    fn cursor_move_right() {
        // Also tests the home key.
        let mut entry = TextEntry::new();

        press_chars(&mut entry, "This is test");
        press_key(&mut entry, Key::Home);
        press_times(&mut entry, Key::Right, 8);
        press_chars(&mut entry, "a ");
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("This is a test".to_owned()), entry.next_entry());

        press_chars(&mut entry, "これはです");
        press_key(&mut entry, Key::Home);
        press_times(&mut entry, Key::Right, 3);
        press_chars(&mut entry, "テスト");
        println!("Text: {}", entry.get_text());
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("これはテストです".to_owned()), entry.next_entry());
    }

    #[test]
    fn cycle_history() {
        let mut entry = TextEntry::new();
        press_chars(&mut entry, "Entry 1");
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("Entry 1".to_owned()), entry.next_entry());
        press_chars(&mut entry, "Another entry 2");
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("Another entry 2".to_owned()), entry.next_entry());
        press_chars(&mut entry, "Entry 3");
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("Entry 3".to_owned()), entry.next_entry());

        assert_eq!("", entry.get_text());
        press_key(&mut entry, Key::Up);
        assert_eq!("Entry 3", entry.get_text());
        press_key(&mut entry, Key::Up);
        assert_eq!("Another entry 2", entry.get_text());
        press_key(&mut entry, Key::Up);
        assert_eq!("Entry 1", entry.get_text());
        press_key(&mut entry, Key::Up);
        assert_eq!("Entry 1", entry.get_text());
        press_key(&mut entry, Key::Down);
        assert_eq!("Another entry 2", entry.get_text());
        press_key(&mut entry, Key::Down);
        assert_eq!("Entry 3", entry.get_text());
        press_key(&mut entry, Key::Down);
        assert_eq!("", entry.get_text());
    }

    #[test]
    fn enter_from_history() {
        // This checks that when we enter a line from our entry history, it gets
        // placed in the history properly.
        let mut entry = TextEntry::new();
        press_chars(&mut entry, "Entry 1");
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("Entry 1".to_owned()), entry.next_entry());
        press_chars(&mut entry, "Another entry");
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("Another entry".to_owned()), entry.next_entry());
        press_chars(&mut entry, "Entry 3");
        press_key(&mut entry, Key::Enter);
        assert_eq!(Some("Entry 3".to_owned()), entry.next_entry());

        // Cycle up to "Another entry 2"
        press_times(&mut entry, Key::Up, 2);
        assert_eq!("Another entry", entry.get_text());
        press_chars(&mut entry, " 2");
        assert_eq!("Another entry 2", entry.get_text());
        press_key(&mut entry, Key::Enter);

        assert_eq!("", entry.get_text());
        press_key(&mut entry, Key::Up);
        assert_eq!("Another entry 2", entry.get_text());
    }
}
<|endoftext|>


<commit_before>use bit_field::BitField;
use collections::vec::Vec;
use x86::bits64::task::TaskStateSegment;

pub struct Gdt(Vec<u64>);

impl Gdt {
    pub fn new() -> Gdt {
        let zero_entry = 0;
        Gdt(vec![zero_entry])
    }

    pub fn add_entry(&mut self, entry: Entry) -> Selector {
        use core::mem::size_of;
        let index = self.0.len() * size_of::<u64>();

        match entry {
            Entry::UserSegment(entry) => self.0.push(entry),
            Entry::SystemSegment(entry_low, entry_high) => {
                self.0.push(entry_low);
                self.0.push(entry_high);
            }
        }

        Selector(index as u16)
    }

    pub fn load(&'static self) {
        use x86::shared::dtables::{DescriptorTablePointer, lgdt};
        use core::mem::size_of;

        let ptr = DescriptorTablePointer {
            base: self.0.as_ptr() as *const ::x86::shared::segmentation::SegmentDescriptor,
            limit: (self.0.len() * size_of::<u64>() - 1) as u16,
        };

        unsafe { lgdt(&ptr) };
    }
}

pub enum Entry {
    UserSegment(u64),
    SystemSegment(u64, u64),
}

impl Entry {
    pub fn code_segment() -> Entry {
        let flags = DESCRIPTOR_TYPE | PRESENT | READ_WRITE | EXECUTABLE | LONG_MODE;
        Entry::UserSegment(flags.bits())
    }

    pub fn data_segment() -> Entry {
        let flags = DESCRIPTOR_TYPE | PRESENT | READ_WRITE;
        Entry::UserSegment(flags.bits())
    }

    pub fn tss_segment(tss: &'static TaskStateSegment) -> Entry {
        use core::mem::size_of;

        let ptr = tss as *const _ as u64;

        let mut low = PRESENT.bits();
        low.set_range(0..16, (size_of::<TaskStateSegment>() - 1) as u64);
        low.set_range(16..40, ptr.get_range(0..24));
        low.set_range(40..44, 0b1001); // type: available 64-bit tss

        let mut high = 0;
        high.set_range(0..32, ptr.get_range(32..64));

        Entry::SystemSegment(low, high)
    }
}

bitflags! {
    flags EntryFlags: u64 {
        const READ_WRITE        = 1 << 41,
        const CONFORMING        = 1 << 42,
        const EXECUTABLE        = 1 << 43,
        const DESCRIPTOR_TYPE   = 1 << 44,
        const PRESENT           = 1 << 47,
        const LONG_MODE         = 1 << 53,
    }
}

#[derive(Debug, Clone, Copy)]
pub struct Selector(u16);

impl Selector {
    pub fn new() -> Selector {
        Selector(0)
    }
}

pub fn reload_segment_registers(code_selector: Selector, data_selector: Selector) {

    let current_code_selector: u16;
    let current_data_selector: u16;

    unsafe {
        asm!("mov $0, cs" : "=r" (current_code_selector) ::: "intel");
        asm!("mov $0, ds" : "=r" (current_data_selector) ::: "intel");
    }
    assert_eq!(code_selector.0, current_code_selector);
    assert_eq!(data_selector.0, current_data_selector);

    // jmp ax:.new_code_segment // TODO
    // .new_code_segment:
    // unsafe { asm!("
    // mov ax, $1
    // mov ss, ax
    // mov ds, ax
    // mov es, ax
    // ":: "r" (code_selector.0), "r" (data_selector.0) :: "intel")};
    //
}

/// Load the task state register.
pub unsafe fn load_ltr(selector: Selector) {
    asm!("ltr $0" :: "r" (selector));
}
<commit_msg>Rewrite gdt module using an array instead of Vec<commit_after>use bit_field::BitField;
use x86::bits64::task::TaskStateSegment;
use x86::shared::segmentation::SegmentSelector;
use x86::shared::PrivilegeLevel;

pub struct Gdt {
    table: [u64; 8],
    current_offset: usize,
}

impl Gdt {
    pub fn new() -> Gdt {
        Gdt {
            table: [0; 8],
            current_offset: 1,
        }
    }

    fn push(&mut self, value: u64) -> usize {
        if self.current_offset < self.table.len() {
            let offset = self.current_offset;
            self.table[offset] = value;
            self.current_offset += 1;
            offset
        } else {
            panic!("GDT full");
        }
    }

    pub fn add_entry(&mut self, entry: Descriptor) -> SegmentSelector {
        let index = match entry {
            Descriptor::UserSegment(value) => self.push(value),
            Descriptor::SystemSegment(value_low, value_high) => {
                let index = self.push(value_low);
                self.push(value_high);
                index
            }
        };
        SegmentSelector::new(index as u16, PrivilegeLevel::Ring0)
    }

    pub fn load(&'static self) {
        use x86::shared::dtables::{DescriptorTablePointer, lgdt};
        use core::mem::size_of;

        let ptr = DescriptorTablePointer {
            base: self.table.as_ptr() as *const ::x86::shared::segmentation::SegmentDescriptor,
            limit: (self.table.len() * size_of::<u64>() - 1) as u16,
        };

        unsafe { lgdt(&ptr) };
    }
}

pub enum Descriptor {
    UserSegment(u64),
    SystemSegment(u64, u64),
}

impl Descriptor {
    pub fn kernel_code_segment() -> Descriptor {
        let flags = USER_SEGMENT | PRESENT | EXECUTABLE | LONG_MODE;
        Descriptor::UserSegment(flags.bits())
    }

    pub fn tss_segment(tss: &'static TaskStateSegment) -> Descriptor {
        use core::mem::size_of;

        let ptr = tss as *const _ as u64;

        let mut low = PRESENT.bits();
        low.set_range(0..16, (size_of::<TaskStateSegment>() - 1) as u64);
        low.set_range(16..40, ptr.get_range(0..24));
        low.set_range(40..44, 0b1001); // type: available 64-bit tss

        let mut high = 0;
        high.set_range(0..32, ptr.get_range(32..64));

        Descriptor::SystemSegment(low, high)
    }
}

bitflags! {
    flags DescriptorFlags: u64 {
        const CONFORMING        = 1 << 42,
        const EXECUTABLE        = 1 << 43,
        const USER_SEGMENT      = 1 << 44,
        const PRESENT           = 1 << 47,
        const LONG_MODE         = 1 << 53,
    }
}
<|endoftext|>


<commit_before><commit_msg>Add test for alternating between `next_u64` and `next_u32`<commit_after><|endoftext|>


<commit_before>use crate::Ipv4Net;
use crate::Ipv6Net;
use crate::IpNet;

use schemars::{JsonSchema, gen::SchemaGenerator, schema::{SubschemaValidation, Schema, SchemaObject, StringValidation, Metadata, SingleOrVec, InstanceType}};

impl JsonSchema for Ipv4Net {
    fn schema_name() -> String {
        "Ipv4Net".to_string()
    }

    fn json_schema(_gen: &mut SchemaGenerator) -> Schema {
        Schema::Object(SchemaObject {
            metadata: Some(Box::new(Metadata {
                title: Some("Ipv4 Network".to_string()),
                description: Some("Ipv4 address with subnet mask".to_string()),
                examples: vec![schemars::_serde_json::Value::String("0.0.0.0/0".to_string())],
                ..Default::default()
            })),
            instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))),
            string: Some(Box::new(StringValidation {
                pattern: Some(r#"\b(?:(?:2(?:[0-4][0-9]|5[0-5])|[0-1]?[0-9]?[0-9])\.){3}(?:(?:2([0-4][0-9]|5[0-5])|[0-1]?[0-9]?[0-9]))\/(?:(?:3([0-2])|[0-2]?[0-9]))\b$"#.to_string()),
                ..Default::default()
            })),
            ..Default::default()
        })
    }
}
impl JsonSchema for Ipv6Net {
    fn schema_name() -> String {
        "Ipv6Net".to_string()
    }

    fn json_schema(_gen: &mut SchemaGenerator) -> Schema {
        Schema::Object(SchemaObject {
            metadata: Some(Box::new(Metadata {
                title: Some("Ipv6 Network".to_string()),
                description: Some("Ipv6 address with prefix".to_string()),
                examples: vec![schemars::_serde_json::Value::String("::/0".to_string())],
                ..Default::default()
            })),
            instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))),
            string: Some(Box::new(StringValidation {
                pattern: Some(r#"^s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]d|1dd|[1-9]?d)(.(25[0-5]|2[0-4]d|1dd|[1-9]?d)){3}))|:)))(%.+)?s*(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))$"#.to_string()),
                ..Default::default()
            })),
            ..Default::default()
        })
    }
}
impl JsonSchema for IpNet {
    fn schema_name() -> String {
        "IpNet".to_string()
    }

    fn json_schema(gen: &mut SchemaGenerator) -> Schema {
        Schema::Object(SchemaObject {
            metadata: Some(Box::new(Metadata {
                title: Some("Ip Network".to_string()),
                description: Some("Ip address (v4 or v6) with Prefix".to_string()),
                ..Default::default()
            })),
            subschemas: Some(Box::new(
                SubschemaValidation {
                    one_of: Some(vec![Ipv4Net::json_schema(gen), Ipv6Net::json_schema(gen)]),
                    ..Default::default()
                }
            )),
            ..Default::default()
        })
    }
}
<commit_msg>Made IPv4 regex stricter, no leading zeroes, see issues #33. IPv6 regex seemed to have errors, simplified it, though it will not perform strict validation anymore.<commit_after>use crate::Ipv4Net;
use crate::Ipv6Net;
use crate::IpNet;

use schemars::{JsonSchema, gen::SchemaGenerator, schema::{SubschemaValidation, Schema, SchemaObject, StringValidation, Metadata, SingleOrVec, InstanceType}};

impl JsonSchema for Ipv4Net {
    fn schema_name() -> String {
        "Ipv4Net".to_string()
    }

    fn json_schema(_gen: &mut SchemaGenerator) -> Schema {
        Schema::Object(SchemaObject {
            metadata: Some(Box::new(Metadata {
                title: Some("IPv4 network".to_string()),
                description: Some("An IPv4 address with prefix length".to_string()),
                examples: vec![
                    schemars::_serde_json::Value::String("0.0.0.0/0".to_string()),
                    schemars::_serde_json::Value::String("192.168.0.0/24".to_string()),
                ],
                ..Default::default()
            })),
            instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))),
            string: Some(Box::new(StringValidation {
                max_length: Some(18),
                min_length: None,
                pattern: Some(r#"^(?:(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\.){3}(?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])\/(?:3[0-2]|[1-2][0-9]|[0-9])$"#.to_string()),
                ..Default::default()
            })),
            ..Default::default()
        })
    }
}
impl JsonSchema for Ipv6Net {
    fn schema_name() -> String {
        "Ipv6Net".to_string()
    }

    fn json_schema(_gen: &mut SchemaGenerator) -> Schema {
        Schema::Object(SchemaObject {
            metadata: Some(Box::new(Metadata {
                title: Some("IPv6 network".to_string()),
                description: Some("An IPv6 address with prefix length".to_string()),
                examples: vec![
                    schemars::_serde_json::Value::String("::/0".to_string()),
                    schemars::_serde_json::Value::String("fd00::/32".to_string()),
                ],
                ..Default::default()
            })),
            instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))),
            string: Some(Box::new(StringValidation {
                max_length: Some(43),
                min_length: None,
                pattern: Some(r#"^[0-9A-Fa-f:\.]+\/(?:[0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$"#.to_string()),
                ..Default::default()
            })),
            ..Default::default()
        })
    }
}
impl JsonSchema for IpNet {
    fn schema_name() -> String {
        "IpNet".to_string()
    }

    fn json_schema(gen: &mut SchemaGenerator) -> Schema {
        Schema::Object(SchemaObject {
            metadata: Some(Box::new(Metadata {
                title: Some("IP network".to_string()),
                description: Some("An IPv4 or IPv6 address with prefix length".to_string()),
                examples: vec![
                    schemars::_serde_json::Value::String("192.168.0.0/24".to_string()),
                    schemars::_serde_json::Value::String("fd00::/32".to_string()),
                ],
                ..Default::default()
            })),
            subschemas: Some(Box::new(
                SubschemaValidation {
                    one_of: Some(vec![Ipv4Net::json_schema(gen), Ipv6Net::json_schema(gen)]),
                    ..Default::default()
                }
            )),
            ..Default::default()
        })
    }
}
<|endoftext|>


<commit_before>// no-reformat

#[doc = "

    A demonstration module

    Contains documentation in various forms that rustdoc understands,
    for testing purposes. It doesn't surve any functional
    purpose. This here, for instance, is just some filler text.

    FIXME (1654): It would be nice if we could run some automated
    tests on this file

"];

#[doc = "The base price of a muffin on a non-holiday"]
const price_of_a_muffin: float = 70f;

type waitress = {
    hair_color: str
};

enum omnomnomy {
    cookie,
    pizza_pie([uint])
}

fn take_my_order_please(
    _waitress: waitress,
    _order: [omnomnomy]
) -> uint {

    #[doc(
        desc = "OMG would you take my order already?",
        args(_waitress = "The waitress that you want to bother",
             _order = "The order vector. It should be filled with food."),
        return = "The price of the order, including tax",
        failure = "This function is full of fail"
    )];

    fail;
}

mod fortress_of_solitude {
    #[doc(
        brief = "Superman's vacation home",
        desc = "

        The fortress of solitude is located in the Arctic and it is
        cold. What you may not know about the fortress of solitude
        though is that it contains two separate bowling alleys. One of
        them features bumper-bowling and is kind of lame.

        Really, it's pretty cool.

    ")];

}

mod blade_runner {
    #[doc(
        brief = "Blade Runner is probably the best movie ever",
        desc = "I like that in the world of Blade Runner it is always
                raining, and that it's always night time. And Aliens
                was also a really good movie.

                Alien 3 was crap though."
    )];
}
<commit_msg>rustdoc: Add some test enums to demo module<commit_after>// no-reformat

#[doc = "

    A demonstration module

    Contains documentation in various forms that rustdoc understands,
    for testing purposes. It doesn't surve any functional
    purpose. This here, for instance, is just some filler text.

    FIXME (1654): It would be nice if we could run some automated
    tests on this file

"];

#[doc = "The base price of a muffin on a non-holiday"]
const price_of_a_muffin: float = 70f;

type waitress = {
    hair_color: str
};

#[doc = "The type of things that produce omnomnom"]
enum omnomnomy {
    #[doc = "Delicious sugar cookies"]
    cookie,
    #[doc = "It's pizza"]
    pizza_pie([uint])
}

fn take_my_order_please(
    _waitress: waitress,
    _order: [omnomnomy]
) -> uint {

    #[doc(
        desc = "OMG would you take my order already?",
        args(_waitress = "The waitress that you want to bother",
             _order = "The order vector. It should be filled with food."),
        return = "The price of the order, including tax",
        failure = "This function is full of fail"
    )];

    fail;
}

mod fortress_of_solitude {
    #[doc(
        brief = "Superman's vacation home",
        desc = "

        The fortress of solitude is located in the Arctic and it is
        cold. What you may not know about the fortress of solitude
        though is that it contains two separate bowling alleys. One of
        them features bumper-bowling and is kind of lame.

        Really, it's pretty cool.

    ")];

}

mod blade_runner {
    #[doc(
        brief = "Blade Runner is probably the best movie ever",
        desc = "I like that in the world of Blade Runner it is always
                raining, and that it's always night time. And Aliens
                was also a really good movie.

                Alien 3 was crap though."
    )];
}
<|endoftext|>


<commit_before>//! moudule for finite automata.

/// Transition represents the rule that moves from one state to another.
/// `S` means the state, `T` means the input symbol.
pub struct Transition<S: Eq + Copy, T:Eq + Copy> {
  pub state: S,
  pub symbol: T,
  pub next_state: S
}

impl<S: Eq + Copy, T:Eq + Copy> Transition<S, T> {
  pub fn new(state: &S, symbol: &T, next_state: &S) -> Transition<S, T> {
    Transition { state: *state, symbol: *symbol, next_state: *next_state }
  }

  /// determine whether th current transition applies to the state and symbol
  pub fn is_apply_to(&self, state: &S, symbol: &T) -> bool {
    self.state == *state && self.symbol == *symbol
  }

  /// get the next state from the transition
  pub fn follow(&self) -> &S {
    &self.next_state
  }
}

/// a collection of transition rules
pub struct TransitionRelation<S: Eq + Copy, T: Eq + Copy> {
  transitions: Vec<Transition<S, T>>
}

impl<S: Eq + Copy, T: Eq + Copy> TransitionRelation<S, T> {
  pub fn new(transitions: Vec<Transition<S, T>>) -> TransitionRelation<S, T> {
    TransitionRelation { transitions: transitions }
  }

  /// get the next state for the input condition
  pub fn next_state_for(&self, state: &S, symbol: &T) -> Option<&S> {
    self.transition_for(state, symbol).map(|trans| { trans.follow() })
  }

  /// get the transition of the state and the symbol
  fn transition_for(&self, state: &S, symbol: &T) -> Option<&Transition<S, T>> {
    self.transitions.iter().find(|&transition| {
      transition.is_apply_to(state, symbol)
    })
  }
}

pub struct DFA<S: Eq + Copy, T: Eq + Copy> {
  current_state: S,
  accept_states: Vec<S>,
  transition_relation: TransitionRelation<S, T>
}

impl<S: Eq + Copy, T: Eq + Copy> DFA<S, T> {
  pub fn new(current_state: &S, accept_states: Vec<S>,
             transition_relation: TransitionRelation<S, T>) -> DFA<S, T> {
    DFA {
      current_state: *current_state,
      accept_states: accept_states,
      transition_relation: transition_relation
    }
  }

  /// read a symbol and change the dfa state
  pub fn read_symbol(&mut self, sym: &T) {
    self.current_state = *self.transition_relation
                             .next_state_for(&self.current_state, sym)
                             .unwrap()
  }

  // pub fn read_symbol_seq(&mut self, syms: Iterator<T>) {
  //   for sym in syms {
  //     self.read_symbol(sym);
  //   }
  // }

  /// determine whether the current dfa is in an accepted state
  pub fn is_accepting(&self) -> bool {
    self.accept_states.iter().any(|&state| {
      state == self.current_state
    })
  }
}

#[cfg(test)]
mod test {
  use super::Transition;
  use super::TransitionRelation;

  #[test]
  fn test_transition() {
    let rule = Transition::new(&1i, & 'a', &2i);
    assert_eq!(2i, rule.next_state);
  }

  #[test]
  fn test_transition_relation() {
    let rules = vec![
      Transition::new(&1i, & 'a', &1i),
      Transition::new(&1i, & 'b', &2i),
      Transition::new(&2i, & 'c', &2i)
    ];
    let relation = TransitionRelation::new(rules);

    let some_rule = relation.transition_for(&1i, & 'a').unwrap();
    assert_eq!(some_rule.state, 1);
    assert_eq!(some_rule.symbol, 'a');
  }
}
<commit_msg>dry: abstract state and symbol<commit_after>//! moudule for finite automata.

trait State: Eq + Copy {}
trait Symbol: Eq + Copy {}

/// Transition represents the rule that moves from one state to another.
/// `S` means the state, `T` means the input symbol.
pub struct Transition<S: State, T: Symbol> {
  pub state: S,
  pub symbol: T,
  pub next_state: S
}

impl<S: State, T: Symbol> Transition<S, T> {
  pub fn new(state: &S, symbol: &T, next_state: &S) -> Transition<S, T> {
    Transition { state: *state, symbol: *symbol, next_state: *next_state }
  }

  /// determine whether th current transition applies to the state and symbol
  pub fn is_apply_to(&self, state: &S, symbol: &T) -> bool {
    self.state == *state && self.symbol == *symbol
  }

  /// get the next state from the transition
  pub fn follow(&self) -> &S {
    &self.next_state
  }
}

/// a collection of transition rules
pub struct TransitionRelation<S: State, T: Symbol> {
  transitions: Vec<Transition<S, T>>
}

impl<S: State, T: Symbol> TransitionRelation<S, T> {
  pub fn new(transitions: Vec<Transition<S, T>>) -> TransitionRelation<S, T> {
    TransitionRelation { transitions: transitions }
  }

  /// get the next state for the input condition
  pub fn next_state_for(&self, state: &S, symbol: &T) -> Option<&S> {
    self.transition_for(state, symbol).map(|trans| { trans.follow() })
  }

  /// get the transition of the state and the symbol
  fn transition_for(&self, state: &S, symbol: &T) -> Option<&Transition<S, T>> {
    self.transitions.iter().find(|&transition| {
      transition.is_apply_to(state, symbol)
    })
  }
}

pub struct DFA<S: State, T: Symbol> {
  current_state: S,
  accept_states: Vec<S>,
  transition_relation: TransitionRelation<S, T>
}

impl<S: State, T: Symbol> DFA<S, T> {
  pub fn new(current_state: &S, accept_states: Vec<S>,
             transition_relation: TransitionRelation<S, T>) -> DFA<S, T> {
    DFA {
      current_state: *current_state,
      accept_states: accept_states,
      transition_relation: transition_relation
    }
  }

  /// read a symbol and change the dfa state
  pub fn read_symbol(&mut self, sym: &T) {
    self.current_state = *self.transition_relation
                             .next_state_for(&self.current_state, sym)
                             .unwrap()
  }

  // pub fn read_symbol_seq(&mut self, syms: Iterator<T>) {
  //   for sym in syms {
  //     self.read_symbol(sym);
  //   }
  // }

  /// determine whether the current dfa is in an accepted state
  pub fn is_accepting(&self) -> bool {
    self.accept_states.iter().any(|&state| {
      state == self.current_state
    })
  }
}

#[cfg(test)]
mod test {
  use super::State;
  use super::Symbol;
  use super::Transition;
  use super::TransitionRelation;

  impl State for int {}
  impl Symbol for char {}

  #[test]
  fn test_transition() {
    let rule = Transition::new(&1i, & 'a', &2i);
    assert_eq!(2i, rule.next_state);
  }

  #[test]
  fn test_transition_relation() {
    let rules = vec![
      Transition::new(&1i, & 'a', &1i),
      Transition::new(&1i, & 'b', &2i),
      Transition::new(&2i, & 'c', &2i)
    ];
    let relation = TransitionRelation::new(rules);

    let some_rule = relation.transition_for(&1i, & 'a').unwrap();
    assert_eq!(some_rule.state, 1);
    assert_eq!(some_rule.symbol, 'a');
  }
}
<|endoftext|>


<commit_before>mod err;

use std::os::unix::io::{AsRawFd, RawFd};
use std::io;

use ::descriptor::Descriptor;
use ::{libc, ffi};

pub use self::err::{MasterError, Result};

#[derive(Debug, Clone)]
#[allow(missing_copy_implementations)]
pub struct Master {
  pty: RawFd,
}

impl Master {
  pub fn new (
    path: *const ::libc::c_char,
  ) -> Result<Self> {
    match Self::open(path, libc::O_RDWR, None) {
      Err(cause) => Err(MasterError::BadDescriptor(cause)),
      Ok(fd) => Ok(Master {
        pty: fd,
      }),
    }
  }

  /// Change UID and GID of slave pty associated with master pty whose
  /// fd is provided, to the real UID and real GID of the calling thread.
  pub fn grantpt(&self) -> Result<libc::c_int> {
    unsafe {
      match ffi::grantpt(self.as_raw_fd()) {
        -1 => Err(MasterError::GrantptError),
        c => Ok(c),
      }
    }
  }

  /// Unlock the slave pty associated with the master to which fd refers.
  pub fn unlockpt(&self) -> Result<libc::c_int> {
    unsafe {
      match ffi::unlockpt(self.as_raw_fd()) {
        -1 => Err(MasterError::UnlockptError),
        c => Ok(c),
      }
    }
  }

  /// Returns a pointer to a static buffer, which will be overwritten on
  /// subsequent calls.
  pub fn ptsname(&self) -> Result<*const libc::c_schar> {
    unsafe {
      match ffi::ptsname(self.as_raw_fd()) {
        c if c.is_null() => Err(MasterError::PtsnameError),
        c => Ok(c),
      }
    }
  }
}

impl Descriptor for Master {
}

impl AsRawFd for Master {

  /// The accessor function `as_raw_fd` returns the fd.
  fn as_raw_fd(&self) -> RawFd {
    self.pty
  }
}

impl io::Read for Master {
  fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
    unsafe {
      match ffi::read(
        self.as_raw_fd(),
        buf.as_mut_ptr(),
        buf.len()
      ) {
        -1 => Ok(0),
        len => Ok(len as usize),
      }
    }
  }
}

impl io::Write for Master {
  fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
    unsafe {
      match ffi::write(
        self.as_raw_fd(),
        buf.as_ptr(),
        buf.len()
      ) {
        -1 => Err(io::Error::last_os_error()),
        ret => Ok(ret as usize),
      }
    }
  }

  fn flush(&mut self) -> io::Result<()> {
    Ok(())
  }
}
<commit_msg>reimplemente Copy trait only for Master<commit_after>mod err;

use std::os::unix::io::{AsRawFd, RawFd};
use std::io;

use ::descriptor::Descriptor;
use ::{libc, ffi};

pub use self::err::{MasterError, Result};

#[derive(Debug, Copy, Clone)]
pub struct Master {
  pty: RawFd,
}

impl Master {
  pub fn new (
    path: *const ::libc::c_char,
  ) -> Result<Self> {
    match Self::open(path, libc::O_RDWR, None) {
      Err(cause) => Err(MasterError::BadDescriptor(cause)),
      Ok(fd) => Ok(Master {
        pty: fd,
      }),
    }
  }

  /// Change UID and GID of slave pty associated with master pty whose
  /// fd is provided, to the real UID and real GID of the calling thread.
  pub fn grantpt(&self) -> Result<libc::c_int> {
    unsafe {
      match ffi::grantpt(self.as_raw_fd()) {
        -1 => Err(MasterError::GrantptError),
        c => Ok(c),
      }
    }
  }

  /// Unlock the slave pty associated with the master to which fd refers.
  pub fn unlockpt(&self) -> Result<libc::c_int> {
    unsafe {
      match ffi::unlockpt(self.as_raw_fd()) {
        -1 => Err(MasterError::UnlockptError),
        c => Ok(c),
      }
    }
  }

  /// Returns a pointer to a static buffer, which will be overwritten on
  /// subsequent calls.
  pub fn ptsname(&self) -> Result<*const libc::c_schar> {
    unsafe {
      match ffi::ptsname(self.as_raw_fd()) {
        c if c.is_null() => Err(MasterError::PtsnameError),
        c => Ok(c),
      }
    }
  }
}

impl Descriptor for Master {
}

impl AsRawFd for Master {

  /// The accessor function `as_raw_fd` returns the fd.
  fn as_raw_fd(&self) -> RawFd {
    self.pty
  }
}

impl io::Read for Master {
  fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
    unsafe {
      match ffi::read(
        self.as_raw_fd(),
        buf.as_mut_ptr(),
        buf.len()
      ) {
        -1 => Ok(0),
        len => Ok(len as usize),
      }
    }
  }
}

impl io::Write for Master {
  fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
    unsafe {
      match ffi::write(
        self.as_raw_fd(),
        buf.as_ptr(),
        buf.len()
      ) {
        -1 => Err(io::Error::last_os_error()),
        ret => Ok(ret as usize),
      }
    }
  }

  fn flush(&mut self) -> io::Result<()> {
    Ok(())
  }
}
<|endoftext|>


<commit_before>//! Print the contents of font tables.
//!
//! This accepts command line arguments similar to what is present in ttx,
//! although it does not produce xml output.

use std::{collections::HashSet, str::FromStr};

use font_types::Tag;
use read_fonts::{traversal::SomeTable, FontData, FontFileRef, FontRef, ReadError, TableProvider};

mod print;
mod query;

use print::PrettyPrinter;
use query::Query;

fn main() -> Result<(), Error> {
    let args = flags::Args::from_env().map_err(|e| Error(e.to_string()))?;
    let index = args.index.unwrap_or(0);
    let bytes = std::fs::read(&args.input).unwrap();
    let data = FontData::new(&bytes);
    let font = FontFileRef::new(data).get_font(index).unwrap(); //FontRef::new(data).unwrap();
    if args.list {
        list_tables(&font);
        return Ok(());
    }

    if let Some(query) = &args.query {
        return query::print_query(&font, query).map_err(Error);
    }

    let filter = TableFilter::from_args(&args)?;
    print_tables(&font, &filter);
    Ok(())
}

fn list_tables(font: &FontRef) {
    println!("Tag  Offset  Length  Checksum");
    println!("-------------------------------");

    let offset_pad = get_offset_width(font);

    for record in font.table_directory.table_records() {
        println!(
            "{0} 0x{1:02$X} {3:8} 0x{4:08X} ",
            record.tag(),
            record.offset().to_u32(),
            offset_pad,
            record.length(),
            record.checksum()
        );
    }
}

fn print_tables(font: &FontRef, filter: &TableFilter) {
    let mut printed = HashSet::new();
    for tag in font
        .table_directory
        .table_records()
        .iter()
        .map(|rec| rec.tag())
        .filter(|tag| filter.should_print(*tag))
    {
        printed.insert(tag);
        print_table(font, tag)
    }

    if let TableFilter::Include(to_print) = filter {
        for unprinted in to_print.difference(&printed) {
            println!("Table {unprinted} not found");
        }
    }
}

fn get_offset_width(font: &FontRef) -> usize {
    // pick how much padding we use for offsets based on the max offset in directory
    let max_off = font
        .table_directory
        .table_records()
        .iter()
        .map(|rec| rec.offset().to_u32())
        .max()
        .unwrap_or_default();
    hex_width(max_off)
}

/// Return the number of hex digits required to represent a given number.
fn hex_width(val: u32) -> usize {
    match val {
        0..=0xffff => 4usize,
        0x10000..=0xffff_ff => 6,
        0x1000000.. => 8,
    }
}

/// Given a font and a tag, return the appropriate table as a [`dyn SomeTable`][SomeTable].
fn get_some_table<'a>(
    font: &FontRef<'a>,
    tag: Tag,
) -> Result<Box<dyn SomeTable<'a> + 'a>, ReadError> {
    match tag {
        read_fonts::tables::gpos::TAG => font.gpos().map(|x| Box::new(x) as _),
        read_fonts::tables::gsub::TAG => font.gsub().map(|x| Box::new(x) as _),
        read_fonts::tables::cmap::TAG => font.cmap().map(|x| Box::new(x) as _),
        read_fonts::tables::gdef::TAG => font.gdef().map(|x| Box::new(x) as _),
        read_fonts::tables::glyf::TAG => font.glyf().map(|x| Box::new(x) as _),
        read_fonts::tables::head::TAG => font.head().map(|x| Box::new(x) as _),
        read_fonts::tables::hhea::TAG => font.hhea().map(|x| Box::new(x) as _),
        read_fonts::tables::hmtx::TAG => font.hmtx().map(|x| Box::new(x) as _),
        read_fonts::tables::loca::TAG => font.loca(None).map(|x| Box::new(x) as _),
        read_fonts::tables::maxp::TAG => font.maxp().map(|x| Box::new(x) as _),
        read_fonts::tables::name::TAG => font.name().map(|x| Box::new(x) as _),
        read_fonts::tables::post::TAG => font.post().map(|x| Box::new(x) as _),
        read_fonts::tables::colr::TAG => font.colr().map(|x| Box::new(x) as _),
        _ => Err(ReadError::TableIsMissing(tag)),
    }
}

fn print_table(font: &FontRef, tag: Tag) {
    match get_some_table(font, tag) {
        Ok(table) => fancy_print_table(&table).unwrap(),
        Err(err) => println!("{tag}: Error '{err}'"),
    }
}

enum TableFilter {
    All,
    Include(HashSet<Tag>),
    Exclude(HashSet<Tag>),
}

impl TableFilter {
    fn from_args(args: &flags::Args) -> Result<Self, Error> {
        if args.tables.is_some() && args.exclude.is_some() {
            return Err(Error::new("pass only one of --tables and --exclude"));
        }
        if let Some(tags) = &args.tables {
            make_tag_set(tags).map(TableFilter::Include)
        } else if let Some(tags) = &args.exclude {
            make_tag_set(tags).map(TableFilter::Exclude)
        } else {
            Ok(TableFilter::All)
        }
    }

    fn should_print(&self, tag: Tag) -> bool {
        match self {
            TableFilter::All => true,
            TableFilter::Include(tags) => tags.contains(&tag),
            TableFilter::Exclude(tags) => !tags.contains(&tag),
        }
    }
}

fn make_tag_set(inp: &str) -> Result<HashSet<Tag>, Error> {
    inp.split(' ')
        .map(|raw| match Tag::from_str(raw) {
            Ok(tag) => Ok(tag),
            Err(e) => Err(Error(format!(
                "Invalid tag '{}': {e}",
                raw.escape_default()
            ))),
        })
        .collect()
}

#[derive(Debug, Clone)]
struct Error(String);

impl Error {
    fn new(t: impl std::fmt::Display) -> Self {
        Self(t.to_string())
    }
}

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

impl std::error::Error for Error {}

fn fancy_print_table<'a>(table: &(dyn SomeTable<'a> + 'a)) -> std::io::Result<()> {
    let stdout = std::io::stdout();
    let mut locked = stdout.lock();
    let mut formatter = PrettyPrinter::new(&mut locked);
    formatter.print_root_table(table)
}

mod flags {
    use super::Query;
    use std::path::PathBuf;

    xflags::xflags! {
        /// Generate font table representations
        cmd args
            required input: PathBuf
            {
                optional -i, --index index: u32
                optional -l, --list
                optional -q, --query query: Query
                optional -t, --tables include: String
                optional -x, --exclude exclude: String
            }

    }
}
<commit_msg>remove commented code<commit_after>//! Print the contents of font tables.
//!
//! This accepts command line arguments similar to what is present in ttx,
//! although it does not produce xml output.

use std::{collections::HashSet, str::FromStr};

use font_types::Tag;
use read_fonts::{traversal::SomeTable, FontData, FontFileRef, FontRef, ReadError, TableProvider};

mod print;
mod query;

use print::PrettyPrinter;
use query::Query;

fn main() -> Result<(), Error> {
    let args = flags::Args::from_env().map_err(|e| Error(e.to_string()))?;
    let index = args.index.unwrap_or(0);
    let bytes = std::fs::read(&args.input).unwrap();
    let data = FontData::new(&bytes);
    let font = FontFileRef::new(data).get_font(index).unwrap();
    if args.list {
        list_tables(&font);
        return Ok(());
    }

    if let Some(query) = &args.query {
        return query::print_query(&font, query).map_err(Error);
    }

    let filter = TableFilter::from_args(&args)?;
    print_tables(&font, &filter);
    Ok(())
}

fn list_tables(font: &FontRef) {
    println!("Tag  Offset  Length  Checksum");
    println!("-------------------------------");

    let offset_pad = get_offset_width(font);

    for record in font.table_directory.table_records() {
        println!(
            "{0} 0x{1:02$X} {3:8} 0x{4:08X} ",
            record.tag(),
            record.offset().to_u32(),
            offset_pad,
            record.length(),
            record.checksum()
        );
    }
}

fn print_tables(font: &FontRef, filter: &TableFilter) {
    let mut printed = HashSet::new();
    for tag in font
        .table_directory
        .table_records()
        .iter()
        .map(|rec| rec.tag())
        .filter(|tag| filter.should_print(*tag))
    {
        printed.insert(tag);
        print_table(font, tag)
    }

    if let TableFilter::Include(to_print) = filter {
        for unprinted in to_print.difference(&printed) {
            println!("Table {unprinted} not found");
        }
    }
}

fn get_offset_width(font: &FontRef) -> usize {
    // pick how much padding we use for offsets based on the max offset in directory
    let max_off = font
        .table_directory
        .table_records()
        .iter()
        .map(|rec| rec.offset().to_u32())
        .max()
        .unwrap_or_default();
    hex_width(max_off)
}

/// Return the number of hex digits required to represent a given number.
fn hex_width(val: u32) -> usize {
    match val {
        0..=0xffff => 4usize,
        0x10000..=0xffff_ff => 6,
        0x1000000.. => 8,
    }
}

/// Given a font and a tag, return the appropriate table as a [`dyn SomeTable`][SomeTable].
fn get_some_table<'a>(
    font: &FontRef<'a>,
    tag: Tag,
) -> Result<Box<dyn SomeTable<'a> + 'a>, ReadError> {
    match tag {
        read_fonts::tables::gpos::TAG => font.gpos().map(|x| Box::new(x) as _),
        read_fonts::tables::gsub::TAG => font.gsub().map(|x| Box::new(x) as _),
        read_fonts::tables::cmap::TAG => font.cmap().map(|x| Box::new(x) as _),
        read_fonts::tables::gdef::TAG => font.gdef().map(|x| Box::new(x) as _),
        read_fonts::tables::glyf::TAG => font.glyf().map(|x| Box::new(x) as _),
        read_fonts::tables::head::TAG => font.head().map(|x| Box::new(x) as _),
        read_fonts::tables::hhea::TAG => font.hhea().map(|x| Box::new(x) as _),
        read_fonts::tables::hmtx::TAG => font.hmtx().map(|x| Box::new(x) as _),
        read_fonts::tables::loca::TAG => font.loca(None).map(|x| Box::new(x) as _),
        read_fonts::tables::maxp::TAG => font.maxp().map(|x| Box::new(x) as _),
        read_fonts::tables::name::TAG => font.name().map(|x| Box::new(x) as _),
        read_fonts::tables::post::TAG => font.post().map(|x| Box::new(x) as _),
        read_fonts::tables::colr::TAG => font.colr().map(|x| Box::new(x) as _),
        _ => Err(ReadError::TableIsMissing(tag)),
    }
}

fn print_table(font: &FontRef, tag: Tag) {
    match get_some_table(font, tag) {
        Ok(table) => fancy_print_table(&table).unwrap(),
        Err(err) => println!("{tag}: Error '{err}'"),
    }
}

enum TableFilter {
    All,
    Include(HashSet<Tag>),
    Exclude(HashSet<Tag>),
}

impl TableFilter {
    fn from_args(args: &flags::Args) -> Result<Self, Error> {
        if args.tables.is_some() && args.exclude.is_some() {
            return Err(Error::new("pass only one of --tables and --exclude"));
        }
        if let Some(tags) = &args.tables {
            make_tag_set(tags).map(TableFilter::Include)
        } else if let Some(tags) = &args.exclude {
            make_tag_set(tags).map(TableFilter::Exclude)
        } else {
            Ok(TableFilter::All)
        }
    }

    fn should_print(&self, tag: Tag) -> bool {
        match self {
            TableFilter::All => true,
            TableFilter::Include(tags) => tags.contains(&tag),
            TableFilter::Exclude(tags) => !tags.contains(&tag),
        }
    }
}

fn make_tag_set(inp: &str) -> Result<HashSet<Tag>, Error> {
    inp.split(' ')
        .map(|raw| match Tag::from_str(raw) {
            Ok(tag) => Ok(tag),
            Err(e) => Err(Error(format!(
                "Invalid tag '{}': {e}",
                raw.escape_default()
            ))),
        })
        .collect()
}

#[derive(Debug, Clone)]
struct Error(String);

impl Error {
    fn new(t: impl std::fmt::Display) -> Self {
        Self(t.to_string())
    }
}

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

impl std::error::Error for Error {}

fn fancy_print_table<'a>(table: &(dyn SomeTable<'a> + 'a)) -> std::io::Result<()> {
    let stdout = std::io::stdout();
    let mut locked = stdout.lock();
    let mut formatter = PrettyPrinter::new(&mut locked);
    formatter.print_root_table(table)
}

mod flags {
    use super::Query;
    use std::path::PathBuf;

    xflags::xflags! {
        /// Generate font table representations
        cmd args
            required input: PathBuf
            {
                optional -i, --index index: u32
                optional -l, --list
                optional -q, --query query: Query
                optional -t, --tables include: String
                optional -x, --exclude exclude: String
            }

    }
}
<|endoftext|>


<commit_before><commit_msg>Add ordering to SymbolRange<commit_after><|endoftext|>


<commit_before>//! External names.
//!
//! These are identifiers for declaring entities defined outside the current
//! function. The name of an external declaration doesn't have any meaning to
//! Cretonne, which compiles functions independently.

use std::fmt::{self, Write};
use std::ascii::AsciiExt;

/// The name of an external can be any sequence of bytes.
///
/// External names are primarily used as keys by code using Cretonne to map
/// from a cretonne::ir::FuncRef or similar to additional associated data.
///
/// External names can also serve as a primitive testing and debugging tool.
/// In particular, many `.cton` test files use function names to identify
/// functions.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct ExternalName(NameRepr);

impl ExternalName {
    /// Creates a new external name from a sequence of bytes.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use cretonne::ir::ExternalName;
    /// // Create `ExternalName` from a string.
    /// let name = ExternalName::new("hello");
    /// assert_eq!(name.to_string(), "%hello");
    ///
    /// // Create `ExternalName` from a sequence of bytes.
    /// let bytes: &[u8] = &[10, 9, 8];
    /// let name = ExternalName::new(bytes);
    /// assert_eq!(name.to_string(), "#0a0908");
    /// ```
    pub fn new<T>(v: T) -> ExternalName
    where
        T: Into<Vec<u8>>,
    {
        let vec = v.into();
        if vec.len() <= NAME_LENGTH_THRESHOLD {
            let mut bytes = [0u8; NAME_LENGTH_THRESHOLD];
            for (i, &byte) in vec.iter().enumerate() {
                bytes[i] = byte;
            }
            ExternalName(NameRepr::Short {
                length: vec.len() as u8,
                bytes: bytes,
            })
        } else {
            ExternalName(NameRepr::Long(vec))
        }
    }
}

/// Tries to interpret bytes as ASCII alphanumerical characters and `_`.
fn try_as_name(bytes: &[u8]) -> Option<String> {
    let mut name = String::with_capacity(bytes.len());
    for c in bytes.iter().map(|&b| b as char) {
        if c.is_ascii() && c.is_alphanumeric() || c == '_' {
            name.push(c);
        } else {
            return None;
        }
    }
    Some(name)
}

const NAME_LENGTH_THRESHOLD: usize = 22;

#[derive(Debug, Clone, PartialEq, Eq)]
enum NameRepr {
    Short {
        length: u8,
        bytes: [u8; NAME_LENGTH_THRESHOLD],
    },
    Long(Vec<u8>),
}

impl AsRef<[u8]> for NameRepr {
    fn as_ref(&self) -> &[u8] {
        match *self {
            NameRepr::Short { length, ref bytes } => &bytes[0..length as usize],
            NameRepr::Long(ref vec) => vec.as_ref(),
        }
    }
}

impl AsRef<[u8]> for ExternalName {
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl Default for NameRepr {
    fn default() -> Self {
        NameRepr::Short {
            length: 0,
            bytes: [0; NAME_LENGTH_THRESHOLD],
        }
    }
}

impl fmt::Display for ExternalName {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(name) = try_as_name(self.0.as_ref()) {
            write!(f, "%{}", name)
        } else {
            f.write_char('#')?;
            for byte in self.0.as_ref() {
                write!(f, "{:02x}", byte)?;
            }
            Ok(())
        }
    }
}

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

    #[test]
    fn displaying() {
        assert_eq!(ExternalName::new("").to_string(), "%");
        assert_eq!(ExternalName::new("x").to_string(), "%x");
        assert_eq!(ExternalName::new("x_1").to_string(), "%x_1");
        assert_eq!(ExternalName::new(" ").to_string(), "#20");
        assert_eq!(
            ExternalName::new("кретон").to_string(),
            "#d0bad180d0b5d182d0bed0bd"
        );
        assert_eq!(
            ExternalName::new("印花棉布").to_string(),
            "#e58db0e88ab1e6a389e5b883"
        );
        assert_eq!(
            ExternalName::new(vec![0, 1, 2, 3, 4, 5]).to_string(),
            "#000102030405"
        );
    }
}
<commit_msg>Implement Hash for ExternalName.<commit_after>//! External names.
//!
//! These are identifiers for declaring entities defined outside the current
//! function. The name of an external declaration doesn't have any meaning to
//! Cretonne, which compiles functions independently.

use std::fmt::{self, Write};
use std::ascii::AsciiExt;

/// The name of an external can be any sequence of bytes.
///
/// External names are primarily used as keys by code using Cretonne to map
/// from a cretonne::ir::FuncRef or similar to additional associated data.
///
/// External names can also serve as a primitive testing and debugging tool.
/// In particular, many `.cton` test files use function names to identify
/// functions.
#[derive(Debug, Clone, PartialEq, Eq, Default, Hash)]
pub struct ExternalName(NameRepr);

impl ExternalName {
    /// Creates a new external name from a sequence of bytes.
    ///
    /// # Examples
    ///
    /// ```rust
    /// # use cretonne::ir::ExternalName;
    /// // Create `ExternalName` from a string.
    /// let name = ExternalName::new("hello");
    /// assert_eq!(name.to_string(), "%hello");
    ///
    /// // Create `ExternalName` from a sequence of bytes.
    /// let bytes: &[u8] = &[10, 9, 8];
    /// let name = ExternalName::new(bytes);
    /// assert_eq!(name.to_string(), "#0a0908");
    /// ```
    pub fn new<T>(v: T) -> ExternalName
    where
        T: Into<Vec<u8>>,
    {
        let vec = v.into();
        if vec.len() <= NAME_LENGTH_THRESHOLD {
            let mut bytes = [0u8; NAME_LENGTH_THRESHOLD];
            for (i, &byte) in vec.iter().enumerate() {
                bytes[i] = byte;
            }
            ExternalName(NameRepr::Short {
                length: vec.len() as u8,
                bytes: bytes,
            })
        } else {
            ExternalName(NameRepr::Long(vec))
        }
    }
}

/// Tries to interpret bytes as ASCII alphanumerical characters and `_`.
fn try_as_name(bytes: &[u8]) -> Option<String> {
    let mut name = String::with_capacity(bytes.len());
    for c in bytes.iter().map(|&b| b as char) {
        if c.is_ascii() && c.is_alphanumeric() || c == '_' {
            name.push(c);
        } else {
            return None;
        }
    }
    Some(name)
}

const NAME_LENGTH_THRESHOLD: usize = 22;

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
enum NameRepr {
    Short {
        length: u8,
        bytes: [u8; NAME_LENGTH_THRESHOLD],
    },
    Long(Vec<u8>),
}

impl AsRef<[u8]> for NameRepr {
    fn as_ref(&self) -> &[u8] {
        match *self {
            NameRepr::Short { length, ref bytes } => &bytes[0..length as usize],
            NameRepr::Long(ref vec) => vec.as_ref(),
        }
    }
}

impl AsRef<[u8]> for ExternalName {
    fn as_ref(&self) -> &[u8] {
        self.0.as_ref()
    }
}

impl Default for NameRepr {
    fn default() -> Self {
        NameRepr::Short {
            length: 0,
            bytes: [0; NAME_LENGTH_THRESHOLD],
        }
    }
}

impl fmt::Display for ExternalName {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if let Some(name) = try_as_name(self.0.as_ref()) {
            write!(f, "%{}", name)
        } else {
            f.write_char('#')?;
            for byte in self.0.as_ref() {
                write!(f, "{:02x}", byte)?;
            }
            Ok(())
        }
    }
}

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

    #[test]
    fn displaying() {
        assert_eq!(ExternalName::new("").to_string(), "%");
        assert_eq!(ExternalName::new("x").to_string(), "%x");
        assert_eq!(ExternalName::new("x_1").to_string(), "%x_1");
        assert_eq!(ExternalName::new(" ").to_string(), "#20");
        assert_eq!(
            ExternalName::new("кретон").to_string(),
            "#d0bad180d0b5d182d0bed0bd"
        );
        assert_eq!(
            ExternalName::new("印花棉布").to_string(),
            "#e58db0e88ab1e6a389e5b883"
        );
        assert_eq!(
            ExternalName::new(vec![0, 1, 2, 3, 4, 5]).to_string(),
            "#000102030405"
        );
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2019 Stefan Lankes, RWTH Aachen University
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

#![allow(dead_code)]
#![allow(unused_imports)]

#[cfg(target_os = "hermit")]
extern crate hermit_sys;
/*extern crate http;*/
extern crate rayon;

mod tests;

use tests::*;

fn test_result<T>(result: Result<(), T>) -> &'static str {
	match result {
		Ok(_) => "ok",
		Err(_) => "failed!",
	}
}

fn main() {
	println!("Test {} ... {}", stringify!(hello), test_result(hello()));
	println!(
		"Test {} ... {}",
		stringify!(print_argv),
		test_result(print_argv())
	);
	println!(
		"Test {} ... {}",
		stringify!(print_env),
		test_result(print_env())
	);
	println!(
		"Test {} ... {}",
		stringify!(read_file),
		test_result(read_file())
	);
	println!(
		"Test {} ... {}",
		stringify!(create_file),
		test_result(create_file())
	);
	println!(
		"Test {} ... {}",
		stringify!(threading),
		test_result(threading())
	);
	println!(
		"Test {} ... {}",
		stringify!(pi_sequential),
		test_result(pi_sequential(5000000))
	);
	println!(
		"Test {} ... {}",
		stringify!(pi_parallel),
		test_result(pi_parallel(2, 5000000))
	);
	/*println!(
		"Test {} ... {}",
		stringify!(laplace),
		test_result(laplace(128, 128))
	);
	println!(
		"Test {} ... {}",
		stringify!(test_matmul_strassen),
		test_result(test_matmul_strassen())
	);*/
	println!(
		"Test {} ... {}",
		stringify!(thread_creation),
		test_result(thread_creation())
	);
	println!(
		"Test {} ... {}",
		stringify!(bench_sched_one_thread),
		test_result(bench_sched_one_thread())
	);
	println!(
		"Test {} ... {}",
		stringify!(bench_sched_two_threads),
		test_result(bench_sched_two_threads())
	);
	/*println!(
		"Test {} ... {}",
		stringify!(test_http_request),
		test_result(test_http_request())
	);*/
}
<commit_msg>disable benchmarks<commit_after>// Copyright (c) 2019 Stefan Lankes, RWTH Aachen University
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

#![allow(dead_code)]
#![allow(unused_imports)]

#[cfg(target_os = "hermit")]
extern crate hermit_sys;
/*extern crate http;*/
extern crate rayon;

mod tests;

use tests::*;

fn test_result<T>(result: Result<(), T>) -> &'static str {
	match result {
		Ok(_) => "ok",
		Err(_) => "failed!",
	}
}

fn main() {
	println!("Test {} ... {}", stringify!(hello), test_result(hello()));
	println!(
		"Test {} ... {}",
		stringify!(print_argv),
		test_result(print_argv())
	);
	println!(
		"Test {} ... {}",
		stringify!(print_env),
		test_result(print_env())
	);
	println!(
		"Test {} ... {}",
		stringify!(read_file),
		test_result(read_file())
	);
	println!(
		"Test {} ... {}",
		stringify!(create_file),
		test_result(create_file())
	);
	println!(
		"Test {} ... {}",
		stringify!(threading),
		test_result(threading())
	);
	println!(
		"Test {} ... {}",
		stringify!(pi_sequential),
		test_result(pi_sequential(5000000))
	);
	println!(
		"Test {} ... {}",
		stringify!(pi_parallel),
		test_result(pi_parallel(2, 5000000))
	);
	/*println!(
		"Test {} ... {}",
		stringify!(laplace),
		test_result(laplace(128, 128))
	);
	println!(
		"Test {} ... {}",
		stringify!(test_matmul_strassen),
		test_result(test_matmul_strassen())
	);*/
	/*println!(
		"Test {} ... {}",
		stringify!(thread_creation),
		test_result(thread_creation())
	);
	println!(
		"Test {} ... {}",
		stringify!(bench_sched_one_thread),
		test_result(bench_sched_one_thread())
	);
	println!(
		"Test {} ... {}",
		stringify!(bench_sched_two_threads),
		test_result(bench_sched_two_threads())
	);*/
	/*println!(
		"Test {} ... {}",
		stringify!(test_http_request),
		test_result(test_http_request())
	);*/
}
<|endoftext|>