<commit_before>#![allow(dead_code)]

extern crate libc;

use self::libc::execvp;
use std::{env, thread};
use std::ptr::null;
use std::ffi::CString;
use std::process::Command;
use std::io::prelude::*;
use std::path::Path;
use std::fs::OpenOptions;
use config::Config;
use layout::LayoutMsg;
use xlib_window_system::XlibWindowSystem;
use workspaces::{Workspaces, MoveOp};
use xlib::Window;
use failure::*;

pub enum Cmd {
    Exec(String),
    SwitchWorkspace(usize),
    SwitchScreen(usize),
    MoveToWorkspace(usize),
    MoveToScreen(usize),
    SendLayoutMsg(LayoutMsg),
    Reload,
    Exit,
    KillClient,
    FocusUp,
    FocusDown,
    FocusMaster,
    SwapUp,
    SwapDown,
    SwapMaster,
}

impl Cmd {
    pub fn call(&self, ws: &XlibWindowSystem, workspaces: &mut Workspaces, config: &Config) -> Result<(), Error> {
        match *self {
            Cmd::Exec(ref cmd) => {
                debug!("Cmd::Exec: {}", cmd);
                exec(cmd.clone());
            }
            Cmd::SwitchWorkspace(index) => {
                debug!("Cmd::SwitchWorkspace: {}", index);
                workspaces.switch_to(ws, config, index - 1);
            }
            Cmd::SwitchScreen(screen) => {
                debug!("Cmd::SwitchScreen: {}", screen);
                workspaces.switch_to_screen(ws, config, screen - 1);
            }
            Cmd::MoveToWorkspace(index) => {
                debug!("Cmd::MoveToWorkspace: {}", index);
                workspaces.move_window_to(ws, config, index - 1);
            }
            Cmd::MoveToScreen(screen) => {
                debug!("Cmd::MoveToScreen: {}", screen);
                workspaces.move_window_to_screen(ws, config, screen - 1);
            }
            Cmd::SendLayoutMsg(ref msg) => {
                debug!("Cmd::SendLayoutMsg::{:?}", msg);
                workspaces.current_mut().send_layout_message(msg.clone());
                workspaces.current().redraw(ws, config);
            }
            Cmd::Reload => {
                debug!("Cmd::Reload");
                reload(workspaces)
                    .context("failed to reload xr3wm")?;
            }
            Cmd::Exit => {
                debug!("Cmd::Exit");
                ws.close();
            }
            Cmd::KillClient => {
                debug!("Cmd::KillClient: {}",
                       workspaces.current_mut().focused_window());
                ws.kill_window(workspaces.current_mut().focused_window());
            }
            Cmd::FocusUp => {
                debug!("Cmd::FocusUp: {}", workspaces.current().focused_window());
                workspaces.current_mut().move_focus(ws, config, MoveOp::Up);
            }
            Cmd::FocusDown => {
                debug!("Cmd::FocusDown: {}", workspaces.current().focused_window());
                workspaces.current_mut().move_focus(ws, config, MoveOp::Down);
            }
            Cmd::FocusMaster => {
                debug!("Cmd::FocusMaster: {}",
                       workspaces.current().focused_window());
                workspaces.current_mut().move_focus(ws, config, MoveOp::Swap);
            }
            Cmd::SwapUp => {
                debug!("Cmd::SwapUp: {}", workspaces.current().focused_window());
                workspaces.current_mut().move_window(ws, config, MoveOp::Up);
            }
            Cmd::SwapDown => {
                debug!("Cmd::SwapDown: {}", workspaces.current().focused_window());
                workspaces.current_mut().move_window(ws, config, MoveOp::Down);
            }
            Cmd::SwapMaster => {
                debug!("Cmd::SwapMaster: {}", workspaces.current().focused_window());
                workspaces.current_mut().move_window(ws, config, MoveOp::Swap);
            }
        }
        Ok(())
    }
}

fn reload(workspaces: &mut Workspaces) -> Result<(), Error> {
    let curr_exe = env::current_exe()
        .context("failed to get executable path")?;
    let filename = curr_exe.file_name()
        .ok_or_else(|| err_msg("failed to get executable filename"))?
        .to_str()
        .ok_or_else(|| err_msg("failed to convert filename to UTF-8"))?;

    info!("recompiling...");
    debug!("Cmd::Reload: compiling...");

    let dir = env::current_dir()
        .context("failed to get current dir")?;
    let mut cmd = Command::new("cargo");

    let output = cmd.current_dir(&dir)
        .arg("build")
        .env("RUST_LOG", "none")
        .output()
        .context("failed to run cargo")?;

    if !output.status.success() {
        let stderr_msg = String::from_utf8(output.stderr)
            .context("failed to convert cargo stderr to UTF-8")?;
        bail!(format_err!("failed to recompile: {}", stderr_msg))
    }

    debug!("Cmd::Reload: restarting xr3wm...");

    let filename = CString::new(filename.as_bytes())
        .context("failed to convert filename to CString")?;
    let args : &mut [*const i8; 2] = &mut [
        filename.as_ptr() as *const i8,
        null()
    ];

    let path = Path::new(concat!(env!("HOME"), "/.xr3wm/.tmp"));

    // save current workspace state to load on restart
    let mut file = OpenOptions::new()
        .create(true)
        .write(true)
        .truncate(true)
        .open(&path)
        .context("failed to open workspace state tmp file")?;
    file.write_all(workspaces.serialize().as_bytes())
        .context("failed to save workspace state")?;
    file.flush()
        .context("failed to flush workspace tmp file")?;

    let curr_exe_str = CString::new(curr_exe.to_str()
        .ok_or_else(|| err_msg("failed to convert executable path to UTF-8"))?
        .as_bytes())
        .context("failed to convert executable path to CString")?;

    unsafe {
        execvp(curr_exe_str.as_ptr() as *const i8, args.as_mut_ptr());
    }
    Ok(())
}

pub struct ManageHook {
    pub class_name: String,
    pub cmd: CmdManage,
}

pub enum CmdManage {
    Move(usize),
    Float,
    Fullscreen,
    Ignore,
}

impl CmdManage {
    pub fn call(&self,
                ws: &XlibWindowSystem,
                workspaces: &mut Workspaces,
                config: &Config,
                window: Window) {
        match *self {
            CmdManage::Move(index) => {
                if let Some(parent) = ws.transient_for(window) {
                    if let Some(workspace) = workspaces.find_window(parent) {
                        workspace.add_window(ws, config, window);
                        workspace.focus_window(ws, config, window);
                    }
                } else {
                    debug!("CmdManage::Move: {}, {}", window, index);
                    workspaces.get_mut(index - 1).add_window(ws, config, window);
                    workspaces.get_mut(index - 1).focus_window(ws, config, window);
                }
            }
            CmdManage::Float => {
                debug!("CmdManage::Float");
                unimplemented!()
            }
            CmdManage::Fullscreen => {
                debug!("CmdManage::Fullscreen");
                unimplemented!()
            }
            CmdManage::Ignore => {
                debug!("CmdManage::Ignore");
                unimplemented!()
            }
        }
    }
}

fn exec(cmd: String) {
    thread::spawn(move || {
        let args: Vec<&str> = cmd[..].split(' ').collect();

        if !args.is_empty() {
            let mut cmd = Command::new(args[0]);

            if args.len() > 1 {
                cmd.args(&args[1..]);
            }

            match cmd.output() {
                Ok(_) => (),
                _ => panic!("failed to start \"{:?}\"", cmd),
            }
        }
    });
}
<commit_msg>Fix incorrect build path on config reload<commit_after>#![allow(dead_code)]

extern crate libc;

use self::libc::execvp;
use std::{env, thread};
use std::ptr::null;
use std::ffi::CString;
use std::process::Command;
use std::io::prelude::*;
use std::path::Path;
use std::fs::OpenOptions;
use config::Config;
use layout::LayoutMsg;
use xlib_window_system::XlibWindowSystem;
use workspaces::{Workspaces, MoveOp};
use xlib::Window;
use failure::*;

pub enum Cmd {
    Exec(String),
    SwitchWorkspace(usize),
    SwitchScreen(usize),
    MoveToWorkspace(usize),
    MoveToScreen(usize),
    SendLayoutMsg(LayoutMsg),
    Reload,
    Exit,
    KillClient,
    FocusUp,
    FocusDown,
    FocusMaster,
    SwapUp,
    SwapDown,
    SwapMaster,
}

impl Cmd {
    pub fn call(&self, ws: &XlibWindowSystem, workspaces: &mut Workspaces, config: &Config) -> Result<(), Error> {
        match *self {
            Cmd::Exec(ref cmd) => {
                debug!("Cmd::Exec: {}", cmd);
                exec(cmd.clone());
            }
            Cmd::SwitchWorkspace(index) => {
                debug!("Cmd::SwitchWorkspace: {}", index);
                workspaces.switch_to(ws, config, index - 1);
            }
            Cmd::SwitchScreen(screen) => {
                debug!("Cmd::SwitchScreen: {}", screen);
                workspaces.switch_to_screen(ws, config, screen - 1);
            }
            Cmd::MoveToWorkspace(index) => {
                debug!("Cmd::MoveToWorkspace: {}", index);
                workspaces.move_window_to(ws, config, index - 1);
            }
            Cmd::MoveToScreen(screen) => {
                debug!("Cmd::MoveToScreen: {}", screen);
                workspaces.move_window_to_screen(ws, config, screen - 1);
            }
            Cmd::SendLayoutMsg(ref msg) => {
                debug!("Cmd::SendLayoutMsg::{:?}", msg);
                workspaces.current_mut().send_layout_message(msg.clone());
                workspaces.current().redraw(ws, config);
            }
            Cmd::Reload => {
                debug!("Cmd::Reload");
                reload(workspaces)
                    .context("failed to reload xr3wm")?;
            }
            Cmd::Exit => {
                debug!("Cmd::Exit");
                ws.close();
            }
            Cmd::KillClient => {
                debug!("Cmd::KillClient: {}",
                       workspaces.current_mut().focused_window());
                ws.kill_window(workspaces.current_mut().focused_window());
            }
            Cmd::FocusUp => {
                debug!("Cmd::FocusUp: {}", workspaces.current().focused_window());
                workspaces.current_mut().move_focus(ws, config, MoveOp::Up);
            }
            Cmd::FocusDown => {
                debug!("Cmd::FocusDown: {}", workspaces.current().focused_window());
                workspaces.current_mut().move_focus(ws, config, MoveOp::Down);
            }
            Cmd::FocusMaster => {
                debug!("Cmd::FocusMaster: {}",
                       workspaces.current().focused_window());
                workspaces.current_mut().move_focus(ws, config, MoveOp::Swap);
            }
            Cmd::SwapUp => {
                debug!("Cmd::SwapUp: {}", workspaces.current().focused_window());
                workspaces.current_mut().move_window(ws, config, MoveOp::Up);
            }
            Cmd::SwapDown => {
                debug!("Cmd::SwapDown: {}", workspaces.current().focused_window());
                workspaces.current_mut().move_window(ws, config, MoveOp::Down);
            }
            Cmd::SwapMaster => {
                debug!("Cmd::SwapMaster: {}", workspaces.current().focused_window());
                workspaces.current_mut().move_window(ws, config, MoveOp::Swap);
            }
        }
        Ok(())
    }
}

fn reload(workspaces: &mut Workspaces) -> Result<(), Error> {
    let curr_exe = env::current_exe()
        .context("failed to get executable path")?;
    let filename = curr_exe.file_name()
        .ok_or_else(|| err_msg("failed to get executable filename"))?
        .to_str()
        .ok_or_else(|| err_msg("failed to convert filename to UTF-8"))?;

    info!("recompiling...");

    let config_build_dir = concat!(env!("HOME"), "/.xr3wm/.build");
    let mut cmd = Command::new("cargo");

    let output = cmd.current_dir(&config_build_dir)
        .arg("build")
        .env("RUST_LOG", "none")
        .output()
        .context("failed to run cargo")?;

    if !output.status.success() {
        let stderr_msg = String::from_utf8(output.stderr)
            .context("failed to convert cargo stderr to UTF-8")?;
        bail!(format_err!("failed to recompile: {}", stderr_msg))
    }

    debug!("Cmd::Reload: restarting xr3wm...");

    let filename = CString::new(filename.as_bytes())
        .context("failed to convert filename to CString")?;
    let args : &mut [*const i8; 2] = &mut [
        filename.as_ptr() as *const i8,
        null()
    ];

    let path = Path::new(concat!(env!("HOME"), "/.xr3wm/.tmp"));

    // save current workspace state to load on restart
    let mut file = OpenOptions::new()
        .create(true)
        .write(true)
        .truncate(true)
        .open(&path)
        .context("failed to open workspace state tmp file")?;
    file.write_all(workspaces.serialize().as_bytes())
        .context("failed to save workspace state")?;
    file.flush()
        .context("failed to flush workspace tmp file")?;

    let curr_exe_str = CString::new(curr_exe.to_str()
        .ok_or_else(|| err_msg("failed to convert executable path to UTF-8"))?
        .as_bytes())
        .context("failed to convert executable path to CString")?;

    unsafe {
        execvp(curr_exe_str.as_ptr() as *const i8, args.as_mut_ptr());
    }
    Ok(())
}

