<commit_before>extern crate libc;

use core::Workspaces;
use window_manager::WindowManager;
use window_system::WindowSystem;
use window_system::Window;
use config::{ GeneralConfig, Config };

pub type KeyHandler<'a> = Box<Fn<(WindowManager<'a>, &'a (WindowSystem + 'a), &'a GeneralConfig<'a>), WindowManager<'a>> + 'a>;
pub type MouseHandler<'a> = Box<Fn<(WindowManager<'a>, &'a (WindowSystem + 'a), &'a GeneralConfig<'a>, Window), WindowManager<'a>> + 'a>;
pub type ManageHook<'a> = Box<Fn<(Workspaces<'a>, &'a (WindowSystem + 'a), Window), Workspaces<'a>> + 'a>;
pub type StartupHook<'a> = Box<Fn<(WindowManager<'a>, &'a (WindowSystem + 'a), &'a Config<'a>), WindowManager<'a>> + 'a>;
pub type LogHook<'a> = Box<FnMut<(WindowManager<'a>, &'a (WindowSystem + 'a)), ()> + 'a>;

extern {
    pub fn waitpid(fd: libc::pid_t, status: *mut libc::c_int, options: libc::c_int) -> libc::pid_t;
}

/// Some default handlers for easier config scripts
pub mod default {
    use std::os;
    use std::ptr::null;
    use std::io::process::Command;
    use std::thread::Thread;
    use serialize::json;
    use core::Workspaces;
    use window_manager::WindowManager;
    use window_system::WindowSystem;
    use window_system::Window;
    use config::GeneralConfig;
    use handlers::libc::funcs::posix88::unistd::execvp;

    pub fn start_terminal<'a>(window_manager: WindowManager<'a>, _: &WindowSystem,
                          config: &GeneralConfig) -> WindowManager<'a> {
        let (terminal, args) = config.terminal.clone();
        let arguments : Vec<String> = if args.is_empty() {
            Vec::new()
        } else {
            args.split(' ').map(String::from_str).collect()
        };

        Thread::spawn(move || {
            debug!("spawning terminal");
            let command = if arguments.is_empty() {
                Command::new(terminal).detached().spawn()
            } else {
                Command::new(terminal).args(arguments.as_slice()).detached().spawn()
            };

            if let Err(_) = command {
                panic!("unable to start terminal")
            }
        }).detach();

        window_manager.clone()
    }

    pub fn start_launcher<'a>(window_manager: WindowManager<'a>, _: &WindowSystem,
                          config: &GeneralConfig) -> WindowManager<'a> {
        let launcher = config.launcher.clone();
        Thread::spawn(move || {
            debug!("spawning launcher");
            match Command::new(launcher).detached().spawn() {
                Ok(_) => (),
                _     => panic!("unable to start launcher")
            }
        }).detach();

        window_manager.clone()
    }

    pub fn switch_to_workspace<'a>(window_manager: WindowManager<'a>, window_system: &WindowSystem,
                               config: &GeneralConfig<'a>, index: uint) -> WindowManager<'a> {
        window_manager.view(window_system, index as u32, config)
    }

    pub fn move_window_to_workspace<'a>(window_manager: WindowManager<'a>, window_system: &WindowSystem,
                                    config: &GeneralConfig<'a>, index: uint) -> WindowManager<'a> {
        window_manager.move_window_to_workspace(window_system, config, index as u32)
    }

    /// Restart the window manager by calling execvp and replacing the current binary
    /// with the new one in memory.
    /// Pass a list of all windows to it via command line arguments
    /// so it may resume work as usual.
    pub fn restart<'a>(window_manager: WindowManager<'a>, _: &WindowSystem, c: &GeneralConfig<'a>) -> WindowManager<'a> {
        // Get absolute path to binary
        let filename = os::make_absolute(&Path::new(os::args()[0].clone())).unwrap().to_c_str();
        // Collect all managed windows
        let window_ids : String = json::encode(&window_manager.workspaces.all_windows_with_workspaces());

        // Create arguments
        let program_name = os::args()[0].clone().to_c_str();
        let resume = String::from_str("--resume").to_c_str();
        let windows = window_ids.to_c_str();

        for ref p in c.pipes.iter() {
            match p.deref().write().unwrap().deref_mut().wait() {
                _ => ()
            }
        }

        unsafe {
            let mut slice : &mut [*const i8; 4] = &mut [
                program_name.as_ptr(),
                resume.as_ptr(),
                windows.as_ptr(),
                null()
            ];
            execvp(filename.as_ptr(), slice.as_mut_ptr());
        }

        window_manager.clone()
    }

    /// Stop the window manager
    pub fn exit<'a>(w: WindowManager<'a>, _: &WindowSystem, _: &GeneralConfig<'a>) -> WindowManager<'a> {
        WindowManager { running: false, dragging: None, workspaces: w.workspaces }
    }

    pub fn shift<'a>(index: u32, workspace: Workspaces<'a>, window: Window) -> Workspaces<'a> {
        workspace.shift_window(index, window)
    }
}
<commit_msg>prefer &'static str instead of single use String<commit_after>extern crate libc;

use core::Workspaces;
use window_manager::WindowManager;
use window_system::WindowSystem;
use window_system::Window;
use config::{ GeneralConfig, Config };

pub type KeyHandler<'a> = Box<Fn<(WindowManager<'a>, &'a (WindowSystem + 'a), &'a GeneralConfig<'a>), WindowManager<'a>> + 'a>;
pub type MouseHandler<'a> = Box<Fn<(WindowManager<'a>, &'a (WindowSystem + 'a), &'a GeneralConfig<'a>, Window), WindowManager<'a>> + 'a>;
pub type ManageHook<'a> = Box<Fn<(Workspaces<'a>, &'a (WindowSystem + 'a), Window), Workspaces<'a>> + 'a>;
pub type StartupHook<'a> = Box<Fn<(WindowManager<'a>, &'a (WindowSystem + 'a), &'a Config<'a>), WindowManager<'a>> + 'a>;
pub type LogHook<'a> = Box<FnMut<(WindowManager<'a>, &'a (WindowSystem + 'a)), ()> + 'a>;

extern {
    pub fn waitpid(fd: libc::pid_t, status: *mut libc::c_int, options: libc::c_int) -> libc::pid_t;
}

/// Some default handlers for easier config scripts
pub mod default {
    use std::os;
    use std::ptr::null;
    use std::io::process::Command;
    use std::thread::Thread;
    use serialize::json;
    use core::Workspaces;
    use window_manager::WindowManager;
    use window_system::WindowSystem;
    use window_system::Window;
    use config::GeneralConfig;
    use handlers::libc::funcs::posix88::unistd::execvp;

    pub fn start_terminal<'a>(window_manager: WindowManager<'a>, _: &WindowSystem,
                          config: &GeneralConfig) -> WindowManager<'a> {
        let (terminal, args) = config.terminal.clone();
        let arguments : Vec<String> = if args.is_empty() {
            Vec::new()
        } else {
            args.split(' ').map(String::from_str).collect()
        };

        Thread::spawn(move || {
            debug!("spawning terminal");
            let command = if arguments.is_empty() {
                Command::new(terminal).detached().spawn()
            } else {
                Command::new(terminal).args(arguments.as_slice()).detached().spawn()
            };

            if let Err(_) = command {
                panic!("unable to start terminal")
            }
        }).detach();

        window_manager.clone()
    }

    pub fn start_launcher<'a>(window_manager: WindowManager<'a>, _: &WindowSystem,
                          config: &GeneralConfig) -> WindowManager<'a> {
        let launcher = config.launcher.clone();
        Thread::spawn(move || {
            debug!("spawning launcher");
            match Command::new(launcher).detached().spawn() {
                Ok(_) => (),
                _     => panic!("unable to start launcher")
            }
        }).detach();

        window_manager.clone()
    }

    pub fn switch_to_workspace<'a>(window_manager: WindowManager<'a>, window_system: &WindowSystem,
                               config: &GeneralConfig<'a>, index: uint) -> WindowManager<'a> {
        window_manager.view(window_system, index as u32, config)
    }

    pub fn move_window_to_workspace<'a>(window_manager: WindowManager<'a>, window_system: &WindowSystem,
                                    config: &GeneralConfig<'a>, index: uint) -> WindowManager<'a> {
        window_manager.move_window_to_workspace(window_system, config, index as u32)
    }

    /// Restart the window manager by calling execvp and replacing the current binary
    /// with the new one in memory.
    /// Pass a list of all windows to it via command line arguments
    /// so it may resume work as usual.
    pub fn restart<'a>(window_manager: WindowManager<'a>, _: &WindowSystem, c: &GeneralConfig<'a>) -> WindowManager<'a> {
        // Get absolute path to binary
        let filename = os::make_absolute(&Path::new(os::args()[0].clone())).unwrap().to_c_str();
        // Collect all managed windows
        let window_ids : String = json::encode(&window_manager.workspaces.all_windows_with_workspaces());

        // Create arguments
        let program_name = os::args()[0].clone().to_c_str();
        let resume = &"--resume".to_c_str();
        let windows = window_ids.to_c_str();

        for ref p in c.pipes.iter() {
            match p.deref().write().unwrap().deref_mut().wait() {
                _ => ()
            }
        }

        unsafe {
            let mut slice : &mut [*const i8; 4] = &mut [
                program_name.as_ptr(),
                resume.as_ptr(),
                windows.as_ptr(),
                null()
            ];
            execvp(filename.as_ptr(), slice.as_mut_ptr());
        }

        window_manager.clone()
    }

    /// Stop the window manager
    pub fn exit<'a>(w: WindowManager<'a>, _: &WindowSystem, _: &GeneralConfig<'a>) -> WindowManager<'a> {
        WindowManager { running: false, dragging: None, workspaces: w.workspaces }
    }

    pub fn shift<'a>(index: u32, workspace: Workspaces<'a>, window: Window) -> Workspaces<'a> {
        workspace.shift_window(index, window)
    }
}
<|endoftext|>


<commit_before>use base::ast::TypedIdent;
use base::merge::{merge, merge_iter};
use base::pos;

use core::{Allocator, Alternative, Closure, Expr, Named, LetBinding, Pattern};

pub trait Visitor<'a> {
    fn visit_expr(&mut self, expr: &'a Expr<'a>) -> Option<&'a Expr<'a>>;
    fn allocator(&self) -> &'a Allocator<'a>;
}

struct RecognizeUnnecessaryAllocation<'a> {
    allocator: &'a Allocator<'a>,
}

impl<'a> Visitor<'a> for RecognizeUnnecessaryAllocation<'a> {
    fn visit_expr(&mut self, expr: &'a Expr<'a>) -> Option<&'a Expr<'a>> {
        // Avoids boxing data which are destructured immediately after creation
        // match { l, r } with
        // | { l, r } -> ...
        //
        // to
        //
        // let l = x
        // let l = y
        // ...
        match *expr {
            Expr::Match(&Expr::Data(ref id, exprs, ..), alts) if alts.len() == 1 => {
                match alts[0].pattern {
                    Pattern::Record(ref fields) => {
                        debug_assert!(id.typ.row_iter().len() >= fields.len());
                        let next_expr = alts[0].expr;
                        Some(
                            id.typ
                                .row_iter()
                                .zip(exprs)
                                .collect::<Vec<_>>()
                                .into_iter()
                                .rev()
                                .fold(next_expr, |next_expr, (field, expr)| {
                                    let pattern_field = fields
                                        .iter()
                                        .find(|f| f.0.name.name_eq(&field.name))
                                        .unwrap();
                                    let pattern_field =
                                        pattern_field.1.as_ref().unwrap_or(&pattern_field.0.name);
                                    let new_expr = Expr::Let(
                                        LetBinding {
                                            name: TypedIdent {
                                                name: pattern_field.clone(),
                                                typ: field.typ.clone(),
                                            },
                                            expr: Named::Expr(expr),
                                            span_start: pos::BytePos::default(),
                                        },
                                        next_expr,
                                    );
                                    &*self.allocator().arena.alloc(new_expr)
                                }),
                        )
                    }
                    _ => walk_expr_alloc(self, expr),
                }
            }
            _ => walk_expr_alloc(self, expr),
        }
    }

    fn allocator(&self) -> &'a Allocator<'a> {
        self.allocator
    }
}