pub struct ManageHook {
    pub class_name: String,
    pub cmd: CmdManage,
}

pub enum CmdManage {
    Move(usize),
    Float,
    Fullscreen,
    Ignore,
}

impl CmdManage {
    pub fn call(&self,
                ws: &XlibWindowSystem,
                workspaces: &mut Workspaces,
                config: &Config,
                window: Window) {
        match *self {
            CmdManage::Move(index) => {
                if let Some(parent) = ws.transient_for(window) {
                    if let Some(workspace) = workspaces.find_window(parent) {
                        workspace.add_window(ws, config, window);
                        workspace.focus_window(ws, config, window);
                    }
                } else {
                    debug!("CmdManage::Move: {}, {}", window, index);
                    workspaces.get_mut(index - 1).add_window(ws, config, window);
                    workspaces.get_mut(index - 1).focus_window(ws, config, window);
                }
            }
            CmdManage::Float => {
                debug!("CmdManage::Float");
                unimplemented!()
            }
            CmdManage::Fullscreen => {
                debug!("CmdManage::Fullscreen");
                unimplemented!()
            }
            CmdManage::Ignore => {
                debug!("CmdManage::Ignore");
                unimplemented!()
            }
        }
    }
}

fn exec(cmd: String) {
    thread::spawn(move || {
        let args: Vec<&str> = cmd[..].split(' ').collect();

        if !args.is_empty() {
            let mut cmd = Command::new(args[0]);

            if args.len() > 1 {
                cmd.args(&args[1..]);
            }

            match cmd.output() {
                Ok(_) => (),
                _ => panic!("failed to start \"{:?}\"", cmd),
            }
        }
    });
}
<|endoftext|>


<commit_before><commit_msg>Add boilerplate for retrieve hook<commit_after>use toml::Value;

use libimagstore::storeid::StoreId;
use libimagstore::hook::Hook;
use libimagstore::hook::result::HookResult;
use libimagstore::hook::position::HookPosition;
use libimagstore::hook::accessor::{HookDataAccessor, HookDataAccessorProvider};
use libimagstore::hook::accessor::StoreIdAccessor;

#[derive(Debug)]
pub struct RetrieveHook {
    position: HookPosition,
    config: Option<Value>,
}

impl RetrieveHook {

    pub fn new(p: HookPosition) -> RetrieveHook {
        RetrieveHook {
            position: p,
            config: None,
        }
    }

}

impl Hook for RetrieveHook {

    fn name(&self) -> &'static str {
        "stdhook_git_retrieve"
    }

    fn set_config(&mut self, config: &Value) {
        self.config = Some(config.clone());
    }

}

impl HookDataAccessorProvider for RetrieveHook {

    fn accessor(&self) -> HookDataAccessor {
        HookDataAccessor::StoreIdAccess(self)
    }
}

impl StoreIdAccessor for RetrieveHook {

    fn access(&self, id: &StoreId) -> HookResult<()> {
        debug!("[GIT RETRIEVE HOOK]: {:?}", id);
        Ok(())
    }

}

<|endoftext|>


<commit_before>fn main() {
    let needle = 42;
    let haystack = [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862];

    for reference in haystack.iter() {
        if reference == &needle {
            println!("{}", reference)
        }
    }
    println!("");

    let three = 0b11;
    let thirty = 0o36;
    let three_hundred = 0x12C;

    println!("{} {} {}", three, thirty, three_hundred);
    println!("{:b} {:b} {:b}", three, thirty, three_hundred);
    println!("{:o} {:o} {:o}", three, thirty, three_hundred);
    println!("{:x} {:x} {:x}", three, thirty, three_hundred);
    println!("");

    let twenty = 20;
    let twenty_one: i32 = twenty + 1;
    let floats_okay = 21.0;
    let one_million = 1_000_000;

    println!("{}; {}; {}; {}", twenty, twenty_one, floats_okay, one_million);
    println!("");

    let a = 10;
    let b: i32 = 20;

    let c = add(a, b);
    println!("a + b = {}", c);
}

fn add(i: i32, j: i32) -> i32 {
    i + j
}
<commit_msg>using match<commit_after>fn main() {
    let haystack = [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862];

    for reference in haystack.iter() {
        let item = *reference;

        let result = match item {
            42 | 132 => "hit!",
            _ => "miss",
        };

        if result == "hit!" {
            println!("{}: {}", item, result);
        }
    }
    println!("");

    let three = 0b11;
    let thirty = 0o36;
    let three_hundred = 0x12C;

    println!("{} {} {}", three, thirty, three_hundred);
    println!("{:b} {:b} {:b}", three, thirty, three_hundred);
    println!("{:o} {:o} {:o}", three, thirty, three_hundred);
    println!("{:x} {:x} {:x}", three, thirty, three_hundred);
    println!("");

    let twenty = 20;
    let twenty_one: i32 = twenty + 1;
    let floats_okay = 21.0;
    let one_million = 1_000_000;

    println!("{}; {}; {}; {}", twenty, twenty_one, floats_okay, one_million);
    println!("");

    let a = 10;
    let b: i32 = 20;

    let c = add(a, b);
    println!("a + b = {}", c);
}

fn add(i: i32, j: i32) -> i32 {
    i + j
}
<|endoftext|>


<commit_before>use syntax::{abi, ast, ast_util, codemap, parse};
use syntax::parse::token;
use syntax::ptr::P;
use syntax::ext::base;
use syntax::ext::build::AstBuilder;

static BEFORE_EACH: &'static str = "before_each";
static AFTER_EACH:  &'static str = "after_each";
static BEFORE:      &'static str = "before";
static AFTER:       &'static str = "after";
static IT:          &'static str = "it";
static DESCRIBE:    &'static str = "describe";

/// Defines the state of a `describe!` macro as it is parsing.
struct DescribeState {
    name: Option<ast::Ident>,
    before: Option<P<ast::Block>>,
    after: Option<P<ast::Block>>,
    before_each: Option<P<ast::Block>>,
    after_each: Option<P<ast::Block>>,
    subblocks: Vec<SubBlock>
}

enum SubBlock {
    TestBlock(Test),
    DescribeBlock(P<ast::Item>)
}

/// A test as a description and associated block.
struct Test {
    description: String,
    block: P<ast::Block>
}

/// Defines the overarching `describe!` syntax extension.
///
/// All other macros in stainless are actually "fake" in the sense
/// that they are detected and expanded inside of the implementation
/// of `describe!`.
pub fn describe<'a>(cx: &'a mut base::ExtCtxt, _: codemap::Span,
                name: ast::Ident, tokens: Vec<ast::TokenTree>) -> Box<base::MacResult + 'a> {
    // Parse a full DescribeState from the input, emitting errors if used incorrectly.
    let state = parse_describe(&mut parse::tts_to_parser(cx.parse_sess(), tokens, cx.cfg()), cx, Some(name));

    // Export the new module.
    base::MacItems::new(Some(create_describe_item(state, cx)).into_iter())
}

fn create_describe_item(state: DescribeState, cx: &mut base::ExtCtxt) -> P<ast::Item> {
    // Get the name of this mod.
    let name = state.name.clone().unwrap();

    // Create subblocks from a full DescribeState
    let subblocks = create_subblocks(state, cx);

    // Get a glob import of all items in scope to the module that `describe!` is called from.
    //
    // This glob is `pub use super::*` so that nested `describe!` blocks (which will also contain
    // this glob) will be able to see all the symbols.
    let super_glob = cx.view_use_glob(codemap::DUMMY_SP, ast::Public, vec![cx.ident_of("super")]);

    // Generate the new module.
    cx.item_mod(codemap::DUMMY_SP, codemap::DUMMY_SP, name, vec![], vec![super_glob], subblocks)
}

fn create_subblocks(state: DescribeState, cx: &mut base::ExtCtxt) -> Vec<P<ast::Item>> {
    // FIXME(reem): Implement before and after.
    let (_before, _after) = (state.before, state.after);

    let (before_each, after_each) = (state.before_each, state.after_each);
    let subblocks = state.subblocks;

    // Create the #[test] attribute.
    let test_attribute = cx.attribute(codemap::DUMMY_SP,
                                      cx.meta_word(codemap::DUMMY_SP, token::InternedString::new("test")));

    subblocks.into_iter().map(|block| {
        match block {
            TestBlock(Test { description, block }) => {
                // Create the full test body by splicing in the statements and view items of the before and
                // after blocks if they are present.
                let test_body = match (&before_each, &after_each) {
                    (&None, &None) => block,

                    (&Some(ref before), &None) => {
                        P(ast::Block {
                            view_items: before.view_items + block.view_items,
                            stmts: before.stmts + block.stmts,
                            ..block.deref().clone()
                        })
                    },

                    (&None, &Some(ref after)) => {
                        P(ast::Block {
                            view_items: block.view_items + after.view_items,
                            stmts: block.stmts + after.stmts,
                            ..block.deref().clone()
                        })
                    },

                    (&Some(ref before), &Some(ref after)) => {
                        P(ast::Block {
                            view_items: before.view_items + block.view_items + after.view_items,
                            stmts: before.stmts + block.stmts + after.stmts,
                            ..block.deref().clone()
                        })
                    }
                };

                // Create the final Item that represents the test.
                P(ast::Item {
                    // Name it with a snake_case version of the description.
                    ident: cx.ident_of(description.replace(" ", "_").as_slice()),

                    // Add #[test]
                    attrs: vec![test_attribute.clone()],
                    id: ast::DUMMY_NODE_ID,
                    node: ast::ItemFn(
                        // Takes no arguments and returns ()
                        cx.fn_decl(vec![], cx.ty_nil()),

                        // All the usual types.
                        ast::NormalFn,
                        abi::Rust,
                        ast_util::empty_generics(),

                        // Add the body of the function.
                        test_body
                    ),
                    // Inherited visibility (not pub)
                    vis: ast::Inherited,
                    span: codemap::DUMMY_SP
                })
            },
            DescribeBlock(item) => item
        }
    }).collect()
}

fn parse_describe(parser: &mut parse::parser::Parser, cx: &mut base::ExtCtxt, name: Option<ast::Ident>) -> DescribeState {
    let mut state = DescribeState {
        name: None, before: None, after: None,
        before_each: None, after_each: None, subblocks: vec![]
    };

    state.name = match name {
        // Top-level describe block.
        Some(name) => Some(name),
        // Nested describe block.
        None => {
            // Get the name of this describe block
            let name = parser.parse_ident();
            // Move past the opening {
            if token::LBRACE != parser.bump_and_get() {
                parser.fatal("Expected { after the name of a describe! block.");
            }
            Some(name)
        }
    };

    // Now parse all tests and subsections:
    while parser.token != token::RBRACE && parser.token != token::EOF {
        // Get the name of this block, must be either:
        //     - before_each
        //     - after_each
        //     - before
        //     - after
        //     - it
        //     - describe!
        //
        // Any other top-level idents are not allowed.
        let block_name = parser.parse_ident();

        match block_name.as_str() {
            BEFORE_EACH => {
                if state.before_each.is_some() { parser.fatal("Only one `before_each` block is allowed per `describe!` block.") }
                state.before_each = Some(parser.parse_block());
            },

            AFTER_EACH => {
                if state.after_each.is_some() { parser.fatal("Only one `after_each` block is allowed per `describe!` block.") }
                state.after_each = Some(parser.parse_block());
            },

            BEFORE => {
                if state.before.is_some() { parser.fatal("Only one `before` block is allowed per `describe!` block.") }
                state.before = Some(parser.parse_block());
            },

            AFTER => {
                if state.after.is_some() { parser.fatal("Only one `after` block is allowed per `describe!` block.") }
                state.after = Some(parser.parse_block());
            },

            IT => {
                // Description of this `it` block.
                let (description, _) = parser.parse_str();

                state.subblocks.push(TestBlock(Test {
                    // Get as a String
                    description: description.get().to_string(),

                    // The associated block
                    block: parser.parse_block()
                }));
            },

            // Nested `describe!` block.
            DESCRIBE => {
                // Skip over the !
                match parser.bump_and_get() {
                    token::NOT => {},
                    other => parser.fatal(format!("Expected ! but found `{}`", other).as_slice())
                };

                // Parse this sublock, generate new item.
                state.subblocks.push(DescribeBlock(create_describe_item(parse_describe(parser, cx, None), cx)));

                // Move past closing bracket and paren.
                //
                // This has to go in here because it two is EOF on the highest-level invocation.
                match parser.bump_and_get() {
                    token::RBRACE => {},
                    other => parser.fatal(format!("Expected }} to close `describe!` but found: `{}`", other).as_slice())
                }
            }

            banned => {
                // Illegal block name.
                let span = parser.span;
                parser.span_fatal(span, format!("Expected one of: `{}`, but found: `{}`",
                    format!("{}, {}, {}, {}, {}", BEFORE_EACH, AFTER_EACH, BEFORE, AFTER, IT).as_slice(),
                    banned).as_slice());
            }
        }
    }

    state
}

<commit_msg>(fix) Use the passed-in span instead of DUMMY_SP.<commit_after>use syntax::{abi, ast, ast_util, codemap, parse};
use syntax::parse::token;
use syntax::ptr::P;
use syntax::ext::base;
use syntax::ext::build::AstBuilder;

static BEFORE_EACH: &'static str = "before_each";
static AFTER_EACH:  &'static str = "after_each";
static BEFORE:      &'static str = "before";
static AFTER:       &'static str = "after";
static IT:          &'static str = "it";
static DESCRIBE:    &'static str = "describe";

/// Defines the state of a `describe!` macro as it is parsing.
struct DescribeState {
    name: Option<ast::Ident>,
    before: Option<P<ast::Block>>,
    after: Option<P<ast::Block>>,
    before_each: Option<P<ast::Block>>,
    after_each: Option<P<ast::Block>>,
    subblocks: Vec<SubBlock>
}

enum SubBlock {
    TestBlock(Test),
    DescribeBlock(P<ast::Item>)
}

/// A test as a description and associated block.
struct Test {
    description: String,
    block: P<ast::Block>
}

/// Defines the overarching `describe!` syntax extension.
///
/// All other macros in stainless are actually "fake" in the sense
/// that they are detected and expanded inside of the implementation
/// of `describe!`.
pub fn describe<'a>(cx: &'a mut base::ExtCtxt, sp: codemap::Span,
                name: ast::Ident, tokens: Vec<ast::TokenTree>) -> Box<base::MacResult + 'a> {
    // Parse a full DescribeState from the input, emitting errors if used incorrectly.
    let state = parse_describe(&mut parse::tts_to_parser(cx.parse_sess(), tokens, cx.cfg()), sp, cx, Some(name));

    // Export the new module.
    base::MacItems::new(Some(create_describe_item(state, sp, cx)).into_iter())
}

fn create_describe_item(state: DescribeState, sp: codemap::Span, cx: &mut base::ExtCtxt) -> P<ast::Item> {
    // Get the name of this mod.
    let name = state.name.clone().unwrap();

    // Create subblocks from a full DescribeState
    let subblocks = create_subblocks(state, sp, cx);

    // Get a glob import of all items in scope to the module that `describe!` is called from.
    //
    // This glob is `pub use super::*` so that nested `describe!` blocks (which will also contain
    // this glob) will be able to see all the symbols.
    let super_glob = cx.view_use_glob(sp, ast::Public, vec![cx.ident_of("super")]);

    // Generate the new module.
    cx.item_mod(sp, sp, name, vec![], vec![super_glob], subblocks)
}

fn create_subblocks(state: DescribeState, sp: codemap::Span, cx: &mut base::ExtCtxt) -> Vec<P<ast::Item>> {
    // FIXME(reem): Implement before and after.
    let (_before, _after) = (state.before, state.after);

    let (before_each, after_each) = (state.before_each, state.after_each);
    let subblocks = state.subblocks;

    // Create the #[test] attribute.
    let test_attribute = cx.attribute(sp,
                                      cx.meta_word(sp, token::InternedString::new("test")));

    subblocks.into_iter().map(|block| {
        match block {
            TestBlock(Test { description, block }) => {
                // Create the full test body by splicing in the statements and view items of the before and
                // after blocks if they are present.
                let test_body = match (&before_each, &after_each) {
                    (&None, &None) => block,

                    (&Some(ref before), &None) => {
                        P(ast::Block {
                            view_items: before.view_items + block.view_items,
                            stmts: before.stmts + block.stmts,
                            ..block.deref().clone()
                        })
                    },

                    (&None, &Some(ref after)) => {
                        P(ast::Block {
                            view_items: block.view_items + after.view_items,
                            stmts: block.stmts + after.stmts,
                            ..block.deref().clone()
                        })
                    },

                    (&Some(ref before), &Some(ref after)) => {
                        P(ast::Block {
                            view_items: before.view_items + block.view_items + after.view_items,
                            stmts: before.stmts + block.stmts + after.stmts,
                            ..block.deref().clone()
                        })
                    }
                };

                // Create the final Item that represents the test.
                P(ast::Item {
                    // Name it with a snake_case version of the description.
                    ident: cx.ident_of(description.replace(" ", "_").as_slice()),

                    // Add #[test]
                    attrs: vec![test_attribute.clone()],
                    id: ast::DUMMY_NODE_ID,
                    node: ast::ItemFn(
                        // Takes no arguments and returns ()
                        cx.fn_decl(vec![], cx.ty_nil()),

                        // All the usual types.
                        ast::NormalFn,
                        abi::Rust,
                        ast_util::empty_generics(),

                        // Add the body of the function.
                        test_body
                    ),
                    // Inherited visibility (not pub)
                    vis: ast::Inherited,
                    span: sp
                })
            },
            DescribeBlock(item) => item
        }
    }).collect()
}

fn parse_describe(parser: &mut parse::parser::Parser, sp: codemap::Span,
                  cx: &mut base::ExtCtxt, name: Option<ast::Ident>) -> DescribeState {
    let mut state = DescribeState {
        name: None, before: None, after: None,
        before_each: None, after_each: None, subblocks: vec![]
    };

    state.name = match name {
        // Top-level describe block.
        Some(name) => Some(name),
        // Nested describe block.
        None => {
            // Get the name of this describe block
            let name = parser.parse_ident();
            // Move past the opening {
            if token::LBRACE != parser.bump_and_get() {
                parser.fatal("Expected { after the name of a describe! block.");
            }
            Some(name)
        }
    };

    // Now parse all tests and subsections:
    while parser.token != token::RBRACE && parser.token != token::EOF {
        // Get the name of this block, must be either:
        //     - before_each
        //     - after_each
        //     - before
        //     - after
        //     - it
        //     - describe!
        //
        // Any other top-level idents are not allowed.
        let block_name = parser.parse_ident();

        match block_name.as_str() {
            BEFORE_EACH => {
                if state.before_each.is_some() { parser.fatal("Only one `before_each` block is allowed per `describe!` block.") }
                state.before_each = Some(parser.parse_block());
            },

            AFTER_EACH => {
                if state.after_each.is_some() { parser.fatal("Only one `after_each` block is allowed per `describe!` block.") }
                state.after_each = Some(parser.parse_block());
            },

            BEFORE => {
                if state.before.is_some() { parser.fatal("Only one `before` block is allowed per `describe!` block.") }
                state.before = Some(parser.parse_block());
            },

            AFTER => {
                if state.after.is_some() { parser.fatal("Only one `after` block is allowed per `describe!` block.") }
                state.after = Some(parser.parse_block());
            },

            IT => {
                // Description of this `it` block.
                let (description, _) = parser.parse_str();

                state.subblocks.push(TestBlock(Test {
                    // Get as a String
                    description: description.get().to_string(),

                    // The associated block
                    block: parser.parse_block()
                }));
            },

            // Nested `describe!` block.
            DESCRIBE => {
                // Skip over the !
                match parser.bump_and_get() {
                    token::NOT => {},
                    other => parser.fatal(format!("Expected ! but found `{}`", other).as_slice())
                };

                // Parse this sublock, generate new item.
                state.subblocks.push(DescribeBlock(create_describe_item(parse_describe(parser, sp, cx, None), sp, cx)));

                // Move past closing bracket and paren.
                //
                // This has to go in here because it two is EOF on the highest-level invocation.
                match parser.bump_and_get() {
                    token::RBRACE => {},
                    other => parser.fatal(format!("Expected }} to close `describe!` but found: `{}`", other).as_slice())
                }
            }

            banned => {
                // Illegal block name.
                let span = parser.span;
                parser.span_fatal(span, format!("Expected one of: `{}`, but found: `{}`",
                    format!("{}, {}, {}, {}, {}", BEFORE_EACH, AFTER_EACH, BEFORE, AFTER, IT).as_slice(),
                    banned).as_slice());
            }
        }
    }

    state
}

<|endoftext|>


<commit_before>use super::content::Content;
use super::encodings::{self, bytes_to_string, string_to_bytes};
use super::{Dictionary, Object, ObjectId};
use crate::xref::Xref;
use crate::{Error, Result};
use encoding::all::UTF_16BE;
use encoding::types::{DecoderTrap, EncoderTrap, Encoding};
use log::info;
use std::collections::BTreeMap;
use std::cmp::max;
use std::io::Write;
use std::str;

/// PDF document.
#[derive(Debug, Clone)]
pub struct Document {
	/// The version of the PDF specification to which the file conforms.
	pub version: String,

	/// The trailer gives the location of the cross-reference table and of certain special objects.
	pub trailer: Dictionary,

	/// The cross-reference table contains locations of the indirect objects.
	pub reference_table: Xref,

	/// The objects that make up the document contained in the file.
	pub objects: BTreeMap<ObjectId, Object>,

	/// Current maximum object id within the document.
	pub max_id: u32,
}

impl Document {
	/// Create new PDF document.
	pub fn new() -> Document {
		Document {
			version: "1.4".to_string(),
			trailer: Dictionary::new(),
			reference_table: Xref::new(0),
			objects: BTreeMap::new(),
			max_id: 0,
		}
	}

	const DEREF_LIMIT : usize = 128;