pub fn optimize<'a>(allocator: &'a Allocator<'a>, expr: &'a Expr<'a>) -> &'a Expr<'a> {
    let mut optimizer = RecognizeUnnecessaryAllocation { allocator: allocator };
    optimizer.visit_expr(expr).unwrap_or(expr)
}

pub fn walk_expr_alloc<'a, V>(visitor: &mut V, expr: &'a Expr<'a>) -> Option<&'a Expr<'a>>
where
    V: ?Sized + Visitor<'a>,
{
    walk_expr(visitor, expr).map(|expr| &*visitor.allocator().arena.alloc(expr))
}

pub fn walk_expr<'a, V>(visitor: &mut V, expr: &'a Expr<'a>) -> Option<Expr<'a>>
where
    V: ?Sized + Visitor<'a>,
{
    match *expr {
        Expr::Call(f, args) => {
            let new_f = walk_expr_alloc(visitor, f);
            let new_args = merge_iter(args, |expr| walk_expr(visitor, expr), Expr::clone)
                .map(|exprs: Vec<_>| {
                    &*visitor.allocator().arena.alloc_extend(exprs.into_iter())
                });

            merge(&f, new_f, &args, new_args, Expr::Call)
        }
        Expr::Const(_, _) => None,
        Expr::Data(ref id, exprs, pos, expansion) => {
            merge_iter(exprs, |expr| walk_expr(visitor, expr), Expr::clone).map(|exprs: Vec<_>| {
                Expr::Data(
                    id.clone(),
                    visitor.allocator().arena.alloc_extend(exprs.into_iter()),
                    pos,
                    expansion,
                )
            })
        }
        Expr::Ident(_, _) => None,
        Expr::Let(ref bind, expr) => {
            let new_named = match bind.expr {
                Named::Recursive(ref closures) => {
                    merge_iter(
                        closures,
                        |closure| {
                            walk_expr_alloc(visitor, closure.expr).map(|new_expr| {
                                Closure {
                                    name: closure.name.clone(),
                                    args: closure.args.clone(),
                                    expr: new_expr,
                                }
                            })
                        },
                        Closure::clone,
                    ).map(Named::Recursive)
                }
                Named::Expr(bind_expr) => walk_expr_alloc(visitor, bind_expr).map(Named::Expr),
            };
            let new_bind = new_named.map(|named| {
                LetBinding {
                    name: bind.name.clone(),
                    expr: named,
                    span_start: bind.span_start,
                }
            });
            let new_expr = walk_expr_alloc(visitor, expr);
            merge(bind, new_bind, &expr, new_expr, Expr::Let)
        }
        Expr::Match(expr, alts) => {
            let new_expr = walk_expr_alloc(visitor, expr);
            let new_alts = merge_iter(alts, |expr| walk_alt(visitor, expr), Alternative::clone)
                .map(|alts: Vec<_>| {
                    &*visitor
                        .allocator()
                        .alternative_arena
                        .alloc_extend(alts.into_iter())
                });
            merge(&expr, new_expr, &alts, new_alts, Expr::Match)
        }
    }
}

fn walk_alt<'a, V>(visitor: &mut V, alt: &'a Alternative<'a>) -> Option<Alternative<'a>>
where
    V: ?Sized + Visitor<'a>,
{
    let new_expr = walk_expr_alloc(visitor, alt.expr);
    new_expr.map(|expr| {
        Alternative {
            pattern: alt.pattern.clone(),
            expr: expr,
        }
    })
}

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

    use base::symbol::Symbols;

    use core;
    use core::grammar::parse_Expr as parse_core_expr;

    #[test]
    fn unnecessary_allocation() {
        let mut symbols = Symbols::new();
        let allocator = core::Allocator::new();

        let initial_str = r#"
            match { l, r } with
            | { l, r } -> l
            end
            "#;
        let initial_expr = allocator.arena.alloc(
            parse_core_expr(&mut symbols, &allocator, initial_str).unwrap(),
        );

        let optimized_expr = optimize(&allocator, initial_expr);

        let expected_str = r#"
            let l = l
            in
            let r = r
            in
            l
            "#;
        let expected_expr = parse_core_expr(&mut symbols, &allocator, expected_str).unwrap();
        assert_deq!(*optimized_expr, expected_expr);
    }
}
<commit_msg>fix: Correctly visit all core expressions when walking the tree<commit_after>use base::ast::TypedIdent;
use base::merge::{merge, merge_iter};
use base::pos;

use core::{Allocator, Alternative, Closure, Expr, Named, LetBinding, Pattern};

pub trait Visitor<'a> {
    fn visit_expr(&mut self, expr: &'a Expr<'a>) -> Option<&'a Expr<'a>>;
    fn allocator(&self) -> &'a Allocator<'a>;
}

struct RecognizeUnnecessaryAllocation<'a> {
    allocator: &'a Allocator<'a>,
}

impl<'a> Visitor<'a> for RecognizeUnnecessaryAllocation<'a> {
    fn visit_expr(&mut self, expr: &'a Expr<'a>) -> Option<&'a Expr<'a>> {
        // Avoids boxing data which are destructured immediately after creation
        // match { l, r } with
        // | { l, r } -> ...
        //
        // to
        //
        // let l = x
        // let l = y
        // ...
        match *expr {
            Expr::Match(&Expr::Data(ref id, exprs, ..), alts) if alts.len() == 1 => {
                match alts[0].pattern {
                    Pattern::Record(ref fields) => {
                        debug_assert!(id.typ.row_iter().len() >= fields.len());
                        let next_expr = alts[0].expr;
                        Some(
                            id.typ
                                .row_iter()
                                .zip(exprs)
                                .collect::<Vec<_>>()
                                .into_iter()
                                .rev()
                                .fold(next_expr, |next_expr, (field, expr)| {
                                    let pattern_field = fields
                                        .iter()
                                        .find(|f| f.0.name.name_eq(&field.name))
                                        .unwrap();
                                    let pattern_field =
                                        pattern_field.1.as_ref().unwrap_or(&pattern_field.0.name);
                                    let new_expr = Expr::Let(
                                        LetBinding {
                                            name: TypedIdent {
                                                name: pattern_field.clone(),
                                                typ: field.typ.clone(),
                                            },
                                            expr: Named::Expr(expr),
                                            span_start: pos::BytePos::default(),
                                        },
                                        next_expr,
                                    );
                                    &*self.allocator().arena.alloc(new_expr)
                                }),
                        )
                    }
                    _ => walk_expr_alloc(self, expr),
                }
            }
            _ => walk_expr_alloc(self, expr),
        }
    }

    fn allocator(&self) -> &'a Allocator<'a> {
        self.allocator
    }
}

pub fn optimize<'a>(allocator: &'a Allocator<'a>, expr: &'a Expr<'a>) -> &'a Expr<'a> {
    let mut optimizer = RecognizeUnnecessaryAllocation { allocator: allocator };
    optimizer.visit_expr(expr).unwrap_or(expr)
}

pub fn walk_expr_alloc<'a, V>(visitor: &mut V, expr: &'a Expr<'a>) -> Option<&'a Expr<'a>>
where
    V: ?Sized + Visitor<'a>,
{
    walk_expr(visitor, expr).map(|expr| &*visitor.allocator().arena.alloc(expr))
}

pub fn walk_expr<'a, V>(visitor: &mut V, expr: &'a Expr<'a>) -> Option<Expr<'a>>
where
    V: ?Sized + Visitor<'a>,
{
    match *expr {
        Expr::Call(f, args) => {
            let new_f = visitor.visit_expr(f);
            let new_args = merge_iter(args, |expr| visitor.visit_expr(expr).cloned(), Expr::clone)
                .map(|exprs: Vec<_>| {
                    &*visitor.allocator().arena.alloc_extend(exprs.into_iter())
                });

            merge(&f, new_f, &args, new_args, Expr::Call)
        }
        Expr::Const(_, _) => None,
        Expr::Data(ref id, exprs, pos, expansion) => {
            merge_iter(exprs, |expr| visitor.visit_expr(expr).cloned(), Expr::clone).map(|exprs: Vec<_>| {
                Expr::Data(
                    id.clone(),
                    visitor.allocator().arena.alloc_extend(exprs.into_iter()),
                    pos,
                    expansion,
                )
            })
        }
        Expr::Ident(_, _) => None,
        Expr::Let(ref bind, expr) => {
            let new_named = match bind.expr {
                Named::Recursive(ref closures) => {
                    merge_iter(
                        closures,
                        |closure| {
                            visitor.visit_expr(closure.expr).map(|new_expr| {
                                Closure {
                                    name: closure.name.clone(),
                                    args: closure.args.clone(),
                                    expr: new_expr,
                                }
                            })
                        },
                        Closure::clone,
                    ).map(Named::Recursive)
                }
                Named::Expr(bind_expr) => visitor.visit_expr(bind_expr).map(Named::Expr),
            };
            let new_bind = new_named.map(|named| {
                LetBinding {
                    name: bind.name.clone(),
                    expr: named,
                    span_start: bind.span_start,
                }
            });
            let new_expr = visitor.visit_expr(expr);
            merge(bind, new_bind, &expr, new_expr, Expr::Let)
        }
        Expr::Match(expr, alts) => {
            let new_expr = visitor.visit_expr(expr);
            let new_alts = merge_iter(alts, |expr| walk_alt(visitor, expr), Alternative::clone)
                .map(|alts: Vec<_>| {
                    &*visitor
                        .allocator()
                        .alternative_arena
                        .alloc_extend(alts.into_iter())
                });
            merge(&expr, new_expr, &alts, new_alts, Expr::Match)
        }
    }
}

fn walk_alt<'a, V>(visitor: &mut V, alt: &'a Alternative<'a>) -> Option<Alternative<'a>>
where
    V: ?Sized + Visitor<'a>,
{
    let new_expr = visitor.visit_expr(alt.expr);
    new_expr.map(|expr| {
        Alternative {
            pattern: alt.pattern.clone(),
            expr: expr,
        }
    })
}

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

    use base::symbol::Symbols;

    use core;
    use core::grammar::parse_Expr as parse_core_expr;

    #[test]
    fn unnecessary_allocation() {
        let mut symbols = Symbols::new();
        let allocator = core::Allocator::new();

        let initial_str = r#"
            match { l, r } with
            | { l, r } -> l
            end
            "#;
        let initial_expr = allocator.arena.alloc(
            parse_core_expr(&mut symbols, &allocator, initial_str).unwrap(),
        );

        let optimized_expr = optimize(&allocator, initial_expr);

        let expected_str = r#"
            let l = l
            in
            let r = r
            in
            l
            "#;
        let expected_expr = parse_core_expr(&mut symbols, &allocator, expected_str).unwrap();
        assert_deq!(*optimized_expr, expected_expr);
    }
}
<|endoftext|>


<commit_before>//! Various C++-related types and functions needed for the `cpp_to_rust` project.

use std::ops::{Deref, DerefMut};
use std::ptr;

#[cfg(test)]
mod tests {
    use crate::{CppBox, CppDeletable};
    use std::cell::RefCell;
    use std::rc::Rc;

    struct Struct1 {
        value: Rc<RefCell<i32>>,
    }

    unsafe extern "C" fn struct1_delete(this_ptr: *mut Struct1) {
        (*this_ptr).value.borrow_mut().clone_from(&42);
    }

    impl CppDeletable for Struct1 {
        unsafe fn delete(&mut self) {
            struct1_delete(self);
        }
    }

    #[test]
    fn test_drop_calls_deleter() {
        let value1 = Rc::new(RefCell::new(10));
        let mut object1 = Struct1 {
            value: value1.clone(),
        };
        assert!(*value1.borrow() == 10);
        unsafe {
            CppBox::new(&mut object1 as *mut _);
        }
        assert!(*value1.borrow() == 42);
    }
}

/// Indicates that the type can be put into a CppBox.
///
/// Example of implementation:
/// ```
/// use cpp_utils::{CppDeletable};
///
/// struct Struct1;
///
/// unsafe extern "C" fn struct1_delete(this_ptr: *mut Struct1) {
///     unimplemented!()
/// }
///
/// impl CppDeletable for Struct1 {
///     unsafe fn delete(&mut self) {
///         struct1_delete(self)
///     }
/// }
/// ```
pub trait CppDeletable: Sized {
    /// Calls C++ `delete x` on `self`.
    unsafe fn delete(&mut self);
}

/// A C++ pointer wrapper to manage deletion of objects.
///
/// Objects of CppBox should be created by calling into_box() for
/// types that implement CppDeletable trait. The object will
/// be deleted when corresponding CppBox is deleted.
pub struct CppBox<T: CppDeletable>(*mut T);

impl<T: CppDeletable> CppBox<T> {
    /// Returns constant raw pointer to the value in the box.
    pub fn as_ptr(&self) -> *const T {
        self.0
    }
    /// Returns mutable raw pointer to the value in the box.
    pub fn as_mut_ptr(&self) -> *mut T {
        self.0
    }
    /// Returns the pointer that was used to create the object and destroys the box.
    /// The caller of the function becomes the owner of the object and should
    /// ensure that the object will be deleted at some point.
    pub fn into_raw(mut self) -> *mut T {
        let ptr = self.0;
        self.0 = ptr::null_mut();
        ptr
    }

    #[allow(clippy::should_implement_trait)]
    pub unsafe fn as_ref(&self) -> &T {
        self.0.as_ref().unwrap()
    }

    #[allow(clippy::should_implement_trait)]
    pub unsafe fn as_mut(&mut self) -> &mut T {
        self.0.as_mut().unwrap()
    }

    /// Returns true if the pointer is null.
    pub fn is_null(&self) -> bool {
        self.0.is_null()
    }
}

impl<T: CppDeletable> CppBox<T> {
    /// Encapsulates the object into a CppBox.
    ///
    /// You should use this function only for
    /// pointers that were created on C++ side and passed through
    /// a FFI boundary to Rust. An object created with C++ `new`
    /// must be deleted using C++ `delete`, which is executed by `CppBox`.
    ///
    /// Do not use this function for objects created in memory managed by Rust.
    /// Any wrapper constructor or function that returns an owned object
    /// is supposed to be deleted using Rust's ownage system and Drop trait.
    ///
    /// Do not use this function for objects that would be deleted by other means.
    /// If another C++ object is the owner of the passed object,
    /// it will attempt to delete it. If `CppBox` containing the object still exists,
    /// it would result in a double deletion, which should never happen.
    ///
    /// Use `CppBox::into_raw` to unwrap the pointer before passing it to
    /// a function that takes ownership of the object.
    ///
    /// It's permitted to put a null pointer into a `CppBox`. Deleter function
    /// will not be called for a null pointer. However, attempting to dereference
    /// a null pointer in a `CppBox`
    /// using `as_ref`, `as_mut`, `deref` or `deref_mut` will result in a panic.
    pub unsafe fn new(ptr: *mut T) -> CppBox<T> {
        CppBox(ptr)
    }
}

impl<T: CppDeletable> Deref for CppBox<T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { self.0.as_ref().unwrap() }
    }
}

impl<T: CppDeletable> DerefMut for CppBox<T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { self.0.as_mut().unwrap() }
    }
}

impl<T: CppDeletable> Drop for CppBox<T> {
    fn drop(&mut self) {
        if !self.0.is_null() {
            unsafe {
                T::delete(&mut *self.0);
            }
        }
    }
}

impl<T: CppDeletable> Default for CppBox<T> {
    fn default() -> CppBox<T> {
        CppBox(ptr::null_mut())
    }
}

/// Provides access to C++ `static_cast` conversion from derived class to base class.
///
/// This trait is automatically implemented by `cpp_to_rust`.
/// If `T1` class is derived (in C++) from `T2` class,
/// `StaticCast<T2>` is implemented for `T1`.
///
/// `StaticCast` allows to convert a reference to a class into
/// a reference to a base class.
///
/// `static_cast` and `static_cast_mut` free functions can be used
/// to convert pointer types.
///
/// Note that Rust functions associated with this trait have runtime overhead.
/// In C++, `static_cast` is usually a no-op if there is no multiple inheritance,
/// and multiple inheritance requires pointer adjustment. However, Rust compiler
/// and `cpp_to_rust` do not have any information about these implementation details,
/// so all calls of `static_cast` are wrapper in FFI functions.
/// Still, `static_cast` is faster than casts with runtime checks on C++ side
/// because runtime overhead of Rust wrapper functions is the same for all cast types.
pub trait StaticUpcast<T> {
    /// Convert type of a const reference.
    unsafe fn static_upcast(&self) -> ConstPtr<T>;
    /// Convert type of a mutable reference.
    unsafe fn static_upcast_mut(&mut self) -> Ptr<T>;
}

/// Converts type of a const pointer using `StaticCast` implementation of the type.
/// If `ptr` is null, this function does nothing and returns null pointer.
pub unsafe fn static_upcast<R, T: StaticUpcast<R>>(value: &T) -> ConstPtr<R> {
    value.static_upcast()
}

/// Converts type of a mutable pointer using `StaticCast` implementation of the type.
/// If `ptr` is null, this function does nothing and returns null pointer.
pub unsafe fn static_upcast_mut<R, T: StaticUpcast<R>>(value: &mut T) -> Ptr<R> {
    value.static_upcast_mut()
}

/// Provides access to C++ `static_cast` conversion from base class to derived class.
///
/// This trait is automatically implemented by `cpp_to_rust`.
/// If `T1` class is derived (in C++) from `T2` class,
/// `UnsafeStaticCast<T1>` is implemented for `T2`.
///
/// `UnsafeStaticCast` allows to convert a reference to a class into
/// a reference to a derived class without runtime check of the type.
/// Casting from base class type to a derived class type which is
/// not the actual type of the object will result in an invalid reference.
///
/// `unsafe_static_cast` and `unsafe_static_cast_mut` free functions can be used
/// to convert pointer types.
///
/// Note that Rust functions associated with this trait have runtime overhead.
/// In C++, `static_cast` is usually a no-op if there is no multiple inheritance,
/// and multiple inheritance requires pointer adjustment. However, Rust compiler
/// and `cpp_to_rust` do not have any information about these implementation details,
/// so all calls of `static_cast` are wrapper in FFI functions.
/// Still, `static_cast` is faster than casts with runtime checks on C++ side
/// because runtime overhead of Rust wrapper functions is the same for all cast types.
pub trait StaticDowncast<T> {
    /// Convert type of a const reference.
    unsafe fn static_downcast(&self) -> ConstPtr<T>;
    /// Convert type of a mutable reference.
    unsafe fn static_downcast_mut(&mut self) -> Ptr<T>;
}

/// Converts type of a const pointer using `UnsafeStaticCast` implementation of the type.
/// `ptr` must be either a null pointer or a valid pointer to an instance of `R` class
/// or a class derived from `R`.
/// If `ptr` is null, this function does nothing and returns null pointer.
pub unsafe fn static_downcast<R, T: StaticDowncast<R>>(value: &T) -> ConstPtr<R> {
    value.static_downcast()
}

/// Converts type of a mutable pointer using `UnsafeStaticCast` implementation of the type.
/// `ptr` must be either a null pointer or a valid pointer to an instance of `R` class
/// or a class derived from `R`.
/// If `ptr` is null, this function does nothing and returns null pointer.
pub unsafe fn static_downcast_mut<R, T: StaticDowncast<R>>(value: &mut T) -> Ptr<R> {
    value.static_downcast_mut()
}

/// Provides access to C++ `dynamic_cast` conversion.
///
/// This trait is automatically implemented by `cpp_to_rust`.
/// If `T1` class is derived (in C++) from `T2` class,
/// `DynamicCast<T1>` is implemented for `T2`.
/// Use `StaticCast` to convert from `T1` to `T2`.
///
/// `DynamicCast` allows to convert a reference to a class into
/// a reference to a derived class with a runtime check of the type.
/// Conversion returns `None` if the object is actually not an instance of
/// the target type.
///
/// `dynamic_cast` and `dynamic_cast_mut` free functions can be used
/// to convert pointer types.
pub trait DynamicCast<T> {
    /// Convert type of a const reference.
    /// Returns `None` if `self` is not an instance of `T`.
    unsafe fn dynamic_cast(&self) -> Option<ConstPtr<T>>;
    /// Convert type of a mutable reference.
    /// Returns `None` if `self` is not an instance of `T`.
    unsafe fn dynamic_cast_mut(&mut self) -> Option<Ptr<T>>;
}

/// Converts type of a const pointer using `DynamicCast` implementation of the type.
/// `ptr` must be either a null pointer or a valid pointer to an instance of `T` class
/// or a class derived from `T`.
/// Returns null pointer if `ptr` does not point to an instance of `R` or an instance of
/// a class derived from `R`.
/// If `ptr` is null, this function does nothing and returns null pointer.

pub unsafe fn dynamic_cast<R, T: DynamicCast<R>>(value: &T) -> Option<ConstPtr<R>> {
    value.dynamic_cast()
}