	/// Follow references if the supplied object is a reference.
	///
	/// Returns a tuple of an optional object id and final object.
	/// The object id will be None if the object was not a
	/// reference. Otherwise, it will be the last object id in the
	/// reference chain.
	pub fn dereference<'a>(&'a self, mut object: &'a Object) -> Result<(Option<ObjectId>, &'a Object)> {
		let mut nb_deref = 0;
		let mut id = None;

		while let Ok(ref_id) = object.as_reference() {
			id = Some(ref_id);
			object = self.objects.get(&ref_id).ok_or(Error::ObjectNotFound)?;

			nb_deref += 1;
			if nb_deref > Self::DEREF_LIMIT {
				return Err(Error::ReferenceLimit);
			}
		}

		Ok((id, object))
	}

	/// Get object by object id, will iteratively dereference a referenced object.
	pub fn get_object(&self, id: ObjectId) -> Result<&Object> {
		let object = self.objects.get(&id).ok_or(Error::ObjectNotFound)?;
		self.dereference(object).map(|(_, object)| object)
	}

	/// Get mutable reference to object by object id, will iteratively dereference a referenced object.
	pub fn get_object_mut(&mut self, id: ObjectId) -> Result<&mut Object> {
		let object = self.objects.get(&id).ok_or(Error::ObjectNotFound)?;
		let (ref_id, _) = self.dereference(object)?;

		Ok(self.objects.get_mut(&ref_id.unwrap_or(id)).unwrap())
	}

	/// Get dictionary object by id.
	pub fn get_dictionary(&self, id: ObjectId) -> Result<&Dictionary> {
		self.get_object(id).and_then(Object::as_dict)
	}

	/// Traverse objects from trailer recursively, return all referenced object IDs.
	pub fn traverse_objects<A: Fn(&mut Object) -> ()>(&mut self, action: A) -> Vec<ObjectId> {
		fn traverse_array<A: Fn(&mut Object) -> ()>(array: &mut Vec<Object>, action: &A, refs: &mut Vec<ObjectId>) {
			for item in array.iter_mut() {
				traverse_object(item, action, refs);
			}
		}
		fn traverse_dictionary<A: Fn(&mut Object) -> ()>(dict: &mut Dictionary, action: &A, refs: &mut Vec<ObjectId>) {
			for (_, v) in dict.iter_mut() {
				traverse_object(v, action, refs);
			}
		}
		fn traverse_object<A: Fn(&mut Object) -> ()>(object: &mut Object, action: &A, refs: &mut Vec<ObjectId>) {
			action(object);
			match *object {
				Object::Array(ref mut array) => traverse_array(array, action, refs),
				Object::Dictionary(ref mut dict) => traverse_dictionary(dict, action, refs),
				Object::Stream(ref mut stream) => traverse_dictionary(&mut stream.dict, action, refs),
				Object::Reference(id) => {
					if !refs.contains(&id) {
						refs.push(id);
					}
				}
				_ => {}
			}
		}
		let mut refs = vec![];
		traverse_dictionary(&mut self.trailer, &action, &mut refs);
		let mut index = 0;
		while index < refs.len() {
			if let Some(object) = self.objects.get_mut(&refs[index]) {
				traverse_object(object, &action, &mut refs);
			}
			index += 1;
		}
		refs
	}

	/// Get catalog dictionary.
	pub fn catalog(&self) -> Result<&Dictionary> {
		self.trailer.get(b"Root").and_then(Object::as_reference).and_then(|id| self.get_dictionary(id))
	}

	/// Get page numbers and corresponding object ids.
	pub fn get_pages(&self) -> BTreeMap<u32, ObjectId> {
		self.page_iter().enumerate().map(|(i, p)| ((i+1) as u32, p)).collect()
	}

	pub fn page_iter(&self) -> impl Iterator<Item=ObjectId> + '_ {
		PageTreeIter::new(self)
	}

	/// Get content stream object ids of a page.
	pub fn get_page_contents(&self, page_id: ObjectId) -> Vec<ObjectId> {
		let mut streams = vec![];
		if let Ok(page) = self.get_dictionary(page_id) {
			if let Ok(contents) = page.get(b"Contents") {
				match *contents {
					Object::Reference(ref id) => {
						streams.push(*id);
					}
					Object::Array(ref arr) => {
						for content in arr {
							if let Ok(id) = content.as_reference() { streams.push(id) }
						}
					}
					_ => {}
				}
			}
		}
		streams
	}

	/// Get content of a page.
	pub fn get_page_content(&self, page_id: ObjectId) -> Result<Vec<u8>> {
		let mut content = Vec::new();
		let content_streams = self.get_page_contents(page_id);
		for object_id in content_streams {
			if let Ok(content_stream) = self.get_object(object_id).and_then(Object::as_stream) {
				match content_stream.decompressed_content() {
					Ok(data) => content.write_all(&data)?,
					Err(_) => content.write_all(&content_stream.content)?,
				};
			}
		}
		Ok(content)
	}

	/// Get decoded page content;
	pub fn get_and_decode_page_content(&self, page_id: ObjectId) -> Result<Content> {
		let content_data = self.get_page_content(page_id)?;
		Content::decode(&content_data)
	}

	/// Get resources used by a page.
	pub fn get_page_resources(&self, page_id: ObjectId) -> (Option<&Dictionary>, Vec<ObjectId>) {
		fn collect_resources(page_node: &Dictionary, resource_ids: &mut Vec<ObjectId>, doc: &Document) {
			if let Ok(resources_id) = page_node.get(b"Resources").and_then(Object::as_reference) {
				resource_ids.push(resources_id);
			}
			if let Ok(page_tree) = page_node.get(b"Parent").and_then(Object::as_reference).and_then(|id| doc.get_dictionary(id)) {
				collect_resources(page_tree, resource_ids, doc);
			}
		};

		let mut resource_dict = None;
		let mut resource_ids = Vec::new();
		if let Ok(page) = self.get_dictionary(page_id) {
			resource_dict = page.get(b"Resources").and_then(Object::as_dict).ok();
			collect_resources(page, &mut resource_ids, self);
		}
		(resource_dict, resource_ids)
	}

	/// Get fonts used by a page.
	pub fn get_page_fonts(&self, page_id: ObjectId) -> BTreeMap<Vec<u8>, &Dictionary> {
		fn collect_fonts_from_resources<'a>(resources: &'a Dictionary, fonts: &mut BTreeMap<Vec<u8>, &'a Dictionary>, doc: &'a Document) {
			if let Ok(font_dict) = resources.get(b"Font").and_then(Object::as_dict) {
				for (name, value) in font_dict.iter() {
					let font = match *value {
						Object::Reference(id) => doc.get_dictionary(id).ok(),
						Object::Dictionary(ref dict) => Some(dict),
						_ => None,
					};
					if !fonts.contains_key(name) {
						font.map(|font| fonts.insert(name.clone(), font));
					}
				}
			}
		};

		let mut fonts = BTreeMap::new();
		let (resource_dict, resource_ids) = self.get_page_resources(page_id);
		if let Some(resources) = resource_dict {
			collect_fonts_from_resources(resources, &mut fonts, self);
		}
		for resource_id in resource_ids {
			if let Ok(resources) = self.get_dictionary(resource_id) {
				collect_fonts_from_resources(resources, &mut fonts, self);
			}
		}
		fonts
	}

	pub fn decode_text(encoding: Option<&str>, bytes: &[u8]) -> String {
		if let Some(encoding) = encoding {
			info!("{}", encoding);
			match encoding {
				"StandardEncoding" => bytes_to_string(encodings::STANDARD_ENCODING, bytes),
				"MacRomanEncoding" => bytes_to_string(encodings::MAC_ROMAN_ENCODING, bytes),
				"MacExpertEncoding" => bytes_to_string(encodings::MAC_EXPERT_ENCODING, bytes),
				"WinAnsiEncoding" => bytes_to_string(encodings::WIN_ANSI_ENCODING, bytes),
				"UniGB-UCS2-H" | "UniGB−UTF16−H" => UTF_16BE.decode(bytes, DecoderTrap::Ignore).unwrap(),
				"Identity-H" => "?Identity-H Unimplemented?".to_string(), // Unimplemented
				_ => String::from_utf8_lossy(bytes).to_string(),
			}
		} else {
			bytes_to_string(encodings::STANDARD_ENCODING, bytes)
		}
	}

	pub fn encode_text(encoding: Option<&str>, text: &str) -> Vec<u8> {
		if let Some(encoding) = encoding {
			match encoding {
				"StandardEncoding" => string_to_bytes(encodings::STANDARD_ENCODING, text),
				"MacRomanEncoding" => string_to_bytes(encodings::MAC_ROMAN_ENCODING, text),
				"MacExpertEncoding" => string_to_bytes(encodings::MAC_EXPERT_ENCODING, text),
				"WinAnsiEncoding" => string_to_bytes(encodings::WIN_ANSI_ENCODING, text),
				"UniGB-UCS2-H" | "UniGB−UTF16−H" => UTF_16BE.encode(text, EncoderTrap::Ignore).unwrap(),
				"Identity-H" => vec![], // Unimplemented
				_ => text.as_bytes().to_vec(),
			}
		} else {
			string_to_bytes(encodings::STANDARD_ENCODING, text)
		}
	}
}

impl Default for Document {
	fn default() -> Self {
		Self::new()
	}
}

struct PageTreeIter<'a> {
	doc: &'a Document,
	stack: Vec<&'a [Object]>,
	kids: Option<&'a [Object]>,
}

impl <'a> PageTreeIter<'a> {
	const PAGE_TREE_DEPTH_LIMIT: usize = 256;

	fn new(doc: &'a Document) -> Self {
		if let Ok(page_tree_id) = doc.catalog().and_then(|cat| cat.get(b"Pages")).and_then(Object::as_reference) {
			Self { doc, kids: Self::kids(doc, page_tree_id), stack: Vec::with_capacity(32) }
		} else {
			Self { doc, kids: None, stack: Vec::new() }
		}
	}

	fn kids(doc: &Document, page_tree_id: ObjectId) -> Option<&[Object]> {
		doc.get_dictionary(page_tree_id).and_then(|page_tree| page_tree.get(b"Kids")).and_then(Object::as_array).map(|k| k.as_slice()).ok()
	}
}

impl Iterator for PageTreeIter<'_> {
	type Item = ObjectId;

	fn next(&mut self) -> Option<Self::Item> {
		loop {
			while let Some((kid, new_kids)) = self.kids.and_then(|k| k.split_first()) {
				self.kids = Some(new_kids);

				if let Ok(kid_id) = kid.as_reference() {
					if let Ok(type_name) = self.doc.get_dictionary(kid_id).and_then(Dictionary::type_name) {
						match type_name {
							"Page" => {
								return Some(kid_id);
							},
							"Pages" => {
								if self.stack.len() < Self::PAGE_TREE_DEPTH_LIMIT {
									let kids = self.kids.unwrap();
									if !kids.is_empty() {
										self.stack.push(kids);
									}
									self.kids = Self::kids(self.doc, kid_id);
								}
							},
							_ => {}
						}
					}
				}
			}

			// Current level exhausted, try to pop.
			if let kids @ Some(_) = self.stack.pop() {
				self.kids = kids;
			} else {
				return None;
			}
		}
	}

	fn size_hint(&self) -> (usize, Option<usize>) {
		let kids = self.kids.unwrap_or(&[]);

		let nb_pages: usize = kids.iter().chain(self.stack.iter().flat_map(|k| k.iter())).map(|kid| {
			if let Ok(dict) = kid.as_reference().and_then(|id| self.doc.get_dictionary(id)) {
				if let Ok("Pages") = dict.type_name() {
					let count = dict.get_deref(b"Count", self.doc).and_then(Object::as_i64).unwrap_or(0);
					// Don't let page count go backwards in case of an invalid document.
					max(0, count) as usize
				} else {
					1
				}
			} else {
				1
			}
		}).sum();

		(nb_pages, Some(nb_pages))
	}
}