/// Converts type of a mutable pointer using `DynamicCast` implementation of the type.
/// `ptr` must be either a null pointer or a valid pointer to an instance of `T` class
/// or a class derived from `T`.
/// Returns null pointer if `ptr` does not point to an instance of `R`.
/// If `ptr` is null, this function does nothing and returns null pointer.
pub unsafe fn dynamic_cast_mut<R, T: DynamicCast<R>>(value: &mut T) -> Option<Ptr<R>> {
    value.dynamic_cast_mut()
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Ptr<T>(*mut T);

impl<T> Ptr<T> {
    pub unsafe fn new(ptr: *mut T) -> Self {
        Ptr(ptr)
    }

    pub unsafe fn new_option(ptr: *mut T) -> Option<Self> {
        if ptr.is_null() {
            None
        } else {
            Some(Ptr(ptr))
        }
    }

    /// Returns constant raw pointer to the value in the box.
    pub fn as_ptr(&self) -> *const T {
        self.0
    }

    /// Returns mutable raw pointer to the value in the box.
    pub fn as_mut_ptr(&self) -> *mut T {
        self.0
    }

    /// Returns true if the pointer is null.
    pub fn is_null(&self) -> bool {
        self.0.is_null()
    }
}

impl<T> Deref for Ptr<T> {
    type Target = T;

    fn deref(&self) -> &T {
        if self.0.is_null() {
            panic!("attempted to deref a null Ptr<T>");
        }
        unsafe { &(*self.0) }
    }
}

impl<T> DerefMut for Ptr<T> {
    fn deref_mut(&mut self) -> &mut T {
        if self.0.is_null() {
            panic!("attempted to deref a null Ptr<T>");
        }
        unsafe { &mut (*self.0) }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ConstPtr<T>(*const T);

impl<T> ConstPtr<T> {
    pub unsafe fn new(ptr: *const T) -> Self {
        ConstPtr(ptr)
    }

    pub unsafe fn new_option(ptr: *const T) -> Option<Self> {
        if ptr.is_null() {
            None
        } else {
            Some(ConstPtr(ptr))
        }
    }

    /// Returns constant raw pointer to the value in the box.
    pub fn as_ptr(&self) -> *const T {
        self.0
    }

    /// Returns true if the pointer is null.
    pub fn is_null(&self) -> bool {
        self.0.is_null()
    }
}

impl<T> Deref for ConstPtr<T> {
    type Target = T;

    fn deref(&self) -> &T {
        if self.0.is_null() {
            panic!("attempted to deref a null ConstPtr<T>");
        }
        unsafe { &(*self.0) }
    }
}
<commit_msg>add Ptr::to_box<commit_after>//! Various C++-related types and functions needed for the `cpp_to_rust` project.

use std::ops::{Deref, DerefMut};
use std::ptr;

#[cfg(test)]
mod tests {
    use crate::{CppBox, CppDeletable};
    use std::cell::RefCell;
    use std::rc::Rc;

    struct Struct1 {
        value: Rc<RefCell<i32>>,
    }

    unsafe extern "C" fn struct1_delete(this_ptr: *mut Struct1) {
        (*this_ptr).value.borrow_mut().clone_from(&42);
    }

    impl CppDeletable for Struct1 {
        unsafe fn delete(&mut self) {
            struct1_delete(self);
        }
    }

    #[test]
    fn test_drop_calls_deleter() {
        let value1 = Rc::new(RefCell::new(10));
        let mut object1 = Struct1 {
            value: value1.clone(),
        };
        assert!(*value1.borrow() == 10);
        unsafe {
            CppBox::new(&mut object1 as *mut _);
        }
        assert!(*value1.borrow() == 42);
    }
}

/// Indicates that the type can be put into a CppBox.
///
/// Example of implementation:
/// ```
/// use cpp_utils::{CppDeletable};
///
/// struct Struct1;
///
/// unsafe extern "C" fn struct1_delete(this_ptr: *mut Struct1) {
///     unimplemented!()
/// }
///
/// impl CppDeletable for Struct1 {
///     unsafe fn delete(&mut self) {
///         struct1_delete(self)
///     }
/// }
/// ```
pub trait CppDeletable: Sized {
    /// Calls C++ `delete x` on `self`.
    unsafe fn delete(&mut self);
}

/// A C++ pointer wrapper to manage deletion of objects.
///
/// Objects of CppBox should be created by calling into_box() for
/// types that implement CppDeletable trait. The object will
/// be deleted when corresponding CppBox is deleted.
pub struct CppBox<T: CppDeletable>(*mut T);

impl<T: CppDeletable> CppBox<T> {
    /// Returns constant raw pointer to the value in the box.
    pub fn as_ptr(&self) -> *const T {
        self.0
    }
    /// Returns mutable raw pointer to the value in the box.
    pub fn as_mut_ptr(&self) -> *mut T {
        self.0
    }
    /// Returns the pointer that was used to create the object and destroys the box.
    /// The caller of the function becomes the owner of the object and should
    /// ensure that the object will be deleted at some point.
    pub fn into_raw(mut self) -> *mut T {
        let ptr = self.0;
        self.0 = ptr::null_mut();
        ptr
    }

    #[allow(clippy::should_implement_trait)]
    pub unsafe fn as_ref(&self) -> &T {
        self.0.as_ref().unwrap()
    }

    #[allow(clippy::should_implement_trait)]
    pub unsafe fn as_mut(&mut self) -> &mut T {
        self.0.as_mut().unwrap()
    }

    /// Returns true if the pointer is null.
    pub fn is_null(&self) -> bool {
        self.0.is_null()
    }
}

impl<T: CppDeletable> CppBox<T> {
    /// Encapsulates the object into a CppBox.
    ///
    /// You should use this function only for
    /// pointers that were created on C++ side and passed through
    /// a FFI boundary to Rust. An object created with C++ `new`
    /// must be deleted using C++ `delete`, which is executed by `CppBox`.
    ///
    /// Do not use this function for objects created in memory managed by Rust.
    /// Any wrapper constructor or function that returns an owned object
    /// is supposed to be deleted using Rust's ownage system and Drop trait.
    ///
    /// Do not use this function for objects that would be deleted by other means.
    /// If another C++ object is the owner of the passed object,
    /// it will attempt to delete it. If `CppBox` containing the object still exists,
    /// it would result in a double deletion, which should never happen.
    ///
    /// Use `CppBox::into_raw` to unwrap the pointer before passing it to
    /// a function that takes ownership of the object.
    ///
    /// It's permitted to put a null pointer into a `CppBox`. Deleter function
    /// will not be called for a null pointer. However, attempting to dereference
    /// a null pointer in a `CppBox`
    /// using `as_ref`, `as_mut`, `deref` or `deref_mut` will result in a panic.
    pub unsafe fn new(ptr: *mut T) -> CppBox<T> {
        CppBox(ptr)
    }
}

impl<T: CppDeletable> Deref for CppBox<T> {
    type Target = T;
    fn deref(&self) -> &T {
        unsafe { self.0.as_ref().unwrap() }
    }
}

impl<T: CppDeletable> DerefMut for CppBox<T> {
    fn deref_mut(&mut self) -> &mut T {
        unsafe { self.0.as_mut().unwrap() }
    }
}

impl<T: CppDeletable> Drop for CppBox<T> {
    fn drop(&mut self) {
        if !self.0.is_null() {
            unsafe {
                T::delete(&mut *self.0);
            }
        }
    }
}

impl<T: CppDeletable> Default for CppBox<T> {
    fn default() -> CppBox<T> {
        CppBox(ptr::null_mut())
    }
}

/// Provides access to C++ `static_cast` conversion from derived class to base class.
///
/// This trait is automatically implemented by `cpp_to_rust`.
/// If `T1` class is derived (in C++) from `T2` class,
/// `StaticCast<T2>` is implemented for `T1`.
///
/// `StaticCast` allows to convert a reference to a class into
/// a reference to a base class.
///
/// `static_cast` and `static_cast_mut` free functions can be used
/// to convert pointer types.
///
/// Note that Rust functions associated with this trait have runtime overhead.
/// In C++, `static_cast` is usually a no-op if there is no multiple inheritance,
/// and multiple inheritance requires pointer adjustment. However, Rust compiler
/// and `cpp_to_rust` do not have any information about these implementation details,
/// so all calls of `static_cast` are wrapper in FFI functions.
/// Still, `static_cast` is faster than casts with runtime checks on C++ side
/// because runtime overhead of Rust wrapper functions is the same for all cast types.
pub trait StaticUpcast<T> {
    /// Convert type of a const reference.
    unsafe fn static_upcast(&self) -> ConstPtr<T>;
    /// Convert type of a mutable reference.
    unsafe fn static_upcast_mut(&mut self) -> Ptr<T>;
}

/// Converts type of a const pointer using `StaticCast` implementation of the type.
/// If `ptr` is null, this function does nothing and returns null pointer.
pub unsafe fn static_upcast<R, T: StaticUpcast<R>>(value: &T) -> ConstPtr<R> {
    value.static_upcast()
}

/// Converts type of a mutable pointer using `StaticCast` implementation of the type.
/// If `ptr` is null, this function does nothing and returns null pointer.
pub unsafe fn static_upcast_mut<R, T: StaticUpcast<R>>(value: &mut T) -> Ptr<R> {
    value.static_upcast_mut()
}

/// Provides access to C++ `static_cast` conversion from base class to derived class.
///
/// This trait is automatically implemented by `cpp_to_rust`.
/// If `T1` class is derived (in C++) from `T2` class,
/// `UnsafeStaticCast<T1>` is implemented for `T2`.
///
/// `UnsafeStaticCast` allows to convert a reference to a class into
/// a reference to a derived class without runtime check of the type.
/// Casting from base class type to a derived class type which is
/// not the actual type of the object will result in an invalid reference.
///
/// `unsafe_static_cast` and `unsafe_static_cast_mut` free functions can be used
/// to convert pointer types.
///
/// Note that Rust functions associated with this trait have runtime overhead.
/// In C++, `static_cast` is usually a no-op if there is no multiple inheritance,
/// and multiple inheritance requires pointer adjustment. However, Rust compiler
/// and `cpp_to_rust` do not have any information about these implementation details,
/// so all calls of `static_cast` are wrapper in FFI functions.
/// Still, `static_cast` is faster than casts with runtime checks on C++ side
/// because runtime overhead of Rust wrapper functions is the same for all cast types.
pub trait StaticDowncast<T> {
    /// Convert type of a const reference.
    unsafe fn static_downcast(&self) -> ConstPtr<T>;
    /// Convert type of a mutable reference.
    unsafe fn static_downcast_mut(&mut self) -> Ptr<T>;
}

/// Converts type of a const pointer using `UnsafeStaticCast` implementation of the type.
/// `ptr` must be either a null pointer or a valid pointer to an instance of `R` class
/// or a class derived from `R`.
/// If `ptr` is null, this function does nothing and returns null pointer.
pub unsafe fn static_downcast<R, T: StaticDowncast<R>>(value: &T) -> ConstPtr<R> {
    value.static_downcast()
}

/// Converts type of a mutable pointer using `UnsafeStaticCast` implementation of the type.
/// `ptr` must be either a null pointer or a valid pointer to an instance of `R` class
/// or a class derived from `R`.
/// If `ptr` is null, this function does nothing and returns null pointer.
pub unsafe fn static_downcast_mut<R, T: StaticDowncast<R>>(value: &mut T) -> Ptr<R> {
    value.static_downcast_mut()
}

/// Provides access to C++ `dynamic_cast` conversion.
///
/// This trait is automatically implemented by `cpp_to_rust`.
/// If `T1` class is derived (in C++) from `T2` class,
/// `DynamicCast<T1>` is implemented for `T2`.
/// Use `StaticCast` to convert from `T1` to `T2`.
///
/// `DynamicCast` allows to convert a reference to a class into
/// a reference to a derived class with a runtime check of the type.
/// Conversion returns `None` if the object is actually not an instance of
/// the target type.
///
/// `dynamic_cast` and `dynamic_cast_mut` free functions can be used
/// to convert pointer types.
pub trait DynamicCast<T> {
    /// Convert type of a const reference.
    /// Returns `None` if `self` is not an instance of `T`.
    unsafe fn dynamic_cast(&self) -> Option<ConstPtr<T>>;
    /// Convert type of a mutable reference.
    /// Returns `None` if `self` is not an instance of `T`.
    unsafe fn dynamic_cast_mut(&mut self) -> Option<Ptr<T>>;
}

/// Converts type of a const pointer using `DynamicCast` implementation of the type.
/// `ptr` must be either a null pointer or a valid pointer to an instance of `T` class
/// or a class derived from `T`.
/// Returns null pointer if `ptr` does not point to an instance of `R` or an instance of
/// a class derived from `R`.
/// If `ptr` is null, this function does nothing and returns null pointer.

pub unsafe fn dynamic_cast<R, T: DynamicCast<R>>(value: &T) -> Option<ConstPtr<R>> {
    value.dynamic_cast()
}

/// Converts type of a mutable pointer using `DynamicCast` implementation of the type.
/// `ptr` must be either a null pointer or a valid pointer to an instance of `T` class
/// or a class derived from `T`.
/// Returns null pointer if `ptr` does not point to an instance of `R`.
/// If `ptr` is null, this function does nothing and returns null pointer.
pub unsafe fn dynamic_cast_mut<R, T: DynamicCast<R>>(value: &mut T) -> Option<Ptr<R>> {
    value.dynamic_cast_mut()
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Ptr<T>(*mut T);

impl<T> Ptr<T> {
    pub unsafe fn new(ptr: *mut T) -> Self {
        Ptr(ptr)
    }

    pub unsafe fn new_option(ptr: *mut T) -> Option<Self> {
        if ptr.is_null() {
            None
        } else {
            Some(Ptr(ptr))
        }
    }

    /// Returns constant raw pointer to the value in the box.
    pub fn as_ptr(&self) -> *const T {
        self.0
    }

    /// Returns mutable raw pointer to the value in the box.
    pub fn as_mut_ptr(&self) -> *mut T {
        self.0
    }

    /// Returns true if the pointer is null.
    pub fn is_null(&self) -> bool {
        self.0.is_null()
    }
}

impl<T: CppDeletable> Ptr<T> {
    pub unsafe fn to_box(&self) -> CppBox<T> {
        CppBox::new(self.0)
    }
}

impl<T> Deref for Ptr<T> {
    type Target = T;

    fn deref(&self) -> &T {
        if self.0.is_null() {
            panic!("attempted to deref a null Ptr<T>");
        }
        unsafe { &(*self.0) }
    }
}

impl<T> DerefMut for Ptr<T> {
    fn deref_mut(&mut self) -> &mut T {
        if self.0.is_null() {
            panic!("attempted to deref a null Ptr<T>");
        }
        unsafe { &mut (*self.0) }
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ConstPtr<T>(*const T);

impl<T> ConstPtr<T> {
    pub unsafe fn new(ptr: *const T) -> Self {
        ConstPtr(ptr)
    }

    pub unsafe fn new_option(ptr: *const T) -> Option<Self> {
        if ptr.is_null() {
            None
        } else {
            Some(ConstPtr(ptr))
        }
    }

    /// Returns constant raw pointer to the value in the box.
    pub fn as_ptr(&self) -> *const T {
        self.0
    }

    /// Returns true if the pointer is null.
    pub fn is_null(&self) -> bool {
        self.0.is_null()
    }
}

impl<T> Deref for ConstPtr<T> {
    type Target = T;

    fn deref(&self) -> &T {
        if self.0.is_null() {
            panic!("attempted to deref a null ConstPtr<T>");
        }
        unsafe { &(*self.0) }
    }
}
<|endoftext|>


<commit_before><commit_msg>Another attempt at RetryPolicy<commit_after><|endoftext|>


<commit_before>//! Generating Graphviz `dot` files from our IR.

use super::context::{BindgenContext, ItemId};
use super::traversal::Trace;
use std::fs::File;
use std::io::{self, Write};
use std::path::Path;

/// A trait for anything that can write attributes as `<table>` rows to a dot
/// file.
pub trait DotAttributes {
    /// Write this thing's attributes to the given output. Each attribute must
    /// be its own `<tr>...</tr>`.
    fn dot_attributes<W>(&self,
                         ctx: &BindgenContext,
                         out: &mut W)
                         -> io::Result<()>
        where W: io::Write;
}

/// Write a graphviz dot file containing our IR.
pub fn write_dot_file
(ctx: &BindgenContext, path: P) -> io::Result<()>
    where P: AsRef<Path>,
{
    let file = try!(File::create(path));
    let mut dot_file = io::BufWriter::new(file);
    try!(writeln!(&mut dot_file, "digraph {{"));

    let mut err: Option<io::Result<_>> = None;

    for (id, item) in ctx.items() {
        try!(writeln!(&mut dot_file,
                      r#"{} [fontname="courier", label=<
"#,
                      id.as_usize()));
        try!(item.dot_attributes(ctx, &mut dot_file));
        try!(writeln!(&mut dot_file, r#"
 >];"#));

        item.trace(ctx,
                   &mut |sub_id: ItemId, _edge_kind| {
            if err.is_some() {
                return;
            }

            match writeln!(&mut dot_file,
                           "{} -> {};",
                           id.as_usize(),
                           sub_id.as_usize()) {
                Ok(_) => {}
                Err(e) => err = Some(Err(e)),
            }
        },
                   &());

        if let Some(err) = err {
            return err;
        }
    }

    try!(writeln!(&mut dot_file, "}}"));
    Ok(())
}
<commit_msg>Add edge labels to our graphviz output<commit_after>//! Generating Graphviz `dot` files from our IR.

use super::context::{BindgenContext, ItemId};
use super::traversal::Trace;
use std::fs::File;
use std::io::{self, Write};
use std::path::Path;

/// A trait for anything that can write attributes as `<table>` rows to a dot
/// file.
pub trait DotAttributes {
    /// Write this thing's attributes to the given output. Each attribute must
    /// be its own `<tr>...</tr>`.
    fn dot_attributes<W>(&self,
                         ctx: &BindgenContext,
                         out: &mut W)
                         -> io::Result<()>
        where W: io::Write;
}

/// Write a graphviz dot file containing our IR.
pub fn write_dot_file
(ctx: &BindgenContext, path: P) -> io::Result<()>
    where P: AsRef<Path>,
{
    let file = try!(File::create(path));
    let mut dot_file = io::BufWriter::new(file);
    try!(writeln!(&mut dot_file, "digraph {{"));

    let mut err: Option<io::Result<_>> = None;

    for (id, item) in ctx.items() {
        try!(writeln!(&mut dot_file,
                      r#"{} [fontname="courier", label=<
"#,
                      id.as_usize()));
        try!(item.dot_attributes(ctx, &mut dot_file));
        try!(writeln!(&mut dot_file, r#"
 >];"#));

        item.trace(ctx,
                   &mut |sub_id: ItemId, edge_kind| {
            if err.is_some() {
                return;
            }

            match writeln!(&mut dot_file,
                           "{} -> {} [label={:?}];",
                           id.as_usize(),
                           sub_id.as_usize(),
                           edge_kind) {
                Ok(_) => {}
                Err(e) => err = Some(Err(e)),
            }
        },
                   &());

        if let Some(err) = err {
            return err;
        }
    }

    try!(writeln!(&mut dot_file, "}}"));
    Ok(())
}
<|endoftext|>


<commit_before>//! Generating Graphviz `dot` files from our IR.

use super::context::{BindgenContext, ItemId};
use super::traversal::Trace;
use std::fs::File;
use std::io::{self, Write};
use std::path::Path;

/// A trait for anything that can write attributes as `<table>` rows to a dot
/// file.
pub trait DotAttributes {
    /// Write this thing's attributes to the given output. Each attribute must
    /// be its own `<tr>...</tr>`.
    fn dot_attributes<W>(
        &self,
        ctx: &BindgenContext,
        out: &mut W,
    ) -> io::Result<()>
    where
        W: io::Write;
}

/// Write a graphviz dot file containing our IR.
pub fn write_dot_file
(ctx: &BindgenContext, path: P) -> io::Result<()>
where
    P: AsRef<Path>,
{
    let file = try!(File::create(path));
    let mut dot_file = io::BufWriter::new(file);
    try!(writeln!(&mut dot_file, "digraph {{"));

    let mut err: Option<io::Result<_>> = None;

    for (id, item) in ctx.items() {
        try!(writeln!(
            &mut dot_file,
            r#"{} [fontname="courier", label=<
"#,
            id.as_usize()
        ));
        try!(item.dot_attributes(ctx, &mut dot_file));
        try!(writeln!(&mut dot_file, r#"
 >];"#));

        item.trace(
            ctx,
            &mut |sub_id: ItemId, edge_kind| {
                if err.is_some() {
                    return;
                }

                match writeln!(
                    &mut dot_file,
                    "{} -> {} [label={:?}];",
                    id.as_usize(),
                    sub_id.as_usize(),
                    edge_kind
                ) {
                    Ok(_) => {}
                    Err(e) => err = Some(Err(e)),
                }
            },
            &(),
        );

        if let Some(err) = err {
            return err;
        }

        if let Some(module) = item.as_module() {
            for child in module.children() {
                try!(writeln!(
                    &mut dot_file,
                    "{} -> {} [style=dotted]",
                    item.id().as_usize(),
                    child.as_usize()
                ));
            }
        }
    }

    try!(writeln!(&mut dot_file, "}}"));
    Ok(())
}
<commit_msg>Reflect whitelisted status via color in graphviz dot files<commit_after>//! Generating Graphviz `dot` files from our IR.

use super::context::{BindgenContext, ItemId};
use super::traversal::Trace;
use std::fs::File;
use std::io::{self, Write};
use std::path::Path;

/// A trait for anything that can write attributes as `<table>` rows to a dot
/// file.
pub trait DotAttributes {
    /// Write this thing's attributes to the given output. Each attribute must
    /// be its own `<tr>...</tr>`.
    fn dot_attributes<W>(
        &self,
        ctx: &BindgenContext,
        out: &mut W,
    ) -> io::Result<()>
    where
        W: io::Write;
}

/// Write a graphviz dot file containing our IR.
pub fn write_dot_file
(ctx: &BindgenContext, path: P) -> io::Result<()>
where
    P: AsRef<Path>,
{
    let file = try!(File::create(path));
    let mut dot_file = io::BufWriter::new(file);
    try!(writeln!(&mut dot_file, "digraph {{"));

    let mut err: Option<io::Result<_>> = None;

    for (id, item) in ctx.items() {
        let is_whitelisted = ctx.whitelisted_items().contains(id);

        try!(writeln!(
            &mut dot_file,
            r#"{} [fontname="courier", color={}, label=<
"#,
            id.as_usize(),
            if is_whitelisted {
                "black"
            } else {
                "gray"
            }
        ));
        try!(item.dot_attributes(ctx, &mut dot_file));
        try!(writeln!(&mut dot_file, r#"
 >];"#));

        item.trace(
            ctx,
            &mut |sub_id: ItemId, edge_kind| {
                if err.is_some() {
                    return;
                }

                match writeln!(
                    &mut dot_file,
                    "{} -> {} [label={:?}, color={}];",
                    id.as_usize(),
                    sub_id.as_usize(),
                    edge_kind,
                    if is_whitelisted {
                        "black"
                    } else {
                        "gray"
                    }
                ) {
                    Ok(_) => {}
                    Err(e) => err = Some(Err(e)),
                }
            },
            &(),
        );

        if let Some(err) = err {
            return err;
        }

        if let Some(module) = item.as_module() {
            for child in module.children() {
                try!(writeln!(
                    &mut dot_file,
                    "{} -> {} [style=dotted, color=gray]",
                    item.id().as_usize(),
                    child.as_usize()
                ));
            }
        }
    }

    try!(writeln!(&mut dot_file, "}}"));
    Ok(())
}
<|endoftext|>


<commit_before>extern crate emval_sys;

use emval_sys::*;

use std;
use std::sync::{Once, ONCE_INIT};

use jsobj::*;
use jsserialize::*;
use jsid::*;
use jsdeserialize::*;

pub trait JSFunc {
    fn to_object(self) -> JSObj;
}

macro_rules! count_idents {
    ( $_h:ident ) => {0};
    ( $_h:ident, $( $tail:ident ),*) => {1 + count_idents!($( $tail ),*)};
}

static mut TEMP_ID: usize = 0;

macro_rules! jsfunc_for {
    ( $signature:ident, $( $vals:ident => $args:ident ),* ) => {
        impl<RET, $( $args ),*> JSFunc for Box<Box<Fn($( $args ),*) -> RET>>
            where RET: JSSerialize, $( $args: JSDeserialize ),* {

            fn to_object(self) -> JSObj {
                pub extern fn helper_helper<RETP: JSSerialize, $( $args: JSDeserialize ),*>(hptr: usize, cptr: usize, $( $vals:usize ),*) -> EM_GENERIC_WIRE_TYPE {
                    let helper: Box<Box<Fn(usize, $( $args ),*) -> RETP>> = unsafe { Box::from_raw(hptr as _) };
                    let result = helper(cptr, $( $args::from_jsobj_id($vals as _) ),*);

                    unsafe {
                        $( _emval_decref($vals as _); )*
                    }

                    std::mem::forget(helper);

                    result.serialize()
                }

                // TODO make unique name for each realization of the templates
                let helper_name = unsafe {
                    format!("{}{}", concat!("rust_helper_", stringify!($signature)), TEMP_ID)
                };
                unsafe { TEMP_ID = TEMP_ID + 1; }
                static REGISTER: Once = ONCE_INIT;
                REGISTER.call_once(|| {
                    let mut arglist = vec![JSObj::id(); count_idents!($( $args ),*) + 2];
                    arglist[0] = RET::id();
                    arglist[1] = usize::id();

                    let helper = |cptr: usize, $( $vals:$args ),*| {
                        let closure: Box<Box<Fn($( $args ),*) -> RET>> = unsafe { Box::from_raw(cptr as _) };
                        let result = closure($( $vals ),*);

                        std::mem::forget(closure);

                        result
                    };

                    let helper_boxed = Box::new(Box::new(helper));

                    unsafe {
                        _embind_register_function(format!("{}\0", helper_name).as_ptr() as _,
                                                  count_idents!($( $args ),*) + 2,
                                                  arglist.as_ptr() as _,
                                                  concat!(stringify!($signature), '\0').as_ptr() as _,
                                                  helper_helper::<RET, $( $args ),*> as _,
                                                  Box::into_raw(helper_boxed) as _);
                    }
                });

                let self_ptr = Box::into_raw(self);
                let module = JSObj::global("Module");
                let helper = module.get_prop(&helper_name);
                let args = Args::new(vec![JSObj::id(), usize::id()], vec![module.serialize(), (self_ptr as usize).serialize()]);
                helper.call_prop("bind", args)
            }
        }
    }
}

jsfunc_for!(ii, a => A);
<commit_msg>added many types<commit_after>extern crate emval_sys;

use emval_sys::*;

use std;
use std::sync::{Once, ONCE_INIT};

use jsobj::*;
use jsserialize::*;
use jsid::*;
use jsdeserialize::*;

pub trait JSFunc {
    fn to_object(self) -> JSObj;
}

macro_rules! count_idents {
    ( $_h:ident ) => {0};
    ( $_h:ident, $( $tail:ident ),*) => {1 + count_idents!($( $tail ),*)};
}

static mut TEMP_ID: usize = 0;

macro_rules! jsfunc_for {
    ( $signature:ident, $( $vals:ident => $args:ident ),* ) => {
        impl<RET, $( $args ),*> JSFunc for Box<Box<Fn($( $args ),*) -> RET>>
            where RET: JSSerialize, $( $args: JSDeserialize ),* {

            fn to_object(self) -> JSObj {
                pub extern fn helper_helper<RETP: JSSerialize, $( $args: JSDeserialize ),*>(hptr: usize, cptr: usize, $( $vals:usize ),*) -> EM_GENERIC_WIRE_TYPE {
                    let helper: Box<Box<Fn(usize, $( $args ),*) -> RETP>> = unsafe { Box::from_raw(hptr as _) };
                    let result = helper(cptr, $( $args::from_jsobj_id($vals as _) ),*);

                    unsafe {
                        $( _emval_decref($vals as _); )*
                    }

                    std::mem::forget(helper);

                    result.serialize()
                }

                // TODO make unique name for each realization of the templates
                let helper_name = unsafe {
                    format!("{}{}", concat!("rust_helper_", stringify!($signature)), TEMP_ID)
                };
                unsafe { TEMP_ID = TEMP_ID + 1; }
                static REGISTER: Once = ONCE_INIT;
                REGISTER.call_once(|| {
                    let mut arglist = vec![JSObj::id(); count_idents!($( $args ),*) + 2];
                    arglist[0] = RET::id();
                    arglist[1] = usize::id();

                    let helper = |cptr: usize, $( $vals:$args ),*| {
                        let closure: Box<Box<Fn($( $args ),*) -> RET>> = unsafe { Box::from_raw(cptr as _) };
                        let result = closure($( $vals ),*);

                        std::mem::forget(closure);

                        result
                    };

                    let helper_boxed = Box::new(Box::new(helper));

                    unsafe {
                        _embind_register_function(format!("{}\0", helper_name).as_ptr() as _,
                                                  count_idents!($( $args ),*) + 2,
                                                  arglist.as_ptr() as _,
                                                  concat!(stringify!($signature), '\0').as_ptr() as _,
                                                  helper_helper::<RET, $( $args ),*> as _,
                                                  Box::into_raw(helper_boxed) as _);
                    }
                });

                let self_ptr = Box::into_raw(self);
                let module = JSObj::global("Module");
                let helper = module.get_prop(&helper_name);
                let args = Args::new(vec![JSObj::id(), usize::id()], vec![module.serialize(), (self_ptr as usize).serialize()]);
                helper.call_prop("bind", args)
            }
        }
    }
}

/*
 * putStrLn $ foldr ((++) . ("\n" ++)) "" $ map (("jsfunc_for!(" ++) . (++ ");")) $ map (\x -> (replicate x 'i') ++ foldr (++) "" [", a" ++ show y ++ " => A" ++ show y | y <- [1..x]]) [1..5]
 */
jsfunc_for!(i, a1 => A1);
jsfunc_for!(ii, a1 => A1, a2 => A2);
jsfunc_for!(iii, a1 => A1, a2 => A2, a3 => A3);
jsfunc_for!(iiii, a1 => A1, a2 => A2, a3 => A3, a4 => A4);
jsfunc_for!(iiiii, a1 => A1, a2 => A2, a3 => A3, a4 => A4, a5 => A5);
jsfunc_for!(iiiiii, a1 => A1, a2 => A2, a3 => A3, a4 => A4, a5 => A5, a6 => A6);
jsfunc_for!(iiiiiii, a1 => A1, a2 => A2, a3 => A3, a4 => A4, a5 => A5, a6 => A6, a7 => A7);
jsfunc_for!(iiiiiiii, a1 => A1, a2 => A2, a3 => A3, a4 => A4, a5 => A5, a6 => A6, a7 => A7, a8 => A8);
jsfunc_for!(iiiiiiiii, a1 => A1, a2 => A2, a3 => A3, a4 => A4, a5 => A5, a6 => A6, a7 => A7, a8 => A8, a9 => A9);
jsfunc_for!(iiiiiiiiii, a1 => A1, a2 => A2, a3 => A3, a4 => A4, a5 => A5, a6 => A6, a7 => A7, a8 => A8, a9 => A9, a10 => A10);
/*
 * TODO vi type
jsfunc_for!(v, a1 => A1);
jsfunc_for!(vi, a1 => A1, a2 => A2);
jsfunc_for!(vii, a1 => A1, a2 => A2, a3 => A3);
jsfunc_for!(viii, a1 => A1, a2 => A2, a3 => A3, a4 => A4);
jsfunc_for!(viiii, a1 => A1, a2 => A2, a3 => A3, a4 => A4, a5 => A5);
jsfunc_for!(viiiii, a1 => A1, a2 => A2, a3 => A3, a4 => A4, a5 => A5, a6 => A6);
jsfunc_for!(viiiiii, a1 => A1, a2 => A2, a3 => A3, a4 => A4, a5 => A5, a6 => A6, a7 => A7);
jsfunc_for!(viiiiiii, a1 => A1, a2 => A2, a3 => A3, a4 => A4, a5 => A5, a6 => A6, a7 => A7, a8 => A8);
jsfunc_for!(viiiiiiii, a1 => A1, a2 => A2, a3 => A3, a4 => A4, a5 => A5, a6 => A6, a7 => A7, a8 => A8, a9 => A9);
jsfunc_for!(viiiiiiiii, a1 => A1, a2 => A2, a3 => A3, a4 => A4, a5 => A5, a6 => A6, a7 => A7, a8 => A8, a9 => A9, a10 => A10);
*/
<|endoftext|>


<commit_before>//!Some helpful macros.

///The `insert_routes!` macro generates routes from the provided handlers and routing tree and
///adds them to the provided router. The router is then returned.
///
///This can be useful to lower the risk of typing errors, among other things.
///
///##Example 1
///
///```rust
///#[macro_use]
///extern crate rustful;
///use rustful::TreeRouter;
///# use rustful::{Handler, Context, Response};
///
///# struct DummyHandler;
///# impl Handler for DummyHandler {
///#     fn handle_request(&self, _: Context, _: Response){}
///# }
///# fn main() {
///# let about_us = DummyHandler;
///# let show_user = DummyHandler;
///# let show_product = DummyHandler;
///# let show_error = DummyHandler;
///# let show_welcome = DummyHandler;
///let router = insert_routes! {
///    TreeRouter::new() => {
///        "/" => Get: show_welcome,
///        "/about" => Get: about_us,
///        "/user/:user" => Get: show_user,
///        "/product/:name" => Get: show_product,
///        "/*" => Get: show_error
///    }
///};
///# }
///```
///
///##Example 2
///
///```rust
///#[macro_use]
///extern crate rustful;
///use rustful::TreeRouter;
///# use rustful::{Handler, Context, Response};
///
///# #[derive(Clone, Copy)]
///# struct DummyHandler;
///# impl Handler for DummyHandler {
///#     fn handle_request(&self, _: Context, _: Response){}
///# }
///# fn main() {
///# let show_home = DummyHandler;
///# let show_user = DummyHandler;
///# let save_user = DummyHandler;
///# let show_all_products = DummyHandler;
///# let send_all_product_data = DummyHandler;
///# let show_product = DummyHandler;
///# let edit_product = DummyHandler;
///# let send_product_data = DummyHandler;
///
///let mut router = TreeRouter::new();
///
///insert_routes! {
///    &mut router => {
///        Get: show_home,
///
///        "home" => Get: show_home,
///        "user/:username" => {
///            Get: show_user,
///            Post: save_user
///        },
///        "product" => {
///            Get: show_all_products,
///
///            "json" => Get: send_all_product_data,
///            ":id" => {
///                Get: show_product,
///                Post: edit_product,
///                Delete: edit_product,
///
///                "json" => Get: send_product_data
///            }
///        }
///    }
///};
///# }
///```
#[macro_export]
macro_rules! insert_routes {
    ($router:expr => {$($paths:tt)+}) => {
        {
            use $crate::Router;
            let mut router = $router;
            __rustful_insert_internal!(router, [], $($paths)+);
            router
        }
    }
}

//Internal stuff. Only meant to be used through `insert_routes!`.
#[doc(hidden)]
#[macro_export]
macro_rules! __rustful_insert_internal {
    ($router:ident, [$($steps:expr),*], $path:expr => {$($paths:tt)+}, $($next:tt)*) => {
        {
            __rustful_insert_internal!($router, [$($steps,)* $path], $($paths)*);
            __rustful_insert_internal!($router, [$($steps),*], $($next)*);
        }
    };
    ($router:ident, [$($steps:expr),*], $path:tt => {$($paths:tt)+}) => {
        {
            __rustful_insert_internal!($router, [$($steps,)* __rustful_to_expr!($path)], $($paths)*);
        }
    };
    ($router:ident, [$($steps:expr),*], $($method:tt)::+: $handler:expr, $($next:tt)*) => {
        {
            let method = {
                #[allow(unused_imports)]
                use $crate::Method::*;
                __rustful_to_path!($($method)::+)
            };
            let path = __rustful_route_expr!($($steps),*);
            $router.insert(method, path, $handler);
            __rustful_insert_internal!($router, [$($steps),*], $($next)*)
        }
    };
    ($router:ident, [$($steps:expr),*], $path:tt => $method:path: $handler:expr, $($next:tt)*) => {
        {
            let method = {
                #[allow(unused_imports)]
                use $crate::Method::*;
                $method
            };
            let path = __rustful_route_expr!($($steps,)* __rustful_to_expr!($path));
            $router.insert(method, path, $handler);
            __rustful_insert_internal!($router, [$($steps),*], $($next)*)
        }
    };
    ($router:ident, [$($steps:expr),*], $($method:tt)::+: $handler:expr) => {
        {
            let method = {
                #[allow(unused_imports)]
                use $crate::Method::*;
                __rustful_to_path!($($method)::+)
            };
            let path = __rustful_route_expr!($($steps),*);
            $router.insert(method, path, $handler);
        }
    };
    ($router:ident, [$($steps:expr),*], $path:tt => $method:path: $handler:expr) => {
        {
            let method = {
                #[allow(unused_imports)]
                use $crate::Method::*;
                $method
            };
            let path = __rustful_route_expr!($($steps,)* __rustful_to_expr!($path));
            $router.insert(method, path, $handler);
        }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __rustful_route_expr {
    () => ("");
    ($($path:expr),+) => (&[$($path),+][..]);
}

/**
A macro for making content types.

It takes a main type, a sub type and a parameter list. Instead of this:

```rust
use rustful::header::ContentType;
use rustful::mime::{Mime, TopLevel, SubLevel, Attr, Value};

ContentType(
    Mime (
        TopLevel::Text,
        SubLevel::Html,
        vec![(Attr::Charset, Value::Utf8)]
    )
);
```

it can be written like this:

```
#[macro_use]
extern crate rustful;
use rustful::header::ContentType;

# fn main() {
ContentType(content_type!(Text / Html; Charset = Utf8));
# }
```

The `Charset = Utf8` part defines the parameter list for the content type and
may contain more than one parameter, or be omitted. Here are some more
examples showing that and how strings can be used for more exotic values:

```
#[macro_use]
extern crate rustful;
use rustful::header::ContentType;

# fn main() {
ContentType(content_type!(Application / "octet-stream"; "type" = "image/gif"; "padding" = "4"));
# }
```

```
#[macro_use]
extern crate rustful;
use rustful::header::ContentType;

# fn main() {
ContentType(content_type!(Image / Png));
# }
```
**/
#[macro_export]
macro_rules! content_type {
    ($main_type:tt / $sub_type:tt) => ({
        use $crate::macros::MimeHelper;
        $crate::mime::Mime (
            {
                #[allow(unused_imports)]
                use $crate::mime::TopLevel::*;
                MimeHelper::from(__rustful_to_expr!($main_type)).convert()
            },
            {
                #[allow(unused_imports)]
                use $crate::mime::SubLevel::*;
                MimeHelper::from(__rustful_to_expr!($sub_type)).convert()
            },
            Vec::new()
        )
    });

    ($main_type:tt / $sub_type:tt; $($param:tt = $value:tt);+) => ({
        use $crate::macros::MimeHelper;
        $crate::mime::Mime (
            {
                #[allow(unused_imports)]
                use $crate::mime::TopLevel::*;
                MimeHelper::from(__rustful_to_expr!($main_type)).convert()
            },
            {
                #[allow(unused_imports)]
                use $crate::mime::SubLevel::*;
                MimeHelper::from(__rustful_to_expr!($sub_type)).convert()
            },
            vec![ $( ({
                #[allow(unused_imports)]
                use $crate::mime::Attr::*;
                MimeHelper::from(__rustful_to_expr!($param)).convert()
            }, {
                #[allow(unused_imports)]
                use $crate::mime::Value::*;
                MimeHelper::from(__rustful_to_expr!($value)).convert()
            })),+ ]
        )
    });
}

#[doc(hidden)]
#[macro_export]
macro_rules! __rustful_to_expr {
    ($e: expr) => ($e)
}

#[doc(hidden)]
#[macro_export]
macro_rules! __rustful_to_path {
    ($e: path) => ($e)
}

use std::str::FromStr;
use std::fmt::Debug;
use mime::{TopLevel, SubLevel, Attr, Value};

#[doc(hidden)]
pub enum MimeHelper<'a, T> {
    Str(&'a str),
    Target(T)
}

impl<'a, T: FromStr> MimeHelper<'a, T> where <T as FromStr>::Err: Debug {
    pub fn convert(self) -> T {
        match self {
            MimeHelper::Str(s) => s.parse().unwrap(),
            MimeHelper::Target(t) => t
        }
    }
}

impl<'a, T: FromStr> From<&'a str> for MimeHelper<'a, T> {
    fn from(s: &'a str) -> MimeHelper<'a, T> {
        MimeHelper::Str(s)
    }
}

impl<'a> From<TopLevel> for MimeHelper<'a, TopLevel> {
    fn from(t: TopLevel) -> MimeHelper<'a, TopLevel> {
        MimeHelper::Target(t)
    }
}

impl<'a> From<SubLevel> for MimeHelper<'a, SubLevel> {
    fn from(t: SubLevel) -> MimeHelper<'a, SubLevel> {
        MimeHelper::Target(t)
    }
}

impl<'a> From<Attr> for MimeHelper<'a, Attr> {
    fn from(t: Attr) -> MimeHelper<'a, Attr> {
        MimeHelper::Target(t)
    }
}

impl<'a> From<Value> for MimeHelper<'a, Value> {
    fn from(t: Value) -> MimeHelper<'a, Value> {
        MimeHelper::Target(t)
    }
}
<commit_msg>Allow trailing `,` in insert_routes! macro<commit_after>//!Some helpful macros.

///The `insert_routes!` macro generates routes from the provided handlers and routing tree and
///adds them to the provided router. The router is then returned.
///
///This can be useful to lower the risk of typing errors, among other things.
///
///##Example 1
///
///```rust
///#[macro_use]
///extern crate rustful;
///use rustful::TreeRouter;
///# use rustful::{Handler, Context, Response};
///
///# struct DummyHandler;
///# impl Handler for DummyHandler {
///#     fn handle_request(&self, _: Context, _: Response){}
///# }
///# fn main() {
///# let about_us = DummyHandler;
///# let show_user = DummyHandler;
///# let show_product = DummyHandler;
///# let show_error = DummyHandler;
///# let show_welcome = DummyHandler;
///let router = insert_routes! {
///    TreeRouter::new() => {
///        "/" => Get: show_welcome,
///        "/about" => Get: about_us,
///        "/user/:user" => Get: show_user,
///        "/product/:name" => Get: show_product,
///        "/*" => Get: show_error
///    }
///};
///# }
///```
///
///##Example 2
///
///```rust
///#[macro_use]
///extern crate rustful;
///use rustful::TreeRouter;
///# use rustful::{Handler, Context, Response};
///
///# #[derive(Clone, Copy)]
///# struct DummyHandler;
///# impl Handler for DummyHandler {
///#     fn handle_request(&self, _: Context, _: Response){}
///# }
///# fn main() {
///# let show_home = DummyHandler;
///# let show_user = DummyHandler;
///# let save_user = DummyHandler;
///# let show_all_products = DummyHandler;
///# let send_all_product_data = DummyHandler;
///# let show_product = DummyHandler;
///# let edit_product = DummyHandler;
///# let send_product_data = DummyHandler;
///
///let mut router = TreeRouter::new();
///
///insert_routes! {
///    &mut router => {
///        Get: show_home,
///
///        "home" => Get: show_home,
///        "user/:username" => {
///            Get: show_user,
///            Post: save_user
///        },
///        "product" => {
///            Get: show_all_products,
///
///            "json" => Get: send_all_product_data,
///            ":id" => {
///                Get: show_product,
///                Post: edit_product,
///                Delete: edit_product,
///
///                "json" => Get: send_product_data
///            }
///        }
///    }
///};
///# }
///```
#[macro_export]
macro_rules! insert_routes {
    ($router:expr => {$($paths:tt)+}) => {
        {
            use $crate::Router;
            let mut router = $router;
            __rustful_insert_internal!(router, [], $($paths)+);
            router
        }
    }
}

//Internal stuff. Only meant to be used through `insert_routes!`.
#[doc(hidden)]
#[macro_export]
macro_rules! __rustful_insert_internal {
    ($router:ident, [$($steps:expr),*],$(,)*) => {{}};
    ($router:ident, [$($steps:expr),*], $path:expr => {$($paths:tt)+}, $($next:tt)*) => {
        {
            __rustful_insert_internal!($router, [$($steps,)* $path], $($paths)*);
            __rustful_insert_internal!($router, [$($steps),*], $($next)*);
        }
    };
    ($router:ident, [$($steps:expr),*], $path:tt => {$($paths:tt)+}) => {
        {
            __rustful_insert_internal!($router, [$($steps,)* __rustful_to_expr!($path)], $($paths)*);
        }
    };
    ($router:ident, [$($steps:expr),*], $($method:tt)::+: $handler:expr, $($next:tt)*) => {
        {
            let method = {
                #[allow(unused_imports)]
                use $crate::Method::*;
                __rustful_to_path!($($method)::+)
            };
            let path = __rustful_route_expr!($($steps),*);
            $router.insert(method, path, $handler);
            __rustful_insert_internal!($router, [$($steps),*], $($next)*)
        }
    };
    ($router:ident, [$($steps:expr),*], $path:tt => $method:path: $handler:expr, $($next:tt)*) => {
        {
            let method = {
                #[allow(unused_imports)]
                use $crate::Method::*;
                $method
            };
            let path = __rustful_route_expr!($($steps,)* __rustful_to_expr!($path));
            $router.insert(method, path, $handler);
            __rustful_insert_internal!($router, [$($steps),*], $($next)*)
        }
    };
    ($router:ident, [$($steps:expr),*], $($method:tt)::+: $handler:expr) => {
        {
            let method = {
                #[allow(unused_imports)]
                use $crate::Method::*;
                __rustful_to_path!($($method)::+)
            };
            let path = __rustful_route_expr!($($steps),*);
            $router.insert(method, path, $handler);
        }
    };
    ($router:ident, [$($steps:expr),*], $path:tt => $method:path: $handler:expr) => {
        {
            let method = {
                #[allow(unused_imports)]
                use $crate::Method::*;
                $method
            };
            let path = __rustful_route_expr!($($steps,)* __rustful_to_expr!($path));
            $router.insert(method, path, $handler);
        }
    };
}

#[doc(hidden)]
#[macro_export]
macro_rules! __rustful_route_expr {
    () => ("");
    ($($path:expr),+) => (&[$($path),+][..]);
}

/**
A macro for making content types.

It takes a main type, a sub type and a parameter list. Instead of this:

```rust
use rustful::header::ContentType;
use rustful::mime::{Mime, TopLevel, SubLevel, Attr, Value};

ContentType(
    Mime (
        TopLevel::Text,
        SubLevel::Html,
        vec![(Attr::Charset, Value::Utf8)]
    )
);
```

it can be written like this:

```
#[macro_use]
extern crate rustful;
use rustful::header::ContentType;

# fn main() {
ContentType(content_type!(Text / Html; Charset = Utf8));
# }
```

The `Charset = Utf8` part defines the parameter list for the content type and
may contain more than one parameter, or be omitted. Here are some more
examples showing that and how strings can be used for more exotic values:

```
#[macro_use]
extern crate rustful;
use rustful::header::ContentType;

# fn main() {
ContentType(content_type!(Application / "octet-stream"; "type" = "image/gif"; "padding" = "4"));
# }
```

```
#[macro_use]
extern crate rustful;
use rustful::header::ContentType;

# fn main() {
ContentType(content_type!(Image / Png));
# }
```
**/
#[macro_export]
macro_rules! content_type {
    ($main_type:tt / $sub_type:tt) => ({
        use $crate::macros::MimeHelper;
        $crate::mime::Mime (
            {
                #[allow(unused_imports)]
                use $crate::mime::TopLevel::*;
                MimeHelper::from(__rustful_to_expr!($main_type)).convert()
            },
            {
                #[allow(unused_imports)]
                use $crate::mime::SubLevel::*;
                MimeHelper::from(__rustful_to_expr!($sub_type)).convert()
            },
            Vec::new()
        )
    });

    ($main_type:tt / $sub_type:tt; $($param:tt = $value:tt);+) => ({
        use $crate::macros::MimeHelper;
        $crate::mime::Mime (
            {
                #[allow(unused_imports)]
                use $crate::mime::TopLevel::*;
                MimeHelper::from(__rustful_to_expr!($main_type)).convert()
            },
            {
                #[allow(unused_imports)]
                use $crate::mime::SubLevel::*;
                MimeHelper::from(__rustful_to_expr!($sub_type)).convert()
            },
            vec![ $( ({
                #[allow(unused_imports)]
                use $crate::mime::Attr::*;
                MimeHelper::from(__rustful_to_expr!($param)).convert()
            }, {
                #[allow(unused_imports)]
                use $crate::mime::Value::*;
                MimeHelper::from(__rustful_to_expr!($value)).convert()
            })),+ ]
        )
    });
}

#[doc(hidden)]
#[macro_export]
macro_rules! __rustful_to_expr {
    ($e: expr) => ($e)
}

#[doc(hidden)]
#[macro_export]
macro_rules! __rustful_to_path {
    ($e: path) => ($e)
}

use std::str::FromStr;
use std::fmt::Debug;
use mime::{TopLevel, SubLevel, Attr, Value};

#[doc(hidden)]
pub enum MimeHelper<'a, T> {
    Str(&'a str),
    Target(T)
}

impl<'a, T: FromStr> MimeHelper<'a, T> where <T as FromStr>::Err: Debug {
    pub fn convert(self) -> T {
        match self {
            MimeHelper::Str(s) => s.parse().unwrap(),
            MimeHelper::Target(t) => t
        }
    }
}

impl<'a, T: FromStr> From<&'a str> for MimeHelper<'a, T> {
    fn from(s: &'a str) -> MimeHelper<'a, T> {
        MimeHelper::Str(s)
    }
}

impl<'a> From<TopLevel> for MimeHelper<'a, TopLevel> {
    fn from(t: TopLevel) -> MimeHelper<'a, TopLevel> {
        MimeHelper::Target(t)
    }
}

impl<'a> From<SubLevel> for MimeHelper<'a, SubLevel> {
    fn from(t: SubLevel) -> MimeHelper<'a, SubLevel> {
        MimeHelper::Target(t)
    }
}

impl<'a> From<Attr> for MimeHelper<'a, Attr> {
    fn from(t: Attr) -> MimeHelper<'a, Attr> {
        MimeHelper::Target(t)
    }
}

impl<'a> From<Value> for MimeHelper<'a, Value> {
    fn from(t: Value) -> MimeHelper<'a, Value> {
        MimeHelper::Target(t)
    }
}
<|endoftext|>


<commit_before>// This module implements the snapshot files used by zakopane.
// ATOW a snapshot file is pretty much the output of the ``sha256sum''
// command with three extra lines atop.

use std::collections::HashMap;
use std::io::{Error, ErrorKind};
use std::result::Result;
use std::str::Lines;
use std::string::String;

// Defines the number of lines preceding the actual checksum content.
const HEADER_LINES: usize = 3;

// Defines the number of hex characters in a sha256sum.
const CHECKSUM_CHARS: usize = 64;

// Defines a zakopane snapshot, which maps paths to checksums.
pub struct Snapshot {
    contents: HashMap<String, String>,
}

// Borrows the string representation of a line in a zakopane snapshot
// and returns sliced str's in a tuple of (path, checksum).
fn parse_snapshot_line(line: &str) -> Result<(&str, &str), Error> {
    let bad_line: Error = Error::new(
        ErrorKind::InvalidData,
        format!("malformed snapshot line: ``{}''", line),
    );
    // A snapshot line should consist of the checksum, a space, and a
    // non-empty pathname.
    if line.len() < CHECKSUM_CHARS + 2
        || !line.is_char_boundary(CHECKSUM_CHARS)
        || !line.is_char_boundary(CHECKSUM_CHARS + 1)
    {
        return Err(bad_line);
    }

    let (checksum, path_with_leading_space) = line.split_at(CHECKSUM_CHARS);
    if !path_with_leading_space.starts_with(" ") {
        return Err(bad_line);
    }
    Ok((checksum, &path_with_leading_space[1..]))
}

impl Snapshot {
    // Borrows the string representation of a zakopane snapshot and
    // returns the corresponding Snapshot struct.
    pub fn new(snapshot: &str) -> Result<Snapshot, Error> {
        let mut lines: Lines = snapshot.lines();

        // A zakopane snapshot starts with three extra lines intended
        // for human readers. zakocmp doesn't care about this header.
        let mut header_drain: usize = HEADER_LINES;
        while header_drain > 0 {
            match lines.next() {
                Some(_) => (),
                None => {
                    return Err(Error::new(
                        ErrorKind::InvalidData,
                        "truncated zakopane snapshot",
                    ))
                }
            };
            header_drain -= 1;
        }

        // Ingests the rest of the snapshot representation.
        let mut contents: HashMap<String, String> = HashMap::new();
        for line in lines {
            let (path, checksum) = parse_snapshot_line(line)?;
            match contents.insert(path.to_string(), checksum.to_string()) {
                None => (),
                Some(old_checksum) => {
                    return Err(Error::new(
                        ErrorKind::AlreadyExists,
                        format!(
                            "path collision: {} (was already {}, is now {})",
                            path, old_checksum, checksum
                        ),
                    ))
                }
            };
        }
        Ok(Snapshot { contents: contents })
    }
}

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

    // Defines a valid zakopane snapshot header.
    const SNAPSHOT_HEADER_FOR_TESTING: &'static str = r#"simple-zakopane.sh: 2019-07-27-090032
simple-zakopane.sh: /home/kalvin
# this line is typically empty but must be present
"#;

    // Accepts a borrowed string representation of some zakopane
    // checksums, prepends the standard zakopane snapshot header to the
    // same, and returns the owned result.
    fn snapshot_string_for_testing(checksums: &str) -> String {
        let mut snapshot: String = SNAPSHOT_HEADER_FOR_TESTING.to_string();
        snapshot.push_str(checksums);
        snapshot
    }

    #[test]
    fn snapshot_must_have_proper_header() {
        let snapshot = Snapshot::new(SNAPSHOT_HEADER_FOR_TESTING).unwrap();
        assert!(snapshot.contents.len() == 0);

        let snapshot_without_proper_header = r#"simple-zakopane.sh: 2019-07-27-090032
simple-zakopane.sh: /home/kalvin
"#;
        assert!(!Snapshot::new(snapshot_without_proper_header).is_ok());
    }

    #[test]
    fn snapshot_checksum_is_hex() {
        let checksum_ok =
            "4e8401b759a877c0d215ba95bb75bd7d08318cbdc395b3fae9763337ee3614a5 ./hello/there.txt";
        let snapshot = Snapshot::new(&snapshot_string_for_testing(checksum_ok)).unwrap();
        assert!(snapshot.contents.len() == 1);

        // Oh no! This checksum dropped a character off the end.
        let checksum_short =
            "4e8401b759a877c0d215ba95bb75bd7d08318cbdc395b3fae9763337ee3614a ./hello/there.txt";
        assert!(!Snapshot::new(&snapshot_string_for_testing(checksum_short)).is_ok());

        // Oh no! This checksum line does not refer to a path.
        let checksum_without_path =
            "4e8401b759a877c0d215ba95bb75bd7d08318cbdc395b3fae9763337ee3614a5 ";
        assert!(!Snapshot::new(&snapshot_string_for_testing(checksum_without_path)).is_ok());

        // Checksum lines may not be empty or too short.
        assert!(!Snapshot::new(&snapshot_string_for_testing("\n")).is_ok());
        assert!(!Snapshot::new(&snapshot_string_for_testing("Hello there!")).is_ok());
    }

    #[test]
    fn snapshot_paths_may_not_repeat() {
        let checksums =
            "4e8401b759a877c0d215ba95bb75bd7d08318cbdc395b3fae9763337ee3614a5 ./hello/there.txt
        4e8401b759a877c0d215ba95bb75bd7d08318cbdc395b3fae9763337ee3614a5 ./hello/there.txt";
        assert!(!Snapshot::new(&snapshot_string_for_testing(checksums)).is_ok());
    }
}
<commit_msg>zakocmp: use is_err() in unit tests<commit_after>// This module implements the snapshot files used by zakopane.
// ATOW a snapshot file is pretty much the output of the ``sha256sum''
// command with three extra lines atop.

use std::collections::HashMap;
use std::io::{Error, ErrorKind};
use std::result::Result;
use std::str::Lines;
use std::string::String;

// Defines the number of lines preceding the actual checksum content.
const HEADER_LINES: usize = 3;

// Defines the number of hex characters in a sha256sum.
const CHECKSUM_CHARS: usize = 64;

// Defines a zakopane snapshot, which maps paths to checksums.
pub struct Snapshot {
    contents: HashMap<String, String>,
}

// Borrows the string representation of a line in a zakopane snapshot
// and returns sliced str's in a tuple of (path, checksum).
fn parse_snapshot_line(line: &str) -> Result<(&str, &str), Error> {
    let bad_line: Error = Error::new(
        ErrorKind::InvalidData,
        format!("malformed snapshot line: ``{}''", line),
    );
    // A snapshot line should consist of the checksum, a space, and a
    // non-empty pathname.
    if line.len() < CHECKSUM_CHARS + 2
        || !line.is_char_boundary(CHECKSUM_CHARS)
        || !line.is_char_boundary(CHECKSUM_CHARS + 1)
    {
        return Err(bad_line);
    }

    let (checksum, path_with_leading_space) = line.split_at(CHECKSUM_CHARS);
    if !path_with_leading_space.starts_with(" ") {
        return Err(bad_line);
    }
    Ok((checksum, &path_with_leading_space[1..]))
}

impl Snapshot {
    // Borrows the string representation of a zakopane snapshot and
    // returns the corresponding Snapshot struct.
    pub fn new(snapshot: &str) -> Result<Snapshot, Error> {
        let mut lines: Lines = snapshot.lines();

        // A zakopane snapshot starts with three extra lines intended
        // for human readers. zakocmp doesn't care about this header.
        let mut header_drain: usize = HEADER_LINES;
        while header_drain > 0 {
            match lines.next() {
                Some(_) => (),
                None => {
                    return Err(Error::new(
                        ErrorKind::InvalidData,
                        "truncated zakopane snapshot",
                    ))
                }
            };
            header_drain -= 1;
        }

        // Ingests the rest of the snapshot representation.
        let mut contents: HashMap<String, String> = HashMap::new();
        for line in lines {
            let (path, checksum) = parse_snapshot_line(line)?;
            match contents.insert(path.to_string(), checksum.to_string()) {
                None => (),
                Some(old_checksum) => {
                    return Err(Error::new(
                        ErrorKind::AlreadyExists,
                        format!(
                            "path collision: {} (was already {}, is now {})",
                            path, old_checksum, checksum
                        ),
                    ))
                }
            };
        }
        Ok(Snapshot { contents: contents })
    }
}

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

    // Defines a valid zakopane snapshot header.
    const SNAPSHOT_HEADER_FOR_TESTING: &'static str = r#"simple-zakopane.sh: 2019-07-27-090032
simple-zakopane.sh: /home/kalvin
# this line is typically empty but must be present
"#;

    // Accepts a borrowed string representation of some zakopane
    // checksums, prepends the standard zakopane snapshot header to the
    // same, and returns the owned result.
    fn snapshot_string_for_testing(checksums: &str) -> String {
        let mut snapshot: String = SNAPSHOT_HEADER_FOR_TESTING.to_string();
        snapshot.push_str(checksums);
        snapshot
    }

    #[test]
    fn snapshot_must_have_proper_header() {
        let snapshot = Snapshot::new(SNAPSHOT_HEADER_FOR_TESTING).unwrap();
        assert!(snapshot.contents.len() == 0);

        let snapshot_without_proper_header = r#"simple-zakopane.sh: 2019-07-27-090032
simple-zakopane.sh: /home/kalvin
"#;
        assert!(Snapshot::new(snapshot_without_proper_header).is_err());
    }

    #[test]
    fn snapshot_checksum_is_hex() {
        let checksum_ok =
            "4e8401b759a877c0d215ba95bb75bd7d08318cbdc395b3fae9763337ee3614a5 ./hello/there.txt";
        let snapshot = Snapshot::new(&snapshot_string_for_testing(checksum_ok)).unwrap();
        assert!(snapshot.contents.len() == 1);

        // Oh no! This checksum dropped a character off the end.
        let checksum_short =
            "4e8401b759a877c0d215ba95bb75bd7d08318cbdc395b3fae9763337ee3614a ./hello/there.txt";
        assert!(Snapshot::new(&snapshot_string_for_testing(checksum_short)).is_err());

        // Oh no! This checksum line does not refer to a path.
        let checksum_without_path =
            "4e8401b759a877c0d215ba95bb75bd7d08318cbdc395b3fae9763337ee3614a5 ";
        assert!(Snapshot::new(&snapshot_string_for_testing(checksum_without_path)).is_err());

        // Checksum lines may not be empty or too short.
        assert!(Snapshot::new(&snapshot_string_for_testing("\n")).is_err());
        assert!(Snapshot::new(&snapshot_string_for_testing("Hello there!")).is_err());
    }

    #[test]
    fn snapshot_paths_may_not_repeat() {
        let checksums =
            "4e8401b759a877c0d215ba95bb75bd7d08318cbdc395b3fae9763337ee3614a5 ./hello/there.txt
        4e8401b759a877c0d215ba95bb75bd7d08318cbdc395b3fae9763337ee3614a5 ./hello/there.txt";
        assert!(Snapshot::new(&snapshot_string_for_testing(checksums)).is_err());
    }
}
<|endoftext|>