impl std::iter::FusedIterator for PageTreeIter<'_> {}
<commit_msg>limit recursion to the number of objects (#92)<commit_after>use super::content::Content;
use super::encodings::{self, bytes_to_string, string_to_bytes};
use super::{Dictionary, Object, ObjectId};
use crate::xref::Xref;
use crate::{Error, Result};
use encoding::all::UTF_16BE;
use encoding::types::{DecoderTrap, EncoderTrap, Encoding};
use log::info;
use std::collections::BTreeMap;
use std::cmp::max;
use std::io::Write;
use std::str;

/// PDF document.
#[derive(Debug, Clone)]
pub struct Document {
	/// The version of the PDF specification to which the file conforms.
	pub version: String,

	/// The trailer gives the location of the cross-reference table and of certain special objects.
	pub trailer: Dictionary,

	/// The cross-reference table contains locations of the indirect objects.
	pub reference_table: Xref,

	/// The objects that make up the document contained in the file.
	pub objects: BTreeMap<ObjectId, Object>,

	/// Current maximum object id within the document.
	pub max_id: u32,
}

impl Document {
	/// Create new PDF document.
	pub fn new() -> Document {
		Document {
			version: "1.4".to_string(),
			trailer: Dictionary::new(),
			reference_table: Xref::new(0),
			objects: BTreeMap::new(),
			max_id: 0,
		}
	}

	const DEREF_LIMIT : usize = 128;

	/// Follow references if the supplied object is a reference.
	///
	/// Returns a tuple of an optional object id and final object.
	/// The object id will be None if the object was not a
	/// reference. Otherwise, it will be the last object id in the
	/// reference chain.
	pub fn dereference<'a>(&'a self, mut object: &'a Object) -> Result<(Option<ObjectId>, &'a Object)> {
		let mut nb_deref = 0;
		let mut id = None;

		while let Ok(ref_id) = object.as_reference() {
			id = Some(ref_id);
			object = self.objects.get(&ref_id).ok_or(Error::ObjectNotFound)?;

			nb_deref += 1;
			if nb_deref > Self::DEREF_LIMIT {
				return Err(Error::ReferenceLimit);
			}
		}

		Ok((id, object))
	}

	/// Get object by object id, will iteratively dereference a referenced object.
	pub fn get_object(&self, id: ObjectId) -> Result<&Object> {
		let object = self.objects.get(&id).ok_or(Error::ObjectNotFound)?;
		self.dereference(object).map(|(_, object)| object)
	}

	/// Get mutable reference to object by object id, will iteratively dereference a referenced object.
	pub fn get_object_mut(&mut self, id: ObjectId) -> Result<&mut Object> {
		let object = self.objects.get(&id).ok_or(Error::ObjectNotFound)?;
		let (ref_id, _) = self.dereference(object)?;

		Ok(self.objects.get_mut(&ref_id.unwrap_or(id)).unwrap())
	}

	/// Get dictionary object by id.
	pub fn get_dictionary(&self, id: ObjectId) -> Result<&Dictionary> {
		self.get_object(id).and_then(Object::as_dict)
	}

	/// Traverse objects from trailer recursively, return all referenced object IDs.
	pub fn traverse_objects<A: Fn(&mut Object) -> ()>(&mut self, action: A) -> Vec<ObjectId> {
		fn traverse_array<A: Fn(&mut Object) -> ()>(array: &mut Vec<Object>, action: &A, refs: &mut Vec<ObjectId>) {
			for item in array.iter_mut() {
				traverse_object(item, action, refs);
			}
		}
		fn traverse_dictionary<A: Fn(&mut Object) -> ()>(dict: &mut Dictionary, action: &A, refs: &mut Vec<ObjectId>) {
			for (_, v) in dict.iter_mut() {
				traverse_object(v, action, refs);
			}
		}
		fn traverse_object<A: Fn(&mut Object) -> ()>(object: &mut Object, action: &A, refs: &mut Vec<ObjectId>) {
			action(object);
			match *object {
				Object::Array(ref mut array) => traverse_array(array, action, refs),
				Object::Dictionary(ref mut dict) => traverse_dictionary(dict, action, refs),
				Object::Stream(ref mut stream) => traverse_dictionary(&mut stream.dict, action, refs),
				Object::Reference(id) => {
					if !refs.contains(&id) {
						refs.push(id);
					}
				}
				_ => {}
			}
		}
		let mut refs = vec![];
		traverse_dictionary(&mut self.trailer, &action, &mut refs);
		let mut index = 0;
		while index < refs.len() {
			if let Some(object) = self.objects.get_mut(&refs[index]) {
				traverse_object(object, &action, &mut refs);
			}
			index += 1;
		}
		refs
	}

	/// Get catalog dictionary.
	pub fn catalog(&self) -> Result<&Dictionary> {
		self.trailer.get(b"Root").and_then(Object::as_reference).and_then(|id| self.get_dictionary(id))
	}

	/// Get page numbers and corresponding object ids.
	pub fn get_pages(&self) -> BTreeMap<u32, ObjectId> {
		self.page_iter().enumerate().map(|(i, p)| ((i+1) as u32, p)).collect()
	}

	pub fn page_iter(&self) -> impl Iterator<Item=ObjectId> + '_ {
		PageTreeIter::new(self)
	}

	/// Get content stream object ids of a page.
	pub fn get_page_contents(&self, page_id: ObjectId) -> Vec<ObjectId> {
		let mut streams = vec![];
		if let Ok(page) = self.get_dictionary(page_id) {
			if let Ok(contents) = page.get(b"Contents") {
				match *contents {
					Object::Reference(ref id) => {
						streams.push(*id);
					}
					Object::Array(ref arr) => {
						for content in arr {
							if let Ok(id) = content.as_reference() { streams.push(id) }
						}
					}
					_ => {}
				}
			}
		}
		streams
	}

	/// Get content of a page.
	pub fn get_page_content(&self, page_id: ObjectId) -> Result<Vec<u8>> {
		let mut content = Vec::new();
		let content_streams = self.get_page_contents(page_id);
		for object_id in content_streams {
			if let Ok(content_stream) = self.get_object(object_id).and_then(Object::as_stream) {
				match content_stream.decompressed_content() {
					Ok(data) => content.write_all(&data)?,
					Err(_) => content.write_all(&content_stream.content)?,
				};
			}
		}
		Ok(content)
	}

	/// Get decoded page content;
	pub fn get_and_decode_page_content(&self, page_id: ObjectId) -> Result<Content> {
		let content_data = self.get_page_content(page_id)?;
		Content::decode(&content_data)
	}

	/// Get resources used by a page.
	pub fn get_page_resources(&self, page_id: ObjectId) -> (Option<&Dictionary>, Vec<ObjectId>) {
		fn collect_resources(page_node: &Dictionary, resource_ids: &mut Vec<ObjectId>, doc: &Document) {
			if let Ok(resources_id) = page_node.get(b"Resources").and_then(Object::as_reference) {
				resource_ids.push(resources_id);
			}
			if let Ok(page_tree) = page_node.get(b"Parent").and_then(Object::as_reference).and_then(|id| doc.get_dictionary(id)) {
				collect_resources(page_tree, resource_ids, doc);
			}
		};

		let mut resource_dict = None;
		let mut resource_ids = Vec::new();
		if let Ok(page) = self.get_dictionary(page_id) {
			resource_dict = page.get(b"Resources").and_then(Object::as_dict).ok();
			collect_resources(page, &mut resource_ids, self);
		}
		(resource_dict, resource_ids)
	}

	/// Get fonts used by a page.
	pub fn get_page_fonts(&self, page_id: ObjectId) -> BTreeMap<Vec<u8>, &Dictionary> {
		fn collect_fonts_from_resources<'a>(resources: &'a Dictionary, fonts: &mut BTreeMap<Vec<u8>, &'a Dictionary>, doc: &'a Document) {
			if let Ok(font_dict) = resources.get(b"Font").and_then(Object::as_dict) {
				for (name, value) in font_dict.iter() {
					let font = match *value {
						Object::Reference(id) => doc.get_dictionary(id).ok(),
						Object::Dictionary(ref dict) => Some(dict),
						_ => None,
					};
					if !fonts.contains_key(name) {
						font.map(|font| fonts.insert(name.clone(), font));
					}
				}
			}
		};

		let mut fonts = BTreeMap::new();
		let (resource_dict, resource_ids) = self.get_page_resources(page_id);
		if let Some(resources) = resource_dict {
			collect_fonts_from_resources(resources, &mut fonts, self);
		}
		for resource_id in resource_ids {
			if let Ok(resources) = self.get_dictionary(resource_id) {
				collect_fonts_from_resources(resources, &mut fonts, self);
			}
		}
		fonts
	}

	pub fn decode_text(encoding: Option<&str>, bytes: &[u8]) -> String {
		if let Some(encoding) = encoding {
			info!("{}", encoding);
			match encoding {
				"StandardEncoding" => bytes_to_string(encodings::STANDARD_ENCODING, bytes),
				"MacRomanEncoding" => bytes_to_string(encodings::MAC_ROMAN_ENCODING, bytes),
				"MacExpertEncoding" => bytes_to_string(encodings::MAC_EXPERT_ENCODING, bytes),
				"WinAnsiEncoding" => bytes_to_string(encodings::WIN_ANSI_ENCODING, bytes),
				"UniGB-UCS2-H" | "UniGB−UTF16−H" => UTF_16BE.decode(bytes, DecoderTrap::Ignore).unwrap(),
				"Identity-H" => "?Identity-H Unimplemented?".to_string(), // Unimplemented
				_ => String::from_utf8_lossy(bytes).to_string(),
			}
		} else {
			bytes_to_string(encodings::STANDARD_ENCODING, bytes)
		}
	}

	pub fn encode_text(encoding: Option<&str>, text: &str) -> Vec<u8> {
		if let Some(encoding) = encoding {
			match encoding {
				"StandardEncoding" => string_to_bytes(encodings::STANDARD_ENCODING, text),
				"MacRomanEncoding" => string_to_bytes(encodings::MAC_ROMAN_ENCODING, text),
				"MacExpertEncoding" => string_to_bytes(encodings::MAC_EXPERT_ENCODING, text),
				"WinAnsiEncoding" => string_to_bytes(encodings::WIN_ANSI_ENCODING, text),
				"UniGB-UCS2-H" | "UniGB−UTF16−H" => UTF_16BE.encode(text, EncoderTrap::Ignore).unwrap(),
				"Identity-H" => vec![], // Unimplemented
				_ => text.as_bytes().to_vec(),
			}
		} else {
			string_to_bytes(encodings::STANDARD_ENCODING, text)
		}
	}
}

impl Default for Document {
	fn default() -> Self {
		Self::new()
	}
}

struct PageTreeIter<'a> {
	doc: &'a Document,
	stack: Vec<&'a [Object]>,
	kids: Option<&'a [Object]>,
}

impl <'a> PageTreeIter<'a> {
	const PAGE_TREE_DEPTH_LIMIT: usize = 256;

	fn new(doc: &'a Document) -> Self {
		if let Ok(page_tree_id) = doc.catalog().and_then(|cat| cat.get(b"Pages")).and_then(Object::as_reference) {
			Self { doc, kids: Self::kids(doc, page_tree_id), stack: Vec::with_capacity(32) }
		} else {
			Self { doc, kids: None, stack: Vec::new() }
		}
	}

	fn kids(doc: &Document, page_tree_id: ObjectId) -> Option<&[Object]> {
		doc.get_dictionary(page_tree_id).and_then(|page_tree| page_tree.get(b"Kids")).and_then(Object::as_array).map(|k| k.as_slice()).ok()
	}
}

impl Iterator for PageTreeIter<'_> {
	type Item = ObjectId;

	fn next(&mut self) -> Option<Self::Item> {
		let mut objcount = self.doc.objects.len();
		loop {
			while let Some((kid, new_kids)) = self.kids.and_then(|k| k.split_first()) {
				if objcount == 0 {
					return None;
				}
				objcount -= 1;

				self.kids = Some(new_kids);

				if let Ok(kid_id) = kid.as_reference() {
					if let Ok(type_name) = self.doc.get_dictionary(kid_id).and_then(Dictionary::type_name) {
						match type_name {
							"Page" => {
								return Some(kid_id);
							},
							"Pages" => {
								if self.stack.len() < Self::PAGE_TREE_DEPTH_LIMIT {
									let kids = self.kids.unwrap();
									if !kids.is_empty() {
										self.stack.push(kids);
									}
									self.kids = Self::kids(self.doc, kid_id);
								}
							},
							_ => {}
						}
					}
				}
			}

			// Current level exhausted, try to pop.
			if let kids @ Some(_) = self.stack.pop() {
				self.kids = kids;
			} else {
				return None;
			}
		}
	}

	fn size_hint(&self) -> (usize, Option<usize>) {
		let kids = self.kids.unwrap_or(&[]);

		let nb_pages: usize = kids.iter().chain(self.stack.iter().flat_map(|k| k.iter())).map(|kid| {
			if let Ok(dict) = kid.as_reference().and_then(|id| self.doc.get_dictionary(id)) {
				if let Ok("Pages") = dict.type_name() {
					let count = dict.get_deref(b"Count", self.doc).and_then(Object::as_i64).unwrap_or(0);
					// Don't let page count go backwards in case of an invalid document.
					max(0, count) as usize
				} else {
					1
				}
			} else {
				1
			}
		}).sum();

		(nb_pages, Some(nb_pages))
	}
}

impl std::iter::FusedIterator for PageTreeIter<'_> {}
<|endoftext|>


<commit_before>#![cfg(feature = "interchange")]

use crate::chip::Chip;
use crate::database::Database;
use std::collections::{HashSet, HashMap};

use crate::bba::idstring::*;
use crate::bba::idxset::*;
use crate::bba::tiletype::{Neighbour, TileTypes};

use crate::sites::*;

// A tile type from the interchange format perspective
// this is not the same as a database tile type; because the Oxide graph can have
// more than one tile at a grid location whereas the interchange grid is one tile
// per location

#[derive(Clone, Eq, PartialEq, Hash)]
pub struct TileTypeKey {
    pub tile_types: Vec<String>,
}
impl TileTypeKey {
    pub fn new() -> TileTypeKey {
        TileTypeKey { tile_types: Vec::new() }
    }
}

pub struct IcTileType {
    pub key: TileTypeKey,
    pub wires: IndexedMap<IdString, IcWire>,
    pub pips: Vec<IcPip>,
    pub site_types: Vec<Site>,
    // TODO: constants, sites, etc
}

impl IcTileType {
    pub fn new(key: TileTypeKey, family: &str, db: &mut Database) -> IcTileType {
        let mut site_types = Vec::new();
        for tt in key.tile_types.iter() {
            site_types.extend(build_sites(&tt, &db.tile_bitdb(family, &tt).db));
        }
        IcTileType {
            key: key,
            wires: IndexedMap::new(),
            pips: Vec::new(),
            site_types: site_types,
        }
    }
    pub fn wire(&mut self, name: IdString) -> usize {
        self.wires.add(&name, IcWire::new(name))
    }
    pub fn add_pip(&mut self, src: IdString, dst: IdString) {
        let src_idx = self.wire(src);
        let dst_idx = self.wire(dst);
        self.pips.push(IcPip {
            src_wire: src_idx,
            dst_wire: dst_idx,
        });
    }
}

pub struct IcWire {
    pub name: IdString,
}

impl IcWire {
    pub fn new(name: IdString) -> IcWire {
        IcWire {
            name: name,
        }
    }
}

pub struct IcPip {
    pub src_wire: usize,
    pub dst_wire: usize,
}

// A tile instance
pub struct IcTileInst {
    pub name: IdString,
    pub x: u32,
    pub y: u32,
    pub type_idx: usize,
    // mapping between wires and nodes
    wire_to_node: HashMap<IdString, usize>,
}

impl IcTileInst {
    pub fn new(ids: &mut IdStringDB, x: u32, y: u32) -> IcTileInst {
        IcTileInst {
            name: ids.id(&format!("R{}C{}", y, x)),
            x: x,
            y: y,
            type_idx: 0,
            wire_to_node: HashMap::new(),
        }
    }
}

// A reference to a tile wire
#[derive(Clone, Hash, Eq, PartialEq)]
pub struct IcWireRef {
    pub tile_name: IdString,
    pub wire_name: IdString,
}

// A node instance
pub struct IcNode {
    // list of tile wires in the node
    pub wires: HashSet<IcWireRef>,
    pub root_wire: IcWireRef,
}

impl IcNode {
    pub fn new(root_wire: IcWireRef) -> IcNode {
        IcNode {
            wires: [root_wire.clone()].iter().cloned().collect(),
            root_wire: root_wire,
        }
    }
}

// The overall routing resource graph
pub struct IcGraph {
    pub tile_types: IndexedMap<TileTypeKey, IcTileType>,
    pub tiles: Vec<IcTileInst>,
    pub nodes: Vec<IcNode>,
    pub width: u32,
    pub height: u32,
}

impl IcGraph {
    pub fn new(ids: &mut IdStringDB, width: u32, height: u32) -> IcGraph {
        IcGraph {
            tile_types: IndexedMap::new(),
            tiles: (0..width*height).map(|i| IcTileInst::new(ids, i%width, i/width)).collect(),
            nodes: Vec::new(),
            width: width,
            height: height
        }
    }
    pub fn tile_idx(&self, x: u32, y: u32) -> usize {
        assert!(x < self.width);
        assert!(y < self.height);
        ((y * self.width) + x) as usize
    }
    pub fn tile_at(&mut self, x: u32, y: u32) -> &mut IcTileInst {
        let idx = self.tile_idx(x, y);
        &mut self.tiles[idx]
    }
    pub fn type_at(&mut self, x: u32, y: u32) -> &mut IcTileType {
        let idx = self.tile_at(x, y).type_idx;
        self.tile_types.value_mut(idx)
    }
    pub fn map_node(&mut self, root_x: u32, root_y: u32, root_wire: IdString, wire_x: u32, wire_y: u32, wire: IdString) {
        // Make sure wire exists in both tiles
        self.type_at(root_x, root_y).wire(root_wire);
        self.type_at(wire_x, wire_y).wire(wire);
        // Update wire-node mapping
        let root_tile_idx = self.tile_idx(root_x, root_y);
        let node_idx = match self.tiles[root_tile_idx].wire_to_node.get(&root_wire) {
            Some(i) => *i,
            None => {
                let idx = self.nodes.len();
                self.nodes.push(IcNode::new(IcWireRef { tile_name: self.tiles[root_tile_idx].name, wire_name: root_wire }));
                self.tiles[root_tile_idx].wire_to_node.insert(root_wire, idx);
                idx
            }
        };
        let wire_tile_idx = self.tile_idx(wire_x, wire_y);
        self.nodes[node_idx].wires.insert(IcWireRef {tile_name: self.tiles[wire_tile_idx].name, wire_name: wire });
        self.tiles[wire_tile_idx].wire_to_node.insert(wire, node_idx);
    }
}

pub struct GraphBuilder<'a> {
    g: IcGraph,
    ids: &'a mut IdStringDB,
    chip: &'a Chip,
    db: &'a mut Database,
    tiletypes_by_xy: HashMap<(u32, u32), TileTypeKey>,
    orig_tts: TileTypes,
}

impl <'a> GraphBuilder<'a> {
    fn new(ids: &'a mut IdStringDB, chip: &'a Chip, db: &'a mut Database) -> GraphBuilder<'a> {
        let mut width = 0;
        let mut height = 0;
        let mut tiletypes_by_xy = HashMap::new();
        for t in chip.tiles.iter() {
            tiletypes_by_xy.entry((t.x, t.y)).or_insert(TileTypeKey::new()).tile_types.push(t.tiletype.to_string());
            width = std::cmp::max(width, t.x + 1);
            height = std::cmp::max(height, t.y + 1);
        }

        let orig_tts = TileTypes::new(db, ids, &chip.family, &[&chip.device]);

        GraphBuilder {
            g: IcGraph::new(ids, width, height),
            ids: ids,
            chip: chip,
            db: db,
            tiletypes_by_xy: tiletypes_by_xy,
            // the original tiletypes from the database
            orig_tts: orig_tts,
        }
    }
    fn setup_tiletypes(&mut self) {
        for t in self.g.tiles.iter_mut() {
            let key = self.tiletypes_by_xy.get(&(t.x, t.y)).unwrap();
            t.type_idx = self.g.tile_types.add(key, IcTileType::new(key.clone(), &self.chip.family, self.db));
        }
        for (key, lt) in self.g.tile_types.iter_mut() {
            // setup wires for site pins
            let site_wires : Vec<String> = lt.site_types.iter().map(|s| s.pins.iter()).flatten().map(|p| p.tile_wire.clone()).collect();
            for w in site_wires {
                lt.wire(self.ids.id(&w));
            }
            for tt in key.tile_types.iter() {
                // setup wires for all sub-tile-types
                let tt_data = self.orig_tts.get(tt).unwrap();
                for wire in tt_data.wire_ids.iter() {
                    lt.wire(*wire);
                }
                // setup pips, both fixed and not
                // TODO: skip site wires and pips and deal with these later
                let tdb = &self.db.tile_bitdb(&self.chip.family, tt).db;
                for (to_wire, pips) in tdb.pips.iter() {
                    for pip in pips.iter() {
                        lt.add_pip(self.ids.id(&pip.from_wire), self.ids.id(to_wire));
                    }
                }
                for (to_wire, conns) in tdb.conns.iter() {
                    for conn in conns.iter() {
                        lt.add_pip(self.ids.id(&conn.from_wire), self.ids.id(to_wire));
                    }
                }
            }
        }
    }
    // Convert a neighbour to a coordinate
    pub fn neighbour_tile(&self, x: u32, y: u32, n: &Neighbour) -> Option<(u32, u32)> {
        match n {
            Neighbour::RelXY { rel_x, rel_y } => {
                let nx = (x as i32) + rel_x;
                let ny = (y as i32) + rel_y;
                if nx >= 0 && ny >= 0 && (nx as u32) < self.g.width && (ny as u32) < self.g.height {
                    Some((nx as u32, ny as u32))
                } else {
                    None
                }
            }
            // TODO: globals
            _ => None
        }
    }
    fn setup_wire2node(&mut self) {
        for ((x, y), key) in self.tiletypes_by_xy.iter() {
            for tt in key.tile_types.iter() {
                for wire in self.orig_tts.get(tt).unwrap().wires.iter() {
                    let (neigh, base_wire) = Neighbour::parse_wire(wire);
                    if let Some(neigh) = neigh {
                        // it's a neighbour wire, map to the base tile
                        if let Some((root_x, root_y)) = self.neighbour_tile(*x, *y, &neigh) {
                            self.g.map_node(root_x, root_y, self.ids.id(base_wire), *x, *y, self.ids.id(wire));
                        }

                    } else {
                        // root node, map to itself
                        self.g.map_node(*x, *y, self.ids.id(base_wire), *x, *y, self.ids.id(base_wire));
                    }
                }
            }
        }
    }

    pub fn run(ids: &'a mut IdStringDB, chip: &'a Chip, db: &'a mut Database) -> IcGraph {
        let mut builder = GraphBuilder::new(ids, chip, db);
        builder.setup_tiletypes();
        builder.setup_wire2node();
        builder.g
    }
}
<commit_msg>interchange: Exclude site pips from tile pips<commit_after>#![cfg(feature = "interchange")]

use crate::chip::Chip;
use crate::database::Database;
use std::collections::{HashSet, HashMap};

use crate::bba::idstring::*;
use crate::bba::idxset::*;
use crate::bba::tiletype::{Neighbour, TileTypes};

use crate::sites::*;
use crate::wires::*;

// A tile type from the interchange format perspective
// this is not the same as a database tile type; because the Oxide graph can have
// more than one tile at a grid location whereas the interchange grid is one tile
// per location

#[derive(Clone, Eq, PartialEq, Hash)]
pub struct TileTypeKey {
    pub tile_types: Vec<String>,
}
impl TileTypeKey {
    pub fn new() -> TileTypeKey {
        TileTypeKey { tile_types: Vec::new() }
    }
}

pub struct IcTileType {
    pub key: TileTypeKey,
    pub wires: IndexedMap<IdString, IcWire>,
    pub pips: Vec<IcPip>,
    pub site_types: Vec<Site>,
    // TODO: constants, sites, etc
}

impl IcTileType {
    pub fn new(key: TileTypeKey, family: &str, db: &mut Database) -> IcTileType {
        let mut site_types = Vec::new();
        for tt in key.tile_types.iter() {
            site_types.extend(build_sites(&tt, &db.tile_bitdb(family, &tt).db));
        }
        IcTileType {
            key: key,
            wires: IndexedMap::new(),
            pips: Vec::new(),
            site_types: site_types,
        }
    }
    pub fn wire(&mut self, name: IdString) -> usize {
        self.wires.add(&name, IcWire::new(name))
    }
    pub fn add_pip(&mut self, src: IdString, dst: IdString) {
        let src_idx = self.wire(src);
        let dst_idx = self.wire(dst);
        self.pips.push(IcPip {
            src_wire: src_idx,
            dst_wire: dst_idx,
        });
    }
}

pub struct IcWire {
    pub name: IdString,
}

impl IcWire {
    pub fn new(name: IdString) -> IcWire {
        IcWire {
            name: name,
        }
    }
}

pub struct IcPip {
    pub src_wire: usize,
    pub dst_wire: usize,
}

// A tile instance
pub struct IcTileInst {
    pub name: IdString,
    pub x: u32,
    pub y: u32,
    pub type_idx: usize,
    // mapping between wires and nodes
    wire_to_node: HashMap<IdString, usize>,
}

impl IcTileInst {
    pub fn new(ids: &mut IdStringDB, x: u32, y: u32) -> IcTileInst {
        IcTileInst {
            name: ids.id(&format!("R{}C{}", y, x)),
            x: x,
            y: y,
            type_idx: 0,
            wire_to_node: HashMap::new(),
        }
    }
}

// A reference to a tile wire
#[derive(Clone, Hash, Eq, PartialEq)]
pub struct IcWireRef {
    pub tile_name: IdString,
    pub wire_name: IdString,
}

// A node instance
pub struct IcNode {
    // list of tile wires in the node
    pub wires: HashSet<IcWireRef>,
    pub root_wire: IcWireRef,
}

impl IcNode {
    pub fn new(root_wire: IcWireRef) -> IcNode {
        IcNode {
            wires: [root_wire.clone()].iter().cloned().collect(),
            root_wire: root_wire,
        }
    }
}

// The overall routing resource graph
pub struct IcGraph {
    pub tile_types: IndexedMap<TileTypeKey, IcTileType>,
    pub tiles: Vec<IcTileInst>,
    pub nodes: Vec<IcNode>,
    pub width: u32,
    pub height: u32,
}

impl IcGraph {
    pub fn new(ids: &mut IdStringDB, width: u32, height: u32) -> IcGraph {
        IcGraph {
            tile_types: IndexedMap::new(),
            tiles: (0..width*height).map(|i| IcTileInst::new(ids, i%width, i/width)).collect(),
            nodes: Vec::new(),
            width: width,
            height: height
        }
    }
    pub fn tile_idx(&self, x: u32, y: u32) -> usize {
        assert!(x < self.width);
        assert!(y < self.height);
        ((y * self.width) + x) as usize
    }
    pub fn tile_at(&mut self, x: u32, y: u32) -> &mut IcTileInst {
        let idx = self.tile_idx(x, y);
        &mut self.tiles[idx]
    }
    pub fn type_at(&mut self, x: u32, y: u32) -> &mut IcTileType {
        let idx = self.tile_at(x, y).type_idx;
        self.tile_types.value_mut(idx)
    }
    pub fn map_node(&mut self, root_x: u32, root_y: u32, root_wire: IdString, wire_x: u32, wire_y: u32, wire: IdString) {
        // Make sure wire exists in both tiles
        self.type_at(root_x, root_y).wire(root_wire);
        self.type_at(wire_x, wire_y).wire(wire);
        // Update wire-node mapping
        let root_tile_idx = self.tile_idx(root_x, root_y);
        let node_idx = match self.tiles[root_tile_idx].wire_to_node.get(&root_wire) {
            Some(i) => *i,
            None => {
                let idx = self.nodes.len();
                self.nodes.push(IcNode::new(IcWireRef { tile_name: self.tiles[root_tile_idx].name, wire_name: root_wire }));
                self.tiles[root_tile_idx].wire_to_node.insert(root_wire, idx);
                idx
            }
        };
        let wire_tile_idx = self.tile_idx(wire_x, wire_y);
        self.nodes[node_idx].wires.insert(IcWireRef {tile_name: self.tiles[wire_tile_idx].name, wire_name: wire });
        self.tiles[wire_tile_idx].wire_to_node.insert(wire, node_idx);
    }
}

pub struct GraphBuilder<'a> {
    g: IcGraph,
    ids: &'a mut IdStringDB,
    chip: &'a Chip,
    db: &'a mut Database,
    tiletypes_by_xy: HashMap<(u32, u32), TileTypeKey>,
    orig_tts: TileTypes,
}

impl <'a> GraphBuilder<'a> {
    fn new(ids: &'a mut IdStringDB, chip: &'a Chip, db: &'a mut Database) -> GraphBuilder<'a> {
        let mut width = 0;
        let mut height = 0;
        let mut tiletypes_by_xy = HashMap::new();
        for t in chip.tiles.iter() {
            tiletypes_by_xy.entry((t.x, t.y)).or_insert(TileTypeKey::new()).tile_types.push(t.tiletype.to_string());
            width = std::cmp::max(width, t.x + 1);
            height = std::cmp::max(height, t.y + 1);
        }

        let orig_tts = TileTypes::new(db, ids, &chip.family, &[&chip.device]);

        GraphBuilder {
            g: IcGraph::new(ids, width, height),
            ids: ids,
            chip: chip,
            db: db,
            tiletypes_by_xy: tiletypes_by_xy,
            // the original tiletypes from the database
            orig_tts: orig_tts,
        }
    }
    fn setup_tiletypes(&mut self) {
        for t in self.g.tiles.iter_mut() {
            let key = self.tiletypes_by_xy.get(&(t.x, t.y)).unwrap();
            t.type_idx = self.g.tile_types.add(key, IcTileType::new(key.clone(), &self.chip.family, self.db));
        }
        for (key, lt) in self.g.tile_types.iter_mut() {
            // setup wires for site pins
            let site_wires : Vec<String> = lt.site_types.iter().map(|s| s.pins.iter()).flatten().map(|p| p.tile_wire.clone()).collect();
            for w in site_wires {
                lt.wire(self.ids.id(&w));
            }
            for tt in key.tile_types.iter() {
                // setup wires for all sub-tile-types
                let tt_data = self.orig_tts.get(tt).unwrap();
                for wire in tt_data.wire_ids.iter() {
                    lt.wire(*wire);
                }
                // setup pips, both fixed and not
                // TODO: skip site wires and pips and deal with these later
                let tdb = &self.db.tile_bitdb(&self.chip.family, tt).db;
                for (to_wire, pips) in tdb.pips.iter() {
                    for pip in pips.iter() {
                        if is_site_wire(tt, &pip.from_wire) && is_site_wire(tt, to_wire) {
                            continue;
                        }
                        lt.add_pip(self.ids.id(&pip.from_wire), self.ids.id(to_wire));
                    }
                }
                for (to_wire, conns) in tdb.conns.iter() {
                    for conn in conns.iter() {
                        if is_site_wire(tt, &conn.from_wire) && is_site_wire(tt, to_wire) {
                            continue;
                        }
                        lt.add_pip(self.ids.id(&conn.from_wire), self.ids.id(to_wire));
                    }
                }
            }
        }
    }
    // Convert a neighbour to a coordinate
    pub fn neighbour_tile(&self, x: u32, y: u32, n: &Neighbour) -> Option<(u32, u32)> {
        match n {
            Neighbour::RelXY { rel_x, rel_y } => {
                let nx = (x as i32) + rel_x;
                let ny = (y as i32) + rel_y;
                if nx >= 0 && ny >= 0 && (nx as u32) < self.g.width && (ny as u32) < self.g.height {
                    Some((nx as u32, ny as u32))
                } else {
                    None
                }
            }
            // TODO: globals
            _ => None
        }
    }
    fn setup_wire2node(&mut self) {
        for ((x, y), key) in self.tiletypes_by_xy.iter() {
            for tt in key.tile_types.iter() {
                for wire in self.orig_tts.get(tt).unwrap().wires.iter() {
                    let (neigh, base_wire) = Neighbour::parse_wire(wire);
                    if let Some(neigh) = neigh {
                        // it's a neighbour wire, map to the base tile
                        if let Some((root_x, root_y)) = self.neighbour_tile(*x, *y, &neigh) {
                            self.g.map_node(root_x, root_y, self.ids.id(base_wire), *x, *y, self.ids.id(wire));
                        }

                    } else {
                        // root node, map to itself
                        self.g.map_node(*x, *y, self.ids.id(base_wire), *x, *y, self.ids.id(base_wire));
                    }
                }
            }
        }
    }

    pub fn run(ids: &'a mut IdStringDB, chip: &'a Chip, db: &'a mut Database) -> IcGraph {
        let mut builder = GraphBuilder::new(ids, chip, db);
        builder.setup_tiletypes();
        builder.setup_wire2node();
        builder.g
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Jonathan Anderson
 *
 * 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.
 */

//! Dissection of Ethernet (IEEE 802.3) frames.

use {
    Endianness,
    Error,
    NamedValue,
    Protocol,
    RawBytes,
    Result,
    Val,
    ip,
    promising_future,
    unsigned,
};

/// The IEEE 802.3 Ethernet protocol.
pub struct Ethernet;

impl Protocol for Ethernet {
    fn short_name(&self) -> &str { "Ethernet" }
    fn full_name(&self) -> &str { "IEEE 802.3 Ethernet" }
    fn dissect(&self, data: &[u8]) -> Result {
        if data.len() < 14 {
            return Err(Error::Underflow { expected: 14, have: data.len(),
                message: "An Ethernet frame must be at least 14 B".to_string() })
        }

        // Process fields asynchronously.
        let (future, promise) = promising_future::future_promise();

        // TODO: actually process asynchronously!
        promise.set(dissect_fields(data));

        Ok(Val::Protocol(future))
    }
}

fn dissect_fields(data: &[u8]) -> Vec<NamedValue> {
    let mut values:Vec<NamedValue> = vec![];
    values.push(("Destination".to_string(), Ok(Val::Bytes(data[0..6].to_vec()))));
    values.push(("Source".to_string(), Ok(Val::Bytes(data[6..12].to_vec()))));

    // The type/length field might be either a type or a length.
    let tlen = unsigned(&data[12..14], Endianness::BigEndian);
    let remainder = &data[14..];

    match tlen {
        Ok(i) if i <= 1500 => {
            values.push(("Length".to_string(), Ok(Val::Unsigned(i))));
        },

        Ok(i) => {
            let protocol: Box<Protocol> = match i {
                // TODO: use the simple 'box' syntax once it hits stable
                0x800 => Box::new(ip::IPv4),
                0x806 => RawBytes::boxed("ARP", "Address Resolution Protocol"),
                0x8138 => RawBytes::boxed("IPX", "Internetwork Packet Exchange"),
                0x86dd => RawBytes::boxed("IPv6", "Internet Protocol version 6"),

                _ => Box::new(RawBytes::unknown_protocol(&format!["0x{:x}", i])),
            };

            let protoname = protocol.short_name().to_string();
            let description = protocol.full_name().to_string();

            values.push(("Type".to_string(), Ok(Val::String(protoname))));
            values.push((description, protocol.dissect(remainder)));
        },
        Err(e) => {
            values.push(("Type/length".to_string(), Err(e)));
        },
    };

    values
}
<commit_msg>Create ethernet::mac_address function.<commit_after>/*
 * Copyright 2015 Jonathan Anderson
 *
 * 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.
 */

//! Dissection of Ethernet (IEEE 802.3) frames.

use {
    Endianness,
    Error,
    NamedValue,
    Protocol,
    RawBytes,
    Result,
    Val,
    ip,
    promising_future,
    unsigned,
};

/// The IEEE 802.3 Ethernet protocol.
pub struct Ethernet;

/// Parse a six-byte MAC address, which can be encoded as, e.g., ff:ff:ff:ff:ff:ff.
pub fn mac_address(raw: &[u8]) -> Result<Val> {
    if raw.len() != 6 {
        return Err(Error::InvalidData(format!["MAC address should have 6 B, not {}",
                                              raw.len()]));
    }

    let encoded = raw
                  .iter()
                  .map(|b| format!["{:02x}", b])
                  .collect::<Vec<String>>()
                  .join(":")
                  ;

    Ok(Val::Address { bytes: raw.to_vec(), encoded: encoded })
}

impl Protocol for Ethernet {
    fn short_name(&self) -> &str { "Ethernet" }
    fn full_name(&self) -> &str { "IEEE 802.3 Ethernet" }
    fn dissect(&self, data: &[u8]) -> Result {
        if data.len() < 14 {
            return Err(Error::Underflow { expected: 14, have: data.len(),
                message: "An Ethernet frame must be at least 14 B".to_string() })
        }

        // Process fields asynchronously.
        let (future, promise) = promising_future::future_promise();

        // TODO: actually process asynchronously!
        promise.set(dissect_fields(data));

        Ok(Val::Protocol(future))
    }
}

fn dissect_fields(data: &[u8]) -> Vec<NamedValue> {
    let mut values:Vec<NamedValue> = vec![];
    values.push(("Destination".to_string(), mac_address(&data[0..6])));
    values.push(("Source".to_string(), mac_address(&data[6..12])));

    // The type/length field might be either a type or a length.
    let tlen = unsigned(&data[12..14], Endianness::BigEndian);
    let remainder = &data[14..];

    match tlen {
        Ok(i) if i <= 1500 => {
            values.push(("Length".to_string(), Ok(Val::Unsigned(i))));
        },

        Ok(i) => {
            let protocol: Box<Protocol> = match i {
                // TODO: use the simple 'box' syntax once it hits stable
                0x800 => Box::new(ip::IPv4),
                0x806 => RawBytes::boxed("ARP", "Address Resolution Protocol"),
                0x8138 => RawBytes::boxed("IPX", "Internetwork Packet Exchange"),
                0x86dd => RawBytes::boxed("IPv6", "Internet Protocol version 6"),

                _ => Box::new(RawBytes::unknown_protocol(&format!["0x{:x}", i])),
            };

            let protoname = protocol.short_name().to_string();
            let description = protocol.full_name().to_string();

            values.push(("Type".to_string(), Ok(Val::String(protoname))));
            values.push((description, protocol.dissect(remainder)));
        },
        Err(e) => {
            values.push(("Type/length".to_string(), Err(e)));
        },
    };

    values
}

<|endoftext|>


<commit_before>//! The module implements the client side of the HTTP/2 protocol and exposes
//! an API for using it.
use std::io;
use std::convert::From;
use std::error::Error;

use hpack::decoder::DecoderError;

pub mod frame;
pub mod transport;
pub mod connection;
pub mod session;

/// An alias for the type that represents the ID of an HTTP/2 stream
pub type StreamId = u32;
/// An alias for the type that represents HTTP/2 haders. For now we only alias
/// the tuple of byte vectors instead of going with a full struct representation.
pub type Header = (Vec<u8>, Vec<u8>);

/// An enum representing errors that can arise when performing operations
/// involving an HTTP/2 connection.
#[derive(Debug)]
pub enum HttpError {
    IoError(io::Error),
    UnknownFrameType,
    InvalidFrame,
    CompressionError(DecoderError),
    UnknownStreamId,
    UnableToConnect,
    MalformedResponse,
}

/// Implement the trait that allows us to automatically convert `io::Error`s
/// into an `HttpError` by wrapping the given `io::Error` into an `HttpError::IoError` variant.
impl From<io::Error> for HttpError {
    fn from(err: io::Error) -> HttpError {
        HttpError::IoError(err)
    }
}

/// Implementation of the `PartialEq` trait as a convenience for tests.
#[cfg(test)]
impl PartialEq for HttpError {
    fn eq(&self, other: &HttpError) -> bool {
        match (self, other) {
            (&HttpError::IoError(ref e1), &HttpError::IoError(ref e2)) => {
                e1.kind() == e2.kind() && e1.description() == e2.description()
            },
            (&HttpError::UnknownFrameType, &HttpError::UnknownFrameType) => true,
            (&HttpError::InvalidFrame, &HttpError::InvalidFrame) => true,
            (&HttpError::CompressionError(ref e1), &HttpError::CompressionError(ref e2)) => {
                e1 == e2
            },
            (&HttpError::UnknownStreamId, &HttpError::UnknownStreamId) => true,
            (&HttpError::UnableToConnect, &HttpError::UnableToConnect) => true,
            (&HttpError::MalformedResponse, &HttpError::MalformedResponse) => true,
            _ => false,
        }
    }
}

/// A convenience `Result` type that has the `HttpError` type as the error
/// type and a generic Ok result type.
pub type HttpResult<T> = Result<T, HttpError>;

/// A struct representing the full raw response received on an HTTP/2 connection.
///
/// The full body of the response is included, regardless how large it may be.
/// The headers contain both the meta-headers, as well as the actual headers.
#[derive(Clone)]
pub struct Response {
    /// The ID of the stream to which the response is associated. HTTP/1.1 does
    /// not really have an equivalent to this.
    pub stream_id: StreamId,
    /// Exposes *all* the raw response headers, including the meta-headers.
    /// (For now the only meta header allowed in HTTP/2 responses is the
    /// `:status`.)
    pub headers: Vec<Header>,
    /// The full body of the response as an uninterpreted sequence of bytes.
    pub body: Vec<u8>,
}

impl Response {
    /// Creates a new `Response` with all the components already provided.
    pub fn new(stream_id: StreamId, headers: Vec<Header>, body: Vec<u8>)
            -> Response {
        Response {
            stream_id: stream_id,
            headers: headers,
            body: body,
        }
    }

    /// Gets the response status code from the pseudo-header. If the response
    /// does not contain the response as the first pseuo-header, an error is
    /// returned as such a response is malformed.
    pub fn status_code(&self) -> HttpResult<u16> {
        // Since pseudo-headers MUST be found before any regular header fields
        // and the *only* pseudo-header defined for responses is the `:status`
        // field, the `:status` MUST be the first header; otherwise, the
        // response is malformed.
        if self.headers.len() < 1 {
            return Err(HttpError::MalformedResponse)
        }
        if &self.headers[0].0 != &b":status" {
            Err(HttpError::MalformedResponse)
        } else {
            Ok(try!(Response::parse_status_code(&self.headers[0].1)))
        }
    }

    /// A helper function that parses a given buffer as a status code and
    /// returns it as a `u16`, if it is valid.
    fn parse_status_code(buf: &[u8]) -> HttpResult<u16> {
        // "The status-code element is a three-digit integer code [...]"
        if buf.len() != 3 {
            return Err(HttpError::MalformedResponse);
        }

        // "There are five values for the first digit"
        if buf[0] < b'1' || buf[0] > b'5' {
            return Err(HttpError::MalformedResponse);
        }

        // The rest of them just have to be digits
        if buf[1] < b'0' || buf[1] > b'9' || buf[2] < b'0' || buf[2] > b'9' {
            return Err(HttpError::MalformedResponse);
        }

        // Finally, we can merge them into an integer
        Ok(100 * ((buf[0] - b'0') as u16) +
           10 * ((buf[1] - b'0') as u16) +
           1 * ((buf[2] - b'0') as u16))
    }
}

/// A struct representing a full HTTP/2 request, along with the full body, as a
/// sequence of bytes.
#[derive(Clone)]
pub struct Request {
    pub stream_id: u32,
    pub headers: Vec<Header>,
    pub body: Vec<u8>,
}

#[cfg(test)]
mod tests {
    use super::{Response, HttpError};

    /// Tests that the `Response` struct correctly parses a status code from
    /// its headers list.
    #[test]
    fn test_parse_status_code_response() {
        {
            // Only status => Ok
            let resp = Response::new(
                1,
                vec![(b":status".to_vec(), b"200".to_vec())],
                vec![]);
            assert_eq!(resp.status_code().ok().unwrap(), 200);
        }
        {
            // Extra headers => still works
            let resp = Response::new(
                1,
                vec![(b":status".to_vec(), b"200".to_vec()),
                     (b"key".to_vec(), b"val".to_vec())],
                vec![]);
            assert_eq!(resp.status_code().ok().unwrap(), 200);
        }
        {
            // Status is not the first header => malformed
            let resp = Response::new(
                1,
                vec![(b"key".to_vec(), b"val".to_vec()),
                     (b":status".to_vec(), b"200".to_vec())],
                vec![]);
            assert_eq!(resp.status_code().err().unwrap(),
                       HttpError::MalformedResponse);
        }
        {
            // No headers at all => Malformed
            let resp = Response::new(1, vec![], vec![]);
            assert_eq!(resp.status_code().err().unwrap(),
                       HttpError::MalformedResponse);
        }
    }
}
<commit_msg>Add an HttpScheme enum<commit_after>//! The module implements the client side of the HTTP/2 protocol and exposes
//! an API for using it.
use std::io;
use std::convert::From;
use std::error::Error;

use hpack::decoder::DecoderError;

pub mod frame;
pub mod transport;
pub mod connection;
pub mod session;

/// An alias for the type that represents the ID of an HTTP/2 stream
pub type StreamId = u32;
/// An alias for the type that represents HTTP/2 haders. For now we only alias
/// the tuple of byte vectors instead of going with a full struct representation.
pub type Header = (Vec<u8>, Vec<u8>);

/// An enum representing errors that can arise when performing operations
/// involving an HTTP/2 connection.
#[derive(Debug)]
pub enum HttpError {
    IoError(io::Error),
    UnknownFrameType,
    InvalidFrame,
    CompressionError(DecoderError),
    UnknownStreamId,
    UnableToConnect,
    MalformedResponse,
}

/// Implement the trait that allows us to automatically convert `io::Error`s
/// into an `HttpError` by wrapping the given `io::Error` into an `HttpError::IoError` variant.
impl From<io::Error> for HttpError {
    fn from(err: io::Error) -> HttpError {
        HttpError::IoError(err)
    }
}

/// Implementation of the `PartialEq` trait as a convenience for tests.
#[cfg(test)]
impl PartialEq for HttpError {
    fn eq(&self, other: &HttpError) -> bool {
        match (self, other) {
            (&HttpError::IoError(ref e1), &HttpError::IoError(ref e2)) => {
                e1.kind() == e2.kind() && e1.description() == e2.description()
            },
            (&HttpError::UnknownFrameType, &HttpError::UnknownFrameType) => true,
            (&HttpError::InvalidFrame, &HttpError::InvalidFrame) => true,
            (&HttpError::CompressionError(ref e1), &HttpError::CompressionError(ref e2)) => {
                e1 == e2
            },
            (&HttpError::UnknownStreamId, &HttpError::UnknownStreamId) => true,
            (&HttpError::UnableToConnect, &HttpError::UnableToConnect) => true,
            (&HttpError::MalformedResponse, &HttpError::MalformedResponse) => true,
            _ => false,
        }
    }
}

/// A convenience `Result` type that has the `HttpError` type as the error
/// type and a generic Ok result type.
pub type HttpResult<T> = Result<T, HttpError>;

/// An enum representing the two possible HTTP schemes.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum HttpScheme {
    /// The variant corresponding to `http://`
    Http,
    /// The variant corresponding to `https://`
    Https,
}

impl HttpScheme {
    /// Returns a byte string representing the scheme.
    #[inline]
    pub fn as_bytes(&self) -> &'static [u8] {
        match *self {
            HttpScheme::Http => b"http",
            HttpScheme::Https => b"https",
        }
    }
}

/// A struct representing the full raw response received on an HTTP/2 connection.
///
/// The full body of the response is included, regardless how large it may be.
/// The headers contain both the meta-headers, as well as the actual headers.
#[derive(Clone)]
pub struct Response {
    /// The ID of the stream to which the response is associated. HTTP/1.1 does
    /// not really have an equivalent to this.
    pub stream_id: StreamId,
    /// Exposes *all* the raw response headers, including the meta-headers.
    /// (For now the only meta header allowed in HTTP/2 responses is the
    /// `:status`.)
    pub headers: Vec<Header>,
    /// The full body of the response as an uninterpreted sequence of bytes.
    pub body: Vec<u8>,
}

impl Response {
    /// Creates a new `Response` with all the components already provided.
    pub fn new(stream_id: StreamId, headers: Vec<Header>, body: Vec<u8>)
            -> Response {
        Response {
            stream_id: stream_id,
            headers: headers,
            body: body,
        }
    }

    /// Gets the response status code from the pseudo-header. If the response
    /// does not contain the response as the first pseuo-header, an error is
    /// returned as such a response is malformed.
    pub fn status_code(&self) -> HttpResult<u16> {
        // Since pseudo-headers MUST be found before any regular header fields
        // and the *only* pseudo-header defined for responses is the `:status`
        // field, the `:status` MUST be the first header; otherwise, the
        // response is malformed.
        if self.headers.len() < 1 {
            return Err(HttpError::MalformedResponse)
        }
        if &self.headers[0].0 != &b":status" {
            Err(HttpError::MalformedResponse)
        } else {
            Ok(try!(Response::parse_status_code(&self.headers[0].1)))
        }
    }

    /// A helper function that parses a given buffer as a status code and
    /// returns it as a `u16`, if it is valid.
    fn parse_status_code(buf: &[u8]) -> HttpResult<u16> {
        // "The status-code element is a three-digit integer code [...]"
        if buf.len() != 3 {
            return Err(HttpError::MalformedResponse);
        }

        // "There are five values for the first digit"
        if buf[0] < b'1' || buf[0] > b'5' {
            return Err(HttpError::MalformedResponse);
        }

        // The rest of them just have to be digits
        if buf[1] < b'0' || buf[1] > b'9' || buf[2] < b'0' || buf[2] > b'9' {
            return Err(HttpError::MalformedResponse);
        }

        // Finally, we can merge them into an integer
        Ok(100 * ((buf[0] - b'0') as u16) +
           10 * ((buf[1] - b'0') as u16) +
           1 * ((buf[2] - b'0') as u16))
    }
}

/// A struct representing a full HTTP/2 request, along with the full body, as a
/// sequence of bytes.
#[derive(Clone)]
pub struct Request {
    pub stream_id: u32,
    pub headers: Vec<Header>,
    pub body: Vec<u8>,
}

#[cfg(test)]
mod tests {
    use super::{Response, HttpError, HttpScheme};

    /// Tests that the `Response` struct correctly parses a status code from
    /// its headers list.
    #[test]
    fn test_parse_status_code_response() {
        {
            // Only status => Ok
            let resp = Response::new(
                1,
                vec![(b":status".to_vec(), b"200".to_vec())],
                vec![]);
            assert_eq!(resp.status_code().ok().unwrap(), 200);
        }
        {
            // Extra headers => still works
            let resp = Response::new(
                1,
                vec![(b":status".to_vec(), b"200".to_vec()),
                     (b"key".to_vec(), b"val".to_vec())],
                vec![]);
            assert_eq!(resp.status_code().ok().unwrap(), 200);
        }
        {
            // Status is not the first header => malformed
            let resp = Response::new(
                1,
                vec![(b"key".to_vec(), b"val".to_vec()),
                     (b":status".to_vec(), b"200".to_vec())],
                vec![]);
            assert_eq!(resp.status_code().err().unwrap(),
                       HttpError::MalformedResponse);
        }
        {
            // No headers at all => Malformed
            let resp = Response::new(1, vec![], vec![]);
            assert_eq!(resp.status_code().err().unwrap(),
                       HttpError::MalformedResponse);
        }
    }

    /// Tests that the `HttpScheme` enum returns the correct scheme strings for
    /// the two variants.
    #[test]
    fn test_scheme_string() {
        assert_eq!(HttpScheme::Http.as_bytes(), b"http");
        assert_eq!(HttpScheme::Https.as_bytes(), b"https");
    }
}
<|endoftext|>