<commit_before>use irc;
use matrix;
use irc::protocol::{Command,Message};
use mio;
use mio::{EventLoop,Handler,Token,EventSet,PollOpt,Sender};
use std::thread;
use std::collections::HashMap;

const CLIENT: Token = Token(0);
const MATRIX: Token = Token(1);

#[derive(Debug)]
pub enum Event {
    EndPoll,
    Matrix(matrix::events::Event)
}

pub struct Bridge {
    client: irc::streams::Client,
    matrix: matrix::client::Client,
    rooms: HashMap<matrix::events::RoomID, Room>,
    seenEvents: Vec<matrix::events::EventID>,
}

impl Handler for Bridge {
    type Timeout = ();
    type Message = Event;

    fn ready(&mut self, event_loop: &mut EventLoop<Bridge>, token: Token, _: EventSet) {
        match token {
            CLIENT =>
                self.handle_client(event_loop),
            _ => unreachable!()
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Bridge>, msg: Self::Message) {
        println!("Got message from matrix! {:?}", msg);
        match msg {
            Event::EndPoll => {
                self.poll_matrix(event_loop.channel());
            },
            Event::Matrix(e) =>
                self.handle_matrix(e)
        };
    }
}

unsafe impl Sync for Bridge{}

struct Room {
    id: matrix::events::RoomID,
    canonical_alias: Option<String>,
    join_rules: Option<String>,
    members: Vec<matrix::events::UserID>
}

impl Room {
    fn new(id: matrix::events::RoomID) -> Self {
        Room {
            id: id,
            canonical_alias: None,
            join_rules: None,
            members: vec![]
        }
    }

    fn handle_event<F>(&mut self, evt: matrix::events::RoomEvent, mut callback: F)
            where F: FnMut(irc::protocol::Message) {
        match evt {
            matrix::events::RoomEvent::CanonicalAlias(name) => {
                let was_empty = self.canonical_alias == None;
                self.canonical_alias = Some(name.clone());
                for ref user in &self.members {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}@anony.oob", user.nickname)),
                        command: irc::protocol::Command::Join,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                }
            },
            matrix::events::RoomEvent::JoinRules(rules) =>
                self.join_rules = Some(rules.clone()),
            matrix::events::RoomEvent::Membership(user, matrix::events::MembershipAction::Join) => {
                if self.canonical_alias != None {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}@anony.oob", user.nickname)),
                        command: irc::protocol::Command::Join,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                }
                self.members.push(user);
            },
            matrix::events::RoomEvent::Membership(user, matrix::events::MembershipAction::Leave) => {
                if self.canonical_alias != None {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}@anony.oob", user.nickname)),
                        command: irc::protocol::Command::Part,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                }
                self.members.push(user);
            },
            matrix::events::RoomEvent::Membership(user, _) => (),
            matrix::events::RoomEvent::Message(user, text) => {
                callback(irc::protocol::Message {
                    prefix: Some(format!("{}@anony.oob", user.nickname)),
                    command: irc::protocol::Command::Privmsg,
                    args: vec![self.canonical_alias.clone().unwrap()],
                    suffix: Some(text)
                });
            },
            matrix::events::RoomEvent::Create => (),
            matrix::events::RoomEvent::Aliases => (),
            matrix::events::RoomEvent::PowerLevels => (),
            matrix::events::RoomEvent::HistoryVisibility(_) => (),
            matrix::events::RoomEvent::Name(_, _) => ()
        };
    }
}

impl Bridge {
    pub fn room(&mut self, id: &matrix::events::RoomID) -> &mut Room {
        if !self.rooms.contains_key(id) {
            self.rooms.insert(id.clone(), Room::new(id.clone()));
        }
        match self.rooms.get_mut(id) {
            Some(room) => room,
            None => unreachable!()
        }
    }

    pub fn new(client: irc::streams::Client, url: &str) -> Self {
        Bridge {
            client: client,
            matrix: matrix::client::Client::new(url),
            rooms: HashMap::new(),
            seenEvents: vec![]
        }
    }

    pub fn run(&mut self) {
        let mut events = EventLoop::new().unwrap();
        events.register(self.client.stream(), CLIENT, EventSet::all(), PollOpt::edge()).unwrap();
        events.run(self).unwrap();
    }

    fn handle_matrix(&mut self, evt: matrix::events::Event) {
        let duplicate = match evt.id {
            Some(ref id) =>
                self.seenEvents.contains(id),
            _ => false
        };
        if !duplicate {
            let mut messages: Vec<irc::protocol::Message> = vec![];
            {
                let appendMsg = |msg: irc::protocol::Message| {
                    messages.push(msg);
                };
                match evt.data {
                    matrix::events::EventData::Room(room_id, room_event) => {
                        self.room(&room_id).handle_event(room_event, appendMsg);
                    },
                    _ => println!("Unhandled {:?}", evt)
                }
            }
            match evt.id {
                Some(id) =>
                    self.seenEvents.push(id),
                None => ()
            };
            for ref msg in messages {
                self.client.send(msg);
            }
        }
    }

    fn poll_matrix(&mut self, channel: mio::Sender<Event>) ->
        thread::JoinHandle<matrix::client::Result> {
        let poll = self.matrix.pollAsync();
        thread::spawn(move|| {
            poll.send().and_then(|evts| {
                for evt in evts {
                    channel.send(Event::Matrix(evt));
                };
                channel.send(Event::EndPoll);
                Ok(())
            })
        })
    }

    fn start_matrix(&mut self, channel: mio::Sender<Event>) ->
        matrix::client::Result {
        self.matrix.sync(|evt: matrix::events::Event| {
            channel.send(Event::Matrix(evt));
        }).and_then(|r| {
            self.poll_matrix(channel);
            Ok(r)
        })
    }

    fn handle_client(&mut self, events: &mut EventLoop<Bridge>) {
        loop {
            match self.client.read_message() {
                None => return,
                Some(message) => {
                    println!("Got a message! {:?}", message);
                    match message.command {
                        Command::Pass => {
                            self.client.auth.set_password(message.args[0].clone())
                        }
                        Command::Nick => {
                            self.client.set_nickname(message.args[0].clone());
                        },
                        Command::User => {
                            println!("User logged in: {}", message.args[0]);
                            self.client.auth.set_username(message.args[0].clone());
                            let auth = self.client.auth.consume();
                            match (auth.username, auth.password) {
                                (Some(username), Some(password)) => {
                                    self.matrix.login(username.trim(), password.trim())
                                        .and(self.start_matrix(events.channel()))
                                        .and_then(|_| {
                                            self.client.welcome(username.trim());
                                            println!("Logged in {:?}", username);
                                            Ok(())
                                        }).expect("Could not login!");
                                },
                                _ => panic!("Username and/or password missing")
                            };
                        },
                        Command::Join => {
                            self.client.join(&message.args[0]);
                        },
                        Command::Ping => {
                            self.client.pong();
                        },
                        Command::Quit => {
                            // FIXME: Logout of matrix and exit thread
                            return;
                        },
                        Command::Privmsg => {
                            let uid = matrix::events::UserID::from_str("@tdfischer:localhost");
                            let roomid = matrix::events::RoomID::from_str("!SNCDinqFeGteFrlCoN:localhost");
                            let evt = matrix::events::EventData::Room(
                                roomid,
                                matrix::events::RoomEvent::Message(
                                    uid, message.suffix.unwrap()));
                            self.seenEvents.push(self.matrix.send(evt));
                        },
                        _ =>
                            println!("unhandled {:?}", message)
                    }
                }
            }
        }
    }
}

<commit_msg>bridge: queue up events that require the canonical room name until we have that<commit_after>use irc;
use matrix;
use irc::protocol::{Command,Message};
use mio;
use mio::{EventLoop,Handler,Token,EventSet,PollOpt,Sender};
use std::thread;
use std::collections::HashMap;

const CLIENT: Token = Token(0);
const MATRIX: Token = Token(1);

#[derive(Debug)]
pub enum Event {
    EndPoll,
    Matrix(matrix::events::Event)
}

pub struct Bridge {
    client: irc::streams::Client,
    matrix: matrix::client::Client,
    rooms: HashMap<matrix::events::RoomID, Room>,
    seenEvents: Vec<matrix::events::EventID>,
}

impl Handler for Bridge {
    type Timeout = ();
    type Message = Event;

    fn ready(&mut self, event_loop: &mut EventLoop<Bridge>, token: Token, _: EventSet) {
        match token {
            CLIENT =>
                self.handle_client(event_loop),
            _ => unreachable!()
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Bridge>, msg: Self::Message) {
        println!("Got message from matrix! {:?}", msg);
        match msg {
            Event::EndPoll => {
                self.poll_matrix(event_loop.channel());
            },
            Event::Matrix(e) =>
                self.handle_matrix(e)
        };
    }
}

unsafe impl Sync for Bridge{}

struct Room {
    id: matrix::events::RoomID,
    canonical_alias: Option<String>,
    join_rules: Option<String>,
    members: Vec<matrix::events::UserID>,
    pending_events: Vec<matrix::events::RoomEvent>
}

impl Room {
    fn new(id: matrix::events::RoomID) -> Self {
        Room {
            id: id,
            canonical_alias: None,
            join_rules: None,
            members: vec![],
            pending_events: vec![]
        }
    }

    fn run_pending<F>(&mut self, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {
        while let Some(evt) = self.pending_events.pop() {
            self.handle_with_alias(evt, callback);
        }
    }

    fn handle_with_alias<F>(&mut self, evt: matrix::events::RoomEvent, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {
        if self.canonical_alias != None {
            match evt {
                matrix::events::RoomEvent::Membership(user, matrix::events::MembershipAction::Join) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}@anony.oob", user.nickname)),
                        command: irc::protocol::Command::Join,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                    self.members.push(user);
                },
                matrix::events::RoomEvent::Membership(user, matrix::events::MembershipAction::Leave) => {
                    if self.canonical_alias != None {
                        callback(irc::protocol::Message {
                            prefix: Some(format!("{}@anony.oob", user.nickname)),
                            command: irc::protocol::Command::Part,
                            args: vec![self.canonical_alias.clone().unwrap()],
                            suffix: None
                        });
                    }
                    self.members.push(user);
                },
                matrix::events::RoomEvent::Membership(user, _) => (),
                matrix::events::RoomEvent::Message(user, text) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}@anony.oob", user.nickname)),
                        command: irc::protocol::Command::Privmsg,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: Some(text)
                    });
                },
                matrix::events::RoomEvent::Topic(user, topic) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}@anony.oob", user.nickname)),
                        command: irc::protocol::Command::Topic,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: Some(topic.clone())
                    });
                },
                matrix::events::RoomEvent::CanonicalAlias(_) => unreachable!(),
                _ => {
                    println!("Unhandled event {:?}", evt)
                }
            }
        } else {
            self.pending_events.push(evt);
        }
    }

    fn handle_event<F>(&mut self, evt: matrix::events::RoomEvent, mut callback: F)
            where F: FnMut(irc::protocol::Message) {
        match evt {
            matrix::events::RoomEvent::CanonicalAlias(name) => {
                let was_empty = self.canonical_alias == None;
                self.canonical_alias = Some(name.clone());
                for ref user in &self.members {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}@anony.oob", user.nickname)),
                        command: irc::protocol::Command::Join,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                };
                if was_empty {
                    self.run_pending(&mut callback);
                }
            },
            matrix::events::RoomEvent::JoinRules(rules) =>
                self.join_rules = Some(rules.clone()),
            matrix::events::RoomEvent::Create => (),
            matrix::events::RoomEvent::Aliases => (),
            matrix::events::RoomEvent::PowerLevels => (),
            matrix::events::RoomEvent::HistoryVisibility(_) => (),
            matrix::events::RoomEvent::Name(_, _) => (),
            matrix::events::RoomEvent::Avatar(_, _) => (),
            matrix::events::RoomEvent::Unknown(json) => {
                println!("Unknown room event: {:?}", json);
            }
            _ => self.handle_with_alias(evt, &mut callback)
        };
    }
}

impl Bridge {
    pub fn room(&mut self, id: &matrix::events::RoomID) -> &mut Room {
        if !self.rooms.contains_key(id) {
            self.rooms.insert(id.clone(), Room::new(id.clone()));
        }
        match self.rooms.get_mut(id) {
            Some(room) => room,
            None => unreachable!()
        }
    }

    pub fn new(client: irc::streams::Client, url: &str) -> Self {
        Bridge {
            client: client,
            matrix: matrix::client::Client::new(url),
            rooms: HashMap::new(),
            seenEvents: vec![]
        }
    }

    pub fn run(&mut self) {
        let mut events = EventLoop::new().unwrap();
        events.register(self.client.stream(), CLIENT, EventSet::all(), PollOpt::edge()).unwrap();
        events.run(self).unwrap();
    }

    fn handle_matrix(&mut self, evt: matrix::events::Event) {
        let duplicate = match evt.id {
            Some(ref id) =>
                self.seenEvents.contains(id),
            _ => false
        };
        if !duplicate {
            let mut messages: Vec<irc::protocol::Message> = vec![];
            {
                let appendMsg = |msg: irc::protocol::Message| {
                    messages.push(msg);
                };
                match evt.data {
                    matrix::events::EventData::Room(room_id, room_event) => {
                        self.room(&room_id).handle_event(room_event, appendMsg);
                    },
                    _ => println!("Unhandled {:?}", evt)
                }
            }
            match evt.id {
                Some(id) =>
                    self.seenEvents.push(id),
                None => ()
            };
            for ref msg in messages {
                self.client.send(msg);
            }
        }
    }

    fn poll_matrix(&mut self, channel: mio::Sender<Event>) ->
        thread::JoinHandle<matrix::client::Result> {
        let poll = self.matrix.pollAsync();
        thread::spawn(move|| {
            poll.send().and_then(|evts| {
                for evt in evts {
                    channel.send(Event::Matrix(evt));
                };
                channel.send(Event::EndPoll);
                Ok(())
            })
        })
    }

    fn start_matrix(&mut self, channel: mio::Sender<Event>) ->
        matrix::client::Result {
        self.matrix.sync(|evt: matrix::events::Event| {
            channel.send(Event::Matrix(evt));
        }).and_then(|r| {
            self.poll_matrix(channel);
            Ok(r)
        })
    }

    fn handle_client(&mut self, events: &mut EventLoop<Bridge>) {
        loop {
            match self.client.read_message() {
                None => return,
                Some(message) => {
                    println!("Got a message! {:?}", message);
                    match message.command {
                        Command::Pass => {
                            self.client.auth.set_password(message.args[0].clone())
                        }
                        Command::Nick => {
                            self.client.set_nickname(message.args[0].clone());
                        },
                        Command::User => {
                            println!("User logged in: {}", message.args[0]);
                            self.client.auth.set_username(message.args[0].clone());
                            let auth = self.client.auth.consume();
                            match (auth.username, auth.password) {
                                (Some(username), Some(password)) => {
                                    self.matrix.login(username.trim(), password.trim())
                                        .and(self.start_matrix(events.channel()))
                                        .and_then(|_| {
                                            self.client.welcome(username.trim());
                                            println!("Logged in {:?}", username);
                                            Ok(())
                                        }).expect("Could not login!");
                                },
                                _ => panic!("Username and/or password missing")
                            };
                        },
                        Command::Join => {
                            self.client.join(&message.args[0]);
                        },
                        Command::Ping => {
                            self.client.pong();
                        },
                        Command::Quit => {
                            // FIXME: Logout of matrix and exit thread
                            return;
                        },
                        Command::Privmsg => {
                            let uid = matrix::events::UserID::from_str("@tdfischer:localhost");
                            let roomid = matrix::events::RoomID::from_str("!SNCDinqFeGteFrlCoN:localhost");
                            let evt = matrix::events::EventData::Room(
                                roomid,
                                matrix::events::RoomEvent::Message(
                                    uid, message.suffix.unwrap()));
                            self.seenEvents.push(self.matrix.send(evt));
                        },
                        _ =>
                            println!("unhandled {:?}", message)
                    }
                }
            }
        }
    }
}

<|endoftext|>


<commit_before>use wasm_bindgen::prelude::*;

use anyhow::Error;
use lancelot::{
    arch::Arch,
    loader::pe::{PEError, PE as lPE},
    module::ModuleError,
    pagemap::PageMapError,
    util::UtilError,
};

#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;

#[wasm_bindgen]
pub fn version() -> String {
    String::from("v0.7.0")
}

#[wasm_bindgen(start)]
pub fn main_js() -> Result<(), JsValue> {
    #[cfg(debug_assertions)]
    console_error_panic_hook::set_once();

    Ok(())
}

// for better function signatures
// no functional difference.
type JsError = JsValue;

fn to_value_error(e: anyhow::Error) -> JsError {
    js_sys::Error::new(&format!("{}", e)).into()
}

fn to_js_err(e: Error) -> JsError {
    match e.downcast_ref::<PEError>() {
        Some(PEError::FormatNotSupported(_)) => return to_value_error(e),
        Some(PEError::MalformedPEFile(_)) => return to_value_error(e),
        None => (),
    };

    #[allow(clippy::single_match)]
    match e.downcast_ref::<ModuleError>() {
        Some(ModuleError::InvalidAddress(_)) => return to_value_error(e),
        None => (),
    };

    match e.downcast_ref::<UtilError>() {
        Some(UtilError::FileAccess) => return to_value_error(e),
        Some(UtilError::FileFormat) => return to_value_error(e),
        None => (),
    };

    #[allow(clippy::single_match)]
    match e.downcast_ref::<PageMapError>() {
        Some(PageMapError::NotMapped) => return to_value_error(e),
        None => (),
    };

    to_value_error(e)
}

#[wasm_bindgen]
pub fn from_bytes(buf: Vec<u8>) -> Result<PE, JsError> {
    let pe = lPE::from_bytes(&buf).map_err(to_js_err)?;
    Ok(PE { inner: pe })
}

#[wasm_bindgen]
#[derive(Clone, Copy)]
pub struct AddressRange {
    pub start: u64,
    pub end:   u64,
}

#[wasm_bindgen]
impl AddressRange {
    #[wasm_bindgen(getter)]
    pub fn size(&self) -> u64 {
        self.end - self.start
    }
}

#[wasm_bindgen]
pub struct Section {
    pub physical_range: AddressRange,
    pub virtual_range:  AddressRange,
    // String are not clone, so we have to manually implement getters
    permissions:        String,
    name:               String,
}

#[wasm_bindgen]
impl Section {
    #[wasm_bindgen(getter)]
    pub fn permissions(&self) -> String {
        self.permissions.to_string()
    }

    #[wasm_bindgen(getter)]
    pub fn name(&self) -> String {
        self.name.clone()
    }
}

impl From<&lancelot::module::Section> for Section {
    fn from(other: &lancelot::module::Section) -> Section {
        Section {
            physical_range: AddressRange {
                start: other.physical_range.start,
                end:   other.physical_range.end,
            },
            virtual_range:  AddressRange {
                start: other.virtual_range.start,
                end:   other.virtual_range.end,
            },
            permissions:    other.permissions.to_string(),
            name:           other.name.to_string(),
        }
    }
}

#[wasm_bindgen]
pub struct PE {
    inner: lPE,
}

#[wasm_bindgen]
impl PE {
    #[wasm_bindgen(getter)]
    pub fn arch(&self) -> JsValue {
        match self.inner.module.arch {
            // we expect these strings may be returned many times,
            // so we intern them for perf
            // https://docs.rs/wasm-bindgen/0.2.78/wasm_bindgen/fn.intern.html
            Arch::X32 => JsValue::from(wasm_bindgen::intern("x32")),
            Arch::X64 => JsValue::from(wasm_bindgen::intern("x64")),
        }
    }

    #[wasm_bindgen(getter)]
    pub fn base_address(&self) -> u64 {
        self.inner.module.address_space.base_address
    }

    // not cheap, so its a function, not getter
    #[wasm_bindgen]
    pub fn functions(&self) -> Result<Vec<u64>, JsError> {
        Ok(lancelot::analysis::pe::find_functions(&self.inner)
            .map_err(to_js_err)?
            .into_iter()
            .filter(|f| matches!(f, lancelot::analysis::pe::Function::Local(_)))
            .map(|f| match f {
                lancelot::analysis::pe::Function::Local(va) => va,
                _ => unreachable!(),
            })
            .collect())
    }

    // Vec<T> cannot be serialized by wasm-bindgen
    // so we have to manually convert to Vec<JsValue>
    // and then annotate the TS type.
    //
    // NB: JS now owns the objects, must explicitly drop.
    #[wasm_bindgen(getter, typescript_type = "Array<Section>")]
    pub fn sections(&self) -> Vec<JsValue> {
        self.inner
            .module
            .sections
            .iter()
            .map(Section::from)
            .map(JsValue::from)
            .collect()
    }
}
<commit_msg>jslancelot: add read_bytes<commit_after>use wasm_bindgen::prelude::*;

use anyhow::Error;
use lancelot::{
    arch::Arch,
    aspace::AddressSpace,
    loader::pe::{PEError, PE as lPE},
    module::ModuleError,
    pagemap::PageMapError,
    util::UtilError,
};

#[cfg(feature = "wee_alloc")]
#[global_allocator]
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;

#[wasm_bindgen]
pub fn version() -> String {
    String::from("v0.7.0")
}

#[wasm_bindgen(start)]
pub fn main_js() -> Result<(), JsValue> {
    #[cfg(debug_assertions)]
    console_error_panic_hook::set_once();

    Ok(())
}

// for better function signatures
// no functional difference.
type JsError = JsValue;

fn to_value_error(e: anyhow::Error) -> JsError {
    js_sys::Error::new(&format!("{}", e)).into()
}

fn to_js_err(e: Error) -> JsError {
    match e.downcast_ref::<PEError>() {
        Some(PEError::FormatNotSupported(_)) => return to_value_error(e),
        Some(PEError::MalformedPEFile(_)) => return to_value_error(e),
        None => (),
    };

    #[allow(clippy::single_match)]
    match e.downcast_ref::<ModuleError>() {
        Some(ModuleError::InvalidAddress(_)) => return to_value_error(e),
        None => (),
    };

    match e.downcast_ref::<UtilError>() {
        Some(UtilError::FileAccess) => return to_value_error(e),
        Some(UtilError::FileFormat) => return to_value_error(e),
        None => (),
    };

    #[allow(clippy::single_match)]
    match e.downcast_ref::<PageMapError>() {
        Some(PageMapError::NotMapped) => return to_value_error(e),
        None => (),
    };

    to_value_error(e)
}

#[wasm_bindgen]
pub fn from_bytes(buf: Vec<u8>) -> Result<PE, JsError> {
    let pe = lPE::from_bytes(&buf).map_err(to_js_err)?;
    Ok(PE { inner: pe })
}

#[wasm_bindgen]
#[derive(Clone, Copy)]
pub struct AddressRange {
    pub start: u64,
    pub end:   u64,
}

#[wasm_bindgen]
impl AddressRange {
    #[wasm_bindgen(getter)]
    pub fn size(&self) -> u64 {
        self.end - self.start
    }
}

#[wasm_bindgen]
pub struct Section {
    pub physical_range: AddressRange,
    pub virtual_range:  AddressRange,
    // String are not clone, so we have to manually implement getters
    permissions:        String,
    name:               String,
}

#[wasm_bindgen]
impl Section {
    #[wasm_bindgen(getter)]
    pub fn permissions(&self) -> String {
        self.permissions.to_string()
    }

    #[wasm_bindgen(getter)]
    pub fn name(&self) -> String {
        self.name.clone()
    }
}

impl From<&lancelot::module::Section> for Section {
    fn from(other: &lancelot::module::Section) -> Section {
        Section {
            physical_range: AddressRange {
                start: other.physical_range.start,
                end:   other.physical_range.end,
            },
            virtual_range:  AddressRange {
                start: other.virtual_range.start,
                end:   other.virtual_range.end,
            },
            permissions:    other.permissions.to_string(),
            name:           other.name.to_string(),
        }
    }
}

#[wasm_bindgen]
pub struct PE {
    inner: lPE,
}

#[wasm_bindgen]
impl PE {
    #[wasm_bindgen(getter)]
    pub fn arch(&self) -> JsValue {
        match self.inner.module.arch {
            // we expect these strings may be returned many times,
            // so we intern them for perf
            // https://docs.rs/wasm-bindgen/0.2.78/wasm_bindgen/fn.intern.html
            Arch::X32 => JsValue::from(wasm_bindgen::intern("x32")),
            Arch::X64 => JsValue::from(wasm_bindgen::intern("x64")),
        }
    }

    #[wasm_bindgen(getter)]
    pub fn base_address(&self) -> u64 {
        self.inner.module.address_space.base_address
    }

    // not cheap, so its a function, not getter
    #[wasm_bindgen]
    pub fn functions(&self) -> Result<Vec<u64>, JsError> {
        Ok(lancelot::analysis::pe::find_functions(&self.inner)
            .map_err(to_js_err)?
            .into_iter()
            .filter(|f| matches!(f, lancelot::analysis::pe::Function::Local(_)))
            .map(|f| match f {
                lancelot::analysis::pe::Function::Local(va) => va,
                _ => unreachable!(),
            })
            .collect())
    }

    // Vec<T> cannot be serialized by wasm-bindgen
    // so we have to manually convert to Vec<JsValue>
    // and then annotate the TS type.
    //
    // NB: JS now owns the objects, must explicitly drop.
    #[wasm_bindgen(getter, typescript_type = "Array<Section>")]
    pub fn sections(&self) -> Vec<JsValue> {
        self.inner
            .module
            .sections
            .iter()
            .map(Section::from)
            .map(JsValue::from)
            .collect()
    }

    #[wasm_bindgen]
    pub fn read_bytes(&self, va: u64, size: usize) -> Result<Vec<u8>, JsError> {
        self.inner.module.address_space.read_bytes(va, size).map_err(to_js_err)
    }
}
<|endoftext|>


<commit_before>use std;
extern crate libc;
use std::ffi::CString;
use std::io::{Error, ErrorKind};

#[derive(Debug)]
pub struct Buffer {
    buf: *mut libc::c_char,
    offset: isize,
    buflen: libc::size_t,
}

impl Buffer {
    pub fn new(buf: *mut libc::c_char, buflen: libc::size_t) -> Self {
        Self { buf,
               offset: 0,
               buflen, }
    }

    fn write(&mut self, data: *const libc::c_char, len: usize) -> Result<*mut libc::c_char, Error> {
        if self.buflen < len as libc::size_t {
            return Err(Error::new(ErrorKind::AddrNotAvailable, "ERANGE"));
        }
        unsafe {
            let pos = self.buf.offset(self.offset);
            std::ptr::copy(data as *mut i8, pos as *mut i8, len);
            self.offset += len as isize;
            self.buflen -= len as libc::size_t;
            Ok(pos)
        }
    }

    fn add_pointers(&mut self, ptrs: &Vec<*mut libc::c_char>) -> Result<*mut *mut libc::c_char, Error> {
        use std::mem::size_of;
        let step = std::cmp::max(size_of::<*mut libc::c_char>() / size_of::<libc::c_char>(),
                                 1);
        if self.buflen < (ptrs.len() + 1) * step as libc::size_t {
            return Err(Error::new(ErrorKind::AddrNotAvailable, "ERANGE"));
        }
        unsafe {
            let mem = self.buf.offset(self.offset) as *mut *mut libc::c_char;
            for (i, p) in ptrs.iter().enumerate() {
                *(mem.offset(i as isize)) = *p;
                self.offset += step as isize;
                self.buflen -= step as libc::size_t;
            }
            *(mem.offset(ptrs.len() as isize)) = std::ptr::null_mut::<libc::c_char>();
            Ok(mem)
        }
    }

    pub fn write_string(&mut self, s: &str) -> Result<*mut libc::c_char, Error> {
        let cs = CString::new(s).unwrap();
        self.write(cs.as_ptr(), s.len() + 1)
    }

    pub fn write_vecstr(&mut self, ss: &Vec<&str>) -> Result<*mut *mut libc::c_char, Error> {
        let mut ptrs = Vec::<*mut libc::c_char>::new();
        for s in ss {
            ptrs.push(self.write_string(s)?);
        }
        self.add_pointers(&ptrs)
    }
}
<commit_msg>Fix size check bug<commit_after>use std;
extern crate libc;
use std::ffi::CString;
use std::io::{Error, ErrorKind};

#[derive(Debug)]
pub struct Buffer {
    buf: *mut libc::c_char,
    offset: isize,
    buflen: libc::size_t,
}

impl Buffer {
    pub fn new(buf: *mut libc::c_char, buflen: libc::size_t) -> Self {
        Self { buf,
               offset: 0,
               buflen, }
    }

    fn write(&mut self, data: *const libc::c_char, len: usize) -> Result<*mut libc::c_char, Error> {
        if self.buflen < len + self.offset as libc::size_t {
            return Err(Error::new(ErrorKind::AddrNotAvailable, "ERANGE"));
        }
        unsafe {
            let pos = self.buf.offset(self.offset);
            std::ptr::copy(data as *mut i8, pos as *mut i8, len);
            self.offset += len as isize;
            self.buflen -= len as libc::size_t;
            Ok(pos)
        }
    }

    fn add_pointers(&mut self, ptrs: &Vec<*mut libc::c_char>) -> Result<*mut *mut libc::c_char, Error> {
        use std::mem::size_of;
        let step = std::cmp::max(size_of::<*mut libc::c_char>() / size_of::<libc::c_char>(),
                                 1);
        if self.buflen < (((ptrs.len() + 1) * step) as isize + self.offset) as libc::size_t {
            return Err(Error::new(ErrorKind::AddrNotAvailable, "ERANGE"));
        }
        unsafe {
            let mem = self.buf.offset(self.offset) as *mut *mut libc::c_char;
            for (i, p) in ptrs.iter().enumerate() {
                *(mem.offset(i as isize)) = *p;
                self.offset += step as isize;
                self.buflen -= step as libc::size_t;
            }
            *(mem.offset(ptrs.len() as isize)) = std::ptr::null_mut::<libc::c_char>();
            Ok(mem)
        }
    }

    pub fn write_string(&mut self, s: &str) -> Result<*mut libc::c_char, Error> {
        let cs = CString::new(s).unwrap();
        self.write(cs.as_ptr(), s.len() + 1)
    }

    pub fn write_vecstr(&mut self, ss: &Vec<&str>) -> Result<*mut *mut libc::c_char, Error> {
        let mut ptrs = Vec::<*mut libc::c_char>::new();
        for s in ss {
            ptrs.push(self.write_string(s)?);
        }
        self.add_pointers(&ptrs)
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::ptr;
use std::marker::PhantomData;
use gl;
use gl::types::*;
use context::Context;
use types::{DrawingMode, GLError};
use index_data::{IndexData, IndexDatum, IndexDatumType};

pub struct Buffer {
    gl_id: GLuint
}

impl Buffer {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Buffer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteBuffers(1, &self.gl_id as *const GLuint);
        }
    }
}

impl Context {
    pub fn gen_buffer(&self) -> Buffer {
        unsafe {
            let mut id : GLuint = mem::uninitialized();

            gl::GenBuffers(1, &mut id as *mut GLuint);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`n` is negative",
                _ => "Unknown error"
            }

            Buffer { gl_id: id }
        }
    }
}

#[derive(Debug, Clone, Copy)]
#[allow(non_camel_case_types)]
pub enum BufferDataUsage {
    STREAM_DRAW = gl::STREAM_DRAW as isize,
    STATIC_DRAW = gl::STATIC_DRAW as isize,
    DYNAMIC_DRAW = gl::DYNAMIC_DRAW as isize
}
pub use self::BufferDataUsage::*;

#[derive(Debug, Clone, Copy)]
#[allow(non_camel_case_types)]
pub enum BufferBindingTarget {
    ARRAY_BUFFER = gl::ARRAY_BUFFER as isize,
    ELEMENT_ARRAY_BUFFER = gl::ELEMENT_ARRAY_BUFFER as isize
}
pub use self::BufferBindingTarget::*;

pub trait BufferBinding {
    fn target(&self) -> BufferBindingTarget;

    fn buffer_bytes(&mut self, bytes: &[u8], usage: BufferDataUsage) {
        let ptr = bytes.as_ptr();
        let size = bytes.len() * mem::size_of::<u8>();
        unsafe {
            gl::BufferData(self.target() as GLenum,
                           size as GLsizeiptr,
                           ptr as *const GLvoid,
                           usage as GLenum);
            dbg_gl_error! {
                GLError::InvalidEnum => "Invalid `target` or `usage`",
                GLError::InvalidValue => "`size` is negative",
                GLError::InvalidOperation => "Object 0 is bound to buffer target",
                GLError::OutOfMemory => "Unable to create a large enough buffer",
                _ => "Unknown error"
            }
        }
    }
}

pub struct ArrayBufferBinding<'a> {
    phantom: PhantomData<&'a mut Buffer>
}

impl<'a> BufferBinding for ArrayBufferBinding<'a> {
    fn target(&self) -> BufferBindingTarget {
        ARRAY_BUFFER
    }
}

unsafe fn _draw_elements(mode: DrawingMode,
                         count: usize,
                         index_type: IndexDatumType,
                         indicies: *const GLvoid)
{
    let gl_index_type: GLenum = match index_type {
        IndexDatumType::UnsignedByte => gl::UNSIGNED_BYTE,
        IndexDatumType::UnsignedShort => gl::UNSIGNED_SHORT
    };
    gl::DrawElements(mode as GLenum,
                     count as GLsizei,
                     gl_index_type,
                     indicies);
    dbg_gl_error! {
        GLError::InvalidEnum => "`mode` or `type` is not an accepted value",
        GLError::InvalidValue => "`count` is negative",
        GLError::InvalidFramebufferOperation => "The current framebuffer is not framebuffer-complete",
        _ => "Unknown error"
    }
}

impl<'a> ArrayBufferBinding<'a> {
    pub unsafe fn vertex_attrib_pointer(&self,
                                        attrib: super::ProgramAttrib,
                                        components: i8,
                                        gl_type: super::DataType,
                                        normalized: bool,
                                        stride: usize,
                                        offset: usize)
    {
        debug_assert!(1 <= components && components <= 4);

        let gl_normalized = if normalized { gl::TRUE } else { gl::FALSE };
        gl::VertexAttribPointer(attrib.gl_index,
                                components as GLint,
                                gl_type as GLenum,
                                gl_normalized,
                                stride as GLsizei,
                                offset as *const GLvoid);
        dbg_gl_error! {
            GLError::InvalidEnum => "Illegal vertex attribute type",
            GLError::InvalidValue => "`stride` is negative, `size` is not in range, or `index` is >= GL_MAX_VERTEX_ATTRIBS",
            GLError::InvalidFramebufferOperation => "Currently bound framebuffer is not framebuffer complete",
            _ => "Unknown error"
        }
    }

    pub unsafe fn draw_arrays_range(&self,
                                    mode: DrawingMode,
                                    first: u32,
                                    count: usize)
    {
        gl::DrawArrays(mode as GLenum, first as GLint, count as GLsizei);
        dbg_gl_sanity_check! {
            GLError::InvalidEnum => "`mode` is not an accepted value",
            GLError::InvalidValue => "`count` is negative",
            _ => "Unknown error"
        }
    }

    pub unsafe fn draw_n_elements_buffered(&self,
                                           _eab: &ElementArrayBufferBinding,
                                           mode: DrawingMode,
                                           count: usize,
                                           index_type: IndexDatumType)
    {
        _draw_elements(mode, count, index_type, ptr::null());
    }

    pub unsafe fn draw_n_elements<I>(&self,
                                     mode: DrawingMode,
                                     count: usize,
                                     indicies: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        debug_assert!(count <= indicies.len());

        let ptr = indicies.index_bytes().as_ptr();
        let index_type = I::index_datum_type();
        _draw_elements(mode, count, index_type, mem::transmute(ptr));
    }

    pub unsafe fn draw_elements<I>(&self,
                                   mode: DrawingMode,
                                   indicies: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        self.draw_n_elements(mode, indicies.len(), indicies);
    }
}

pub struct ElementArrayBufferBinding<'a> {
    phantom: PhantomData<&'a mut Buffer>
}

impl<'a> BufferBinding for ElementArrayBufferBinding<'a> {
    fn target(&self) -> BufferBindingTarget {
        ELEMENT_ARRAY_BUFFER
    }
}

unsafe fn _bind_buffer(target: BufferBindingTarget, buffer: &mut Buffer) {
    gl::BindBuffer(target as GLuint, buffer.gl_id());
    dbg_gl_sanity_check! {
        GLError::InvalidEnum => "`target` is not an allowed value",
        _ => "Unknown error"
    }
}

pub struct ArrayBufferBinder;
impl ArrayBufferBinder {
    pub fn bind<'a>(&'a mut self, buffer: &mut Buffer)
        -> ArrayBufferBinding<'a>
    {
        let binding = ArrayBufferBinding { phantom: PhantomData };
        unsafe {
            _bind_buffer(binding.target(), buffer);
        }
        binding
    }
}

pub struct ElementArrayBufferBinder;
impl ElementArrayBufferBinder {
    pub fn bind<'a>(&'a mut self, buffer: &mut Buffer)
        -> ElementArrayBufferBinding<'a>
    {
        let binding = ElementArrayBufferBinding { phantom: PhantomData };
        unsafe {
            _bind_buffer(binding.target(), buffer);
        }
        binding
    }
}
<commit_msg>Refactor `BufferDataUsage`/`BufferBindingTarget` to export with consts<commit_after>use std::mem;
use std::ptr;
use std::marker::PhantomData;
use gl;
use gl::types::*;
use context::Context;
use types::{DrawingMode, GLError};
use index_data::{IndexData, IndexDatum, IndexDatumType};

pub struct Buffer {
    gl_id: GLuint
}

impl Buffer {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}

impl Drop for Buffer {
    fn drop(&mut self) {
        unsafe {
            gl::DeleteBuffers(1, &self.gl_id as *const GLuint);
        }
    }
}

impl Context {
    pub fn gen_buffer(&self) -> Buffer {
        unsafe {
            let mut id : GLuint = mem::uninitialized();

            gl::GenBuffers(1, &mut id as *mut GLuint);
            dbg_gl_sanity_check! {
                GLError::InvalidValue => "`n` is negative",
                _ => "Unknown error"
            }

            Buffer { gl_id: id }
        }
    }
}

#[derive(Debug, Clone, Copy)]
pub enum BufferDataUsage {
    StreamDraw = gl::STREAM_DRAW as isize,
    StaticDraw = gl::STATIC_DRAW as isize,
    DynamicDraw = gl::DYNAMIC_DRAW as isize
}
pub const STREAM_DRAW : BufferDataUsage = BufferDataUsage::StreamDraw;
pub const STATIC_DRAW : BufferDataUsage = BufferDataUsage::StaticDraw;
pub const DYNAMIC_DRAW : BufferDataUsage = BufferDataUsage::DynamicDraw;

#[derive(Debug, Clone, Copy)]
pub enum BufferBindingTarget {
    ArrayBuffer = gl::ARRAY_BUFFER as isize,
    ElementArrayBuffer = gl::ELEMENT_ARRAY_BUFFER as isize
}
pub const ARRAY_BUFFER : BufferBindingTarget =
    BufferBindingTarget::ArrayBuffer;
pub const ELEMENT_ARRAY_BUFFER : BufferBindingTarget =
    BufferBindingTarget::ElementArrayBuffer;

pub trait BufferBinding {
    fn target(&self) -> BufferBindingTarget;

    fn buffer_bytes(&mut self, bytes: &[u8], usage: BufferDataUsage) {
        let ptr = bytes.as_ptr();
        let size = bytes.len() * mem::size_of::<u8>();
        unsafe {
            gl::BufferData(self.target() as GLenum,
                           size as GLsizeiptr,
                           ptr as *const GLvoid,
                           usage as GLenum);
            dbg_gl_error! {
                GLError::InvalidEnum => "Invalid `target` or `usage`",
                GLError::InvalidValue => "`size` is negative",
                GLError::InvalidOperation => "Object 0 is bound to buffer target",
                GLError::OutOfMemory => "Unable to create a large enough buffer",
                _ => "Unknown error"
            }
        }
    }
}

pub struct ArrayBufferBinding<'a> {
    phantom: PhantomData<&'a mut Buffer>
}

impl<'a> BufferBinding for ArrayBufferBinding<'a> {
    fn target(&self) -> BufferBindingTarget {
        ARRAY_BUFFER
    }
}

unsafe fn _draw_elements(mode: DrawingMode,
                         count: usize,
                         index_type: IndexDatumType,
                         indicies: *const GLvoid)
{
    let gl_index_type: GLenum = match index_type {
        IndexDatumType::UnsignedByte => gl::UNSIGNED_BYTE,
        IndexDatumType::UnsignedShort => gl::UNSIGNED_SHORT
    };
    gl::DrawElements(mode as GLenum,
                     count as GLsizei,
                     gl_index_type,
                     indicies);
    dbg_gl_error! {
        GLError::InvalidEnum => "`mode` or `type` is not an accepted value",
        GLError::InvalidValue => "`count` is negative",
        GLError::InvalidFramebufferOperation => "The current framebuffer is not framebuffer-complete",
        _ => "Unknown error"
    }
}

impl<'a> ArrayBufferBinding<'a> {
    pub unsafe fn vertex_attrib_pointer(&self,
                                        attrib: super::ProgramAttrib,
                                        components: i8,
                                        gl_type: super::DataType,
                                        normalized: bool,
                                        stride: usize,
                                        offset: usize)
    {
        debug_assert!(1 <= components && components <= 4);

        let gl_normalized = if normalized { gl::TRUE } else { gl::FALSE };
        gl::VertexAttribPointer(attrib.gl_index,
                                components as GLint,
                                gl_type as GLenum,
                                gl_normalized,
                                stride as GLsizei,
                                offset as *const GLvoid);
        dbg_gl_error! {
            GLError::InvalidEnum => "Illegal vertex attribute type",
            GLError::InvalidValue => "`stride` is negative, `size` is not in range, or `index` is >= GL_MAX_VERTEX_ATTRIBS",
            GLError::InvalidFramebufferOperation => "Currently bound framebuffer is not framebuffer complete",
            _ => "Unknown error"
        }
    }

    pub unsafe fn draw_arrays_range(&self,
                                    mode: DrawingMode,
                                    first: u32,
                                    count: usize)
    {
        gl::DrawArrays(mode as GLenum, first as GLint, count as GLsizei);
        dbg_gl_sanity_check! {
            GLError::InvalidEnum => "`mode` is not an accepted value",
            GLError::InvalidValue => "`count` is negative",
            _ => "Unknown error"
        }
    }

    pub unsafe fn draw_n_elements_buffered(&self,
                                           _eab: &ElementArrayBufferBinding,
                                           mode: DrawingMode,
                                           count: usize,
                                           index_type: IndexDatumType)
    {
        _draw_elements(mode, count, index_type, ptr::null());
    }

    pub unsafe fn draw_n_elements<I>(&self,
                                     mode: DrawingMode,
                                     count: usize,
                                     indicies: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        debug_assert!(count <= indicies.len());

        let ptr = indicies.index_bytes().as_ptr();
        let index_type = I::index_datum_type();
        _draw_elements(mode, count, index_type, mem::transmute(ptr));
    }

    pub unsafe fn draw_elements<I>(&self,
                                   mode: DrawingMode,
                                   indicies: &[I])
        where I: IndexDatum, [I]: IndexData
    {
        self.draw_n_elements(mode, indicies.len(), indicies);
    }
}

pub struct ElementArrayBufferBinding<'a> {
    phantom: PhantomData<&'a mut Buffer>
}

impl<'a> BufferBinding for ElementArrayBufferBinding<'a> {
    fn target(&self) -> BufferBindingTarget {
        ELEMENT_ARRAY_BUFFER
    }
}

unsafe fn _bind_buffer(target: BufferBindingTarget, buffer: &mut Buffer) {
    gl::BindBuffer(target as GLuint, buffer.gl_id());
    dbg_gl_sanity_check! {
        GLError::InvalidEnum => "`target` is not an allowed value",
        _ => "Unknown error"
    }
}

pub struct ArrayBufferBinder;
impl ArrayBufferBinder {
    pub fn bind<'a>(&'a mut self, buffer: &mut Buffer)
        -> ArrayBufferBinding<'a>
    {
        let binding = ArrayBufferBinding { phantom: PhantomData };
        unsafe {
            _bind_buffer(binding.target(), buffer);
        }
        binding
    }
}

pub struct ElementArrayBufferBinder;
impl ElementArrayBufferBinder {
    pub fn bind<'a>(&'a mut self, buffer: &mut Buffer)
        -> ElementArrayBufferBinding<'a>
    {
        let binding = ElementArrayBufferBinding { phantom: PhantomData };
        unsafe {
            _bind_buffer(binding.target(), buffer);
        }
        binding
    }
}
<|endoftext|>


<commit_before>use std::fmt;

pub enum MouseButton {
    Left,
    Middle,
    Right,
    ScrollUp,
    ScrollDown,
}

pub struct Button {
    actions:    Vec<ClickAction>,
    text:       String,
}

pub struct ClickAction {
    button:     MouseButton,
    command:    String,
}

impl fmt::Display for Button {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut content = self.text.to_string();

        for action in self.actions.iter().rev() {
            content = format!("{}{}%{{A}}", action, content);
        }

        write!(f, "{}", content)
    }
}

impl fmt::Display for ClickAction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "%{{A{}:{}:}}", self.button, self.command)
    }
}

impl fmt::Display for MouseButton {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let btn_number = match *self {
            MouseButton::Left => 1,
            MouseButton::Middle => 2,
            MouseButton::Right => 3,
            MouseButton::ScrollUp => 4,
            MouseButton::ScrollDown => 5,
        };

        write!(f, "{}", btn_number)
    }
}

#[cfg(test)]
mod tests {
    use super::{Button, ClickAction, MouseButton};

    #[test]
    fn button_to_string() {
        let left_action = ClickAction {
            button: MouseButton::Left,
            command: "reboot".to_string(),
        };

        let right_action = ClickAction {
            button: MouseButton::Right,
            command: "halt".to_string(),
        };

        let button = Button {
            actions: vec![left_action, right_action],
            text: "test".to_string(),
        };

        assert!(button.to_string() == "%{A1:reboot:}%{A3:halt:}test%{A}%{A}");
    }

    #[test]
    fn click_action_to_string() {
        let action = ClickAction {
            button: MouseButton::Left,
            command: "echo".to_string(),
        };

        assert!(action.to_string() == "%{A1:echo:}");
    }

    #[test]
    fn mouse_button_to_string() {
        assert!(MouseButton::Left.to_string() == "1");
        assert!(MouseButton::Middle.to_string() == "2");
        assert!(MouseButton::Right.to_string() == "3");
        assert!(MouseButton::ScrollUp.to_string() == "4");
        assert!(MouseButton::ScrollDown.to_string() == "5");
    }
}
<commit_msg>Make Button and ClickAction fields public<commit_after>use std::fmt;

pub enum MouseButton {
    Left,
    Middle,
    Right,
    ScrollUp,
    ScrollDown,
}

pub struct Button {
    pub actions:    Vec<ClickAction>,
    pub text:       String,
}

pub struct ClickAction {
    pub button:     MouseButton,
    pub command:    String,
}

impl fmt::Display for Button {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut content = self.text.to_string();

        for action in self.actions.iter().rev() {
            content = format!("{}{}%{{A}}", action, content);
        }

        write!(f, "{}", content)
    }
}

impl fmt::Display for ClickAction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "%{{A{}:{}:}}", self.button, self.command)
    }
}

impl fmt::Display for MouseButton {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let btn_number = match *self {
            MouseButton::Left => 1,
            MouseButton::Middle => 2,
            MouseButton::Right => 3,
            MouseButton::ScrollUp => 4,
            MouseButton::ScrollDown => 5,
        };

        write!(f, "{}", btn_number)
    }
}

#[cfg(test)]
mod tests {
    use super::{Button, ClickAction, MouseButton};

    #[test]
    fn button_to_string() {
        let left_action = ClickAction {
            button: MouseButton::Left,
            command: "reboot".to_string(),
        };

        let right_action = ClickAction {
            button: MouseButton::Right,
            command: "halt".to_string(),
        };

        let button = Button {
            actions: vec![left_action, right_action],
            text: "test".to_string(),
        };

        assert!(button.to_string() == "%{A1:reboot:}%{A3:halt:}test%{A}%{A}");
    }

    #[test]
    fn click_action_to_string() {
        let action = ClickAction {
            button: MouseButton::Left,
            command: "echo".to_string(),
        };

        assert!(action.to_string() == "%{A1:echo:}");
    }

    #[test]
    fn mouse_button_to_string() {
        assert!(MouseButton::Left.to_string() == "1");
        assert!(MouseButton::Middle.to_string() == "2");
        assert!(MouseButton::Right.to_string() == "3");
        assert!(MouseButton::ScrollUp.to_string() == "4");
        assert!(MouseButton::ScrollDown.to_string() == "5");
    }
}
<|endoftext|>


<commit_before>//! # Drains
//!
//! Drains are responsible for filtering, formatting and writing the log records
//! into given destination.
use super::{Level};
use super::format;
use super::logger::RecordInfo;
use std::{io, str};
use std::sync::Mutex;
use super::{OwnedKeyValue,BorrowedKeyValue};
use std::sync::mpsc;
use std::thread;

///
/// Drain for Loggers
///
/// Implementing this trait allows writing own Drains
pub trait Drain : Send+Sync {
    /// Write one logging record
    fn log(&self, info : &RecordInfo, &[OwnedKeyValue], &[BorrowedKeyValue]);
}

/// Drain formating records and writing them to a byte-stream (io::Write)
///
/// Uses mutex to serialize writes.
/// TODO: Add one that does not serialize?
pub struct Streamer<W : io::Write, F : format::Format> {
    io : Mutex<W>,
    format : F,
}

impl<W : io::Write, F : format::Format> Streamer<W, F> {
    /// Create new `Streamer` writing to `io` using `format`
    pub fn new(io : W, format : F) -> Self {
        Streamer {
            io: Mutex::new(io),
            format : format,
        }
    }
}

impl<W : 'static+io::Write+Send, F : format::Format+Send> Drain for Streamer<W, F> {
    fn log(&self, info : &RecordInfo, logger_values : &[OwnedKeyValue], values : &[BorrowedKeyValue]) {
        let formatted = self.format.format(info, logger_values, values);

        let mut io = self.io.lock().unwrap();
        let _ = write!(io, "{}", formatted);
    }
}

/// Record log level filter
///
/// Wraps a drain and passes records to it, only
/// if their level is at least given level.
pub struct FilterLevel<D : Drain> {
    level: Level,
    drain : D,
}

impl<D : Drain> FilterLevel<D> {
    /// Create FilterLevel wrapping given `subdrain` and passing to it records
    /// only of at least `level`.
    pub fn new(level : Level, subdrain : D) -> Self {
        FilterLevel {
            level: level,
            drain: subdrain,
        }
    }
}

impl<D : Drain> Drain for FilterLevel<D> {
    fn log(&self, info : &RecordInfo, logger_values : &[OwnedKeyValue], values : &[BorrowedKeyValue]) {
        if info.level.is_at_least(self.level) {
            self.drain.log(info, logger_values, values)
        }
    }
}

/// Duplicate records into two drains
pub struct Duplicate<D1 : Drain, D2 : Drain> {
    drain1 : D1,
    drain2 : D2,
}

impl<D1 : Drain, D2 : Drain> Duplicate<D1, D2> {
    /// Create FilterLevel wrapping given `subdrain` and passing to it records
    /// only of at least `level`.
    pub fn new(drain1 : D1, drain2 : D2) -> Self {
        Duplicate {
            drain1: drain1,
            drain2: drain2,
        }
    }
}

impl<D1 : Drain, D2 : Drain> Drain for Duplicate<D1, D2> {
    fn log(&self, info : &RecordInfo, logger_values : &[OwnedKeyValue], values : &[BorrowedKeyValue]) {
        self.drain1.log(info, logger_values, values);
        self.drain2.log(info, logger_values, values);
    }
}

enum AsyncIoMsg{
    Bytes(Vec<u8>),
    Flush,
    Eof
}

/// Asynchronous io::Writer
///
/// Wraps an `io::Writer` and writes to it in separate thread
/// using channel to send the data.
///
/// This makes logging not block on potentially-slow IO operations.
///
/// Note: Dropping `AsyncIoWriter` waits for it's io-thread to finish.
/// If you can't tolerate the delay, make sure to use `Logger::
pub struct AsyncIoWriter {
    sender : mpsc::Sender<AsyncIoMsg>,
    join : Option<thread::JoinHandle<()>>,
}

impl AsyncIoWriter {
    /// Create `AsyncIoWriter`
    pub fn new<W : io::Write+Send+'static>(mut io : W) -> Self {
        let (tx, rx) = mpsc::channel();
        let join = thread::spawn(move || {
            loop {
                match rx.recv().unwrap() {
                    AsyncIoMsg::Bytes(buf) => io.write_all(&buf).unwrap(),
                    AsyncIoMsg::Flush => io.flush().unwrap(),
                    AsyncIoMsg::Eof => return,
                }
            }
        });

        AsyncIoWriter {
            sender: tx,
            join: Some(join),
        }
    }
}

impl io::Write for AsyncIoWriter {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let _ = self.sender.send(AsyncIoMsg::Bytes(buf.to_vec())).unwrap();
        Ok(buf.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        let _ = self.sender.send(AsyncIoMsg::Flush);
        Ok(())
    }
}

impl Drop for AsyncIoWriter {
    fn drop(&mut self) {
        let _ = self.sender.send(AsyncIoMsg::Eof);
        let _ = self.join.take().unwrap().join();
    }
}

/// Create AsyncIoWriter
pub fn async<W : io::Write + Send + 'static>(io : W) -> AsyncIoWriter {
    AsyncIoWriter::new(io)
}

/// Create Streamer drain
pub fn stream<W : io::Write + Send, F : format::Format>(io : W, format : F) -> Streamer<W, F> {
    Streamer::new(io, format)
}

/// Create FilterLevel drain
pub fn filter_level<D : Drain>(level : Level, d : D) -> FilterLevel<D> {
    FilterLevel::new(level, d)
}

/// Create Duplicate drain
pub fn duplicate<D1 : Drain, D2 : Drain>(d1 : D1, d2 : D2) -> Duplicate<D1, D2> {
    Duplicate::new(d1, d2)
}
<commit_msg>Add `drain::Filter`<commit_after>//! # Drains
//!
//! Drains are responsible for filtering, formatting and writing the log records
//! into given destination.
use super::{Level};
use super::format;
use super::logger::RecordInfo;
use std::{io, str};
use std::sync::Mutex;
use super::{OwnedKeyValue,BorrowedKeyValue};
use std::sync::mpsc;
use std::thread;

///
/// Drain for Loggers
///
/// Implementing this trait allows writing own Drains
pub trait Drain : Send+Sync {
    /// Write one logging record
    fn log(&self, info : &RecordInfo, &[OwnedKeyValue], &[BorrowedKeyValue]);
}

/// Drain formating records and writing them to a byte-stream (io::Write)
///
/// Uses mutex to serialize writes.
/// TODO: Add one that does not serialize?
pub struct Streamer<W : io::Write, F : format::Format> {
    io : Mutex<W>,
    format : F,
}

impl<W : io::Write, F : format::Format> Streamer<W, F> {
    /// Create new `Streamer` writing to `io` using `format`
    pub fn new(io : W, format : F) -> Self {
        Streamer {
            io: Mutex::new(io),
            format : format,
        }
    }
}

impl<W : 'static+io::Write+Send, F : format::Format+Send> Drain for Streamer<W, F> {
    fn log(&self, info : &RecordInfo, logger_values : &[OwnedKeyValue], values : &[BorrowedKeyValue]) {
        let formatted = self.format.format(info, logger_values, values);

        let mut io = self.io.lock().unwrap();
        let _ = write!(io, "{}", formatted);
    }
}

/// Filter log record
///
/// Wraps a drain and passes records to it, only if their `RecordInfo`
/// satisifies a condition `cond`.
pub struct Filter<D : Drain> {
    drain : D,
    // eliminated dynamic dispatch, after rust learns `-> impl Trait`
    cond : Box<Fn(&RecordInfo)->bool+'static+Send+Sync>,
}

impl<D : Drain> Filter<D> {
    /// Create Filter wrapping given `subdrain` and passing to it records
    /// only the `cond` is true
    pub fn new<F : 'static+Sync+Send+Fn(&RecordInfo)->bool>(drain : D, cond : F) -> Self {
        Filter {
            drain: drain,
            cond: Box::new(cond),
        }
    }
}

impl<D : Drain> Drain for Filter<D> {
    fn log(&self, info : &RecordInfo, logger_values : &[OwnedKeyValue], values : &[BorrowedKeyValue]) {
        if (self.cond)(&info) {
            self.drain.log(info, logger_values, values)
        }
    }
}

/// Record log level filter
///
/// Wraps a drain and passes records to it, only
/// if their level is at least given level.
///
/// TODO: Remove this type. This drain is a special case of `Filter`, but
/// because `Filter` can not use static dispatch ATM due to Rust limitations
/// that will be lifted in the future, it is a standalone type.
pub struct FilterLevel<D : Drain> {
    level: Level,
    drain : D,
}

impl<D : Drain> FilterLevel<D> {
    /// Create `FilterLevel`
    pub fn new(drain : D, level : Level) -> Self {
        FilterLevel {
            level: level,
            drain: drain,
        }
    }
}

impl<D : Drain> Drain for FilterLevel<D> {
    fn log(&self, info : &RecordInfo, logger_values : &[OwnedKeyValue], values : &[BorrowedKeyValue]) {
        if info.level.is_at_least(self.level) {
            self.drain.log(info, logger_values, values)
        }
    }
}

/// Duplicate records into two drains
pub struct Duplicate<D1 : Drain, D2 : Drain> {
    drain1 : D1,
    drain2 : D2,
}

impl<D1 : Drain, D2 : Drain> Duplicate<D1, D2> {
    /// Create `Duplicate`
    pub fn new(drain1 : D1, drain2 : D2) -> Self {
        Duplicate {
            drain1: drain1,
            drain2: drain2,
        }
    }
}

impl<D1 : Drain, D2 : Drain> Drain for Duplicate<D1, D2> {
    fn log(&self, info : &RecordInfo, logger_values : &[OwnedKeyValue], values : &[BorrowedKeyValue]) {
        self.drain1.log(info, logger_values, values);
        self.drain2.log(info, logger_values, values);
    }
}

enum AsyncIoMsg{
    Bytes(Vec<u8>),
    Flush,
    Eof
}

/// Asynchronous io::Writer
///
/// Wraps an `io::Writer` and writes to it in separate thread
/// using channel to send the data.
///
/// This makes logging not block on potentially-slow IO operations.
///
/// Note: Dropping `AsyncIoWriter` waits for it's io-thread to finish.
/// If you can't tolerate the delay, make sure to use `Logger::
pub struct AsyncIoWriter {
    sender : mpsc::Sender<AsyncIoMsg>,
    join : Option<thread::JoinHandle<()>>,
}

impl AsyncIoWriter {
    /// Create `AsyncIoWriter`
    pub fn new<W : io::Write+Send+'static>(mut io : W) -> Self {
        let (tx, rx) = mpsc::channel();
        let join = thread::spawn(move || {
            loop {
                match rx.recv().unwrap() {
                    AsyncIoMsg::Bytes(buf) => io.write_all(&buf).unwrap(),
                    AsyncIoMsg::Flush => io.flush().unwrap(),
                    AsyncIoMsg::Eof => return,
                }
            }
        });

        AsyncIoWriter {
            sender: tx,
            join: Some(join),
        }
    }
}

impl io::Write for AsyncIoWriter {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let _ = self.sender.send(AsyncIoMsg::Bytes(buf.to_vec())).unwrap();
        Ok(buf.len())
    }

    fn flush(&mut self) -> io::Result<()> {
        let _ = self.sender.send(AsyncIoMsg::Flush);
        Ok(())
    }
}

impl Drop for AsyncIoWriter {
    fn drop(&mut self) {
        let _ = self.sender.send(AsyncIoMsg::Eof);
        let _ = self.join.take().unwrap().join();
    }
}

/// Create AsyncIoWriter
pub fn async<W : io::Write + Send + 'static>(io : W) -> AsyncIoWriter {
    AsyncIoWriter::new(io)
}

/// Create Streamer drain
pub fn stream<W : io::Write + Send, F : format::Format>(io : W, format : F) -> Streamer<W, F> {
    Streamer::new(io, format)
}

/// Filter by `cond` closure
pub fn filter<D : Drain, F : 'static+Send+Sync+Fn(&RecordInfo)->bool>(cond : F, d : D) -> Filter<D> {
    Filter::new(d, cond)
}

/// Filter by log level
pub fn filter_level<D : Drain>(level : Level, d : D) -> FilterLevel<D> {
    FilterLevel::new(d, level)
}

/// Create Duplicate drain
pub fn duplicate<D1 : Drain, D2 : Drain>(d1 : D1, d2 : D2) -> Duplicate<D1, D2> {
    Duplicate::new(d1, d2)
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use rustc_serialize::Decodable;
use rustc_serialize::base64::{
    FromBase64,
    ToBase64,
};
use rustc_serialize::json::{
    self,
    Decoder,
    Json,
};
use error::Error;
use BASE_CONFIG;

#[derive(Debug, Default, PartialEq)]
pub struct Claims {
    pub reg: Registered,
    pub private: BTreeMap<String, Json>,
}

#[derive(Debug, Default, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Registered {
    pub iss: Option<String>,
    pub sub: Option<String>,
    pub aud: Option<String>,
    pub exp: Option<u64>,
    pub nbf: Option<u64>,
    pub iat: Option<u64>,
    pub jti: Option<String>,
}

/// JWT Claims. Registered claims are directly accessible via the `Registered`
/// struct embedded, while private fields are a map that contains `Json`
/// values.
impl Claims {
    pub fn new(reg: Registered) -> Claims {
        Claims {
            reg: reg,
            private: BTreeMap::new(),
        }
    }

    /// Parse claims from a string.
    pub fn from_base64(raw: &str) -> Result<Claims, Error> {
        let data = try!(raw.from_base64());
        let s = try!(String::from_utf8(data));
        let tree = match try!(Json::from_str(&*s)) {
            Json::Object(x) => x,
            _ => return Err(Error::Format),
        };

        const FIELDS: [&'static str; 7] = [
            "iss", "sub", "aud",
            "exp", "nbf", "iat",
            "jti",
        ];

        let (reg, pri): (BTreeMap<_, _>, BTreeMap<_, _>) = tree.into_iter()
            .partition(|&(ref key, _)| {
                FIELDS.iter().any(|f| f == key)
            });

        let mut decoder = Decoder::new(Json::Object(reg));
        let reg_claims: Registered = try!(Decodable::decode(&mut decoder));

        Ok(Claims{
            reg: reg_claims,
            private: pri,
        })
    }

    /// Encode claims to a string.
    pub fn to_base64(&self) -> Result<String, Error> {
        // Extremely inefficient
        let s = try!(json::encode(&self.reg));
        let mut tree = match try!(Json::from_str(&*s)) {
            Json::Object(x) => x,
            _ => return Err(Error::Format),
        };

        tree.extend(self.private.clone());

        let s = try!(json::encode(&tree));
        let enc = (&*s).as_bytes().to_base64(BASE_CONFIG);
        Ok(enc)
    }
}

#[cfg(test)]
mod tests {
    use std::default::Default;
    use claims::Claims;

    #[test]
    fn from_base64() {
        let enc = "ew0KICAiaXNzIjogIm1pa2t5YW5nLmNvbSIsDQogICJleHAiOiAxMzAyMzE5MTAwLA0KICAibmFtZSI6ICJNaWNoYWVsIFlhbmciLA0KICAiYWRtaW4iOiB0cnVlDQp9";
        let claims = Claims::from_base64(enc).unwrap();

        assert_eq!(claims.reg.iss.unwrap(), "mikkyang.com");
        assert_eq!(claims.reg.exp.unwrap(), 1302319100);
    }

    #[test]
    fn roundtrip() {
        let mut claims: Claims = Default::default();
        claims.reg.iss = Some("mikkyang.com".into());
        claims.reg.exp = Some(1302319100);
        let enc = claims.to_base64().unwrap();
        assert_eq!(claims, Claims::from_base64(&*enc).unwrap());
    }
}
<commit_msg>Replace Claims impl with Component trait<commit_after>use std::collections::BTreeMap;
use rustc_serialize::Decodable;
use rustc_serialize::base64::{
    FromBase64,
    ToBase64,
};
use rustc_serialize::json::{
    self,
    Decoder,
    Json,
};
use Component;
use error::Error;
use BASE_CONFIG;

#[derive(Debug, Default, PartialEq)]
pub struct Claims {
    pub reg: Registered,
    pub private: BTreeMap<String, Json>,
}

#[derive(Debug, Default, PartialEq, RustcDecodable, RustcEncodable)]
pub struct Registered {
    pub iss: Option<String>,
    pub sub: Option<String>,
    pub aud: Option<String>,
    pub exp: Option<u64>,
    pub nbf: Option<u64>,
    pub iat: Option<u64>,
    pub jti: Option<String>,
}

/// JWT Claims. Registered claims are directly accessible via the `Registered`
/// struct embedded, while private fields are a map that contains `Json`
/// values.
impl Claims {
    pub fn new(reg: Registered) -> Claims {
        Claims {
            reg: reg,
            private: BTreeMap::new(),
        }
    }
}

impl Component for Claims {
    fn from_base64(raw: &str) -> Result<Claims, Error> {
        let data = try!(raw.from_base64());
        let s = try!(String::from_utf8(data));
        let tree = match try!(Json::from_str(&*s)) {
            Json::Object(x) => x,
            _ => return Err(Error::Format),
        };

        const FIELDS: [&'static str; 7] = [
            "iss", "sub", "aud",
            "exp", "nbf", "iat",
            "jti",
        ];

        let (reg, pri): (BTreeMap<_, _>, BTreeMap<_, _>) = tree.into_iter()
            .partition(|&(ref key, _)| {
                FIELDS.iter().any(|f| f == key)
            });

        let mut decoder = Decoder::new(Json::Object(reg));
        let reg_claims: Registered = try!(Decodable::decode(&mut decoder));

        Ok(Claims{
            reg: reg_claims,
            private: pri,
        })
    }

    fn to_base64(&self) -> Result<String, Error> {
        // Extremely inefficient
        let s = try!(json::encode(&self.reg));
        let mut tree = match try!(Json::from_str(&*s)) {
            Json::Object(x) => x,
            _ => return Err(Error::Format),
        };

        tree.extend(self.private.clone());

        let s = try!(json::encode(&tree));
        let enc = (&*s).as_bytes().to_base64(BASE_CONFIG);
        Ok(enc)
    }
}

#[cfg(test)]
mod tests {
    use std::default::Default;
    use claims::Claims;

    #[test]
    fn from_base64() {
        let enc = "ew0KICAiaXNzIjogIm1pa2t5YW5nLmNvbSIsDQogICJleHAiOiAxMzAyMzE5MTAwLA0KICAibmFtZSI6ICJNaWNoYWVsIFlhbmciLA0KICAiYWRtaW4iOiB0cnVlDQp9";
        let claims = Claims::from_base64(enc).unwrap();

        assert_eq!(claims.reg.iss.unwrap(), "mikkyang.com");
        assert_eq!(claims.reg.exp.unwrap(), 1302319100);
    }

    #[test]
    fn roundtrip() {
        let mut claims: Claims = Default::default();
        claims.reg.iss = Some("mikkyang.com".into());
        claims.reg.exp = Some(1302319100);
        let enc = claims.to_base64().unwrap();
        assert_eq!(claims, Claims::from_base64(&*enc).unwrap());
    }
}
<|endoftext|>


<commit_before>pub mod edge;
pub mod face;
pub mod path;
pub mod vertex;

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

use crate::entity::storage::{AsStorage, Storage};
use crate::graph::core::OwnedCore;
use crate::graph::data::{Data, Parametric};
use crate::graph::edge::{Arc, Edge};
use crate::graph::face::Face;
use crate::graph::mutation::face::FaceMutation;
use crate::graph::vertex::Vertex;
use crate::graph::GraphError;
use crate::transact::Transact;

/// Marker trait for graph representations that promise to be in a consistent
/// state.
///
/// This trait is only implemented by representations that ensure that their
/// storage is only ever mutated via the mutation API (and therefore is
/// consistent). Note that `Core` does not implement this trait and instead acts
/// as a raw container for topological storage that can be freely manipulated.
///
/// This trait allows code to make assumptions about the data it operates
/// against. For example, views expose an API to user code that assumes that
/// topologies are present and therefore unwraps values.
pub trait Consistent {}

impl<'a, T> Consistent for &'a T where T: Consistent {}

impl<'a, T> Consistent for &'a mut T where T: Consistent {}

/// Graph mutation.
pub struct Mutation<M>
where
    M: Consistent + From<OwnedCore<Data<M>>> + Parametric + Into<OwnedCore<Data<M>>>,
{
    inner: FaceMutation<M>,
}

impl<M> AsRef<Self> for Mutation<M>
where
    M: Consistent + From<OwnedCore<Data<M>>> + Parametric + Into<OwnedCore<Data<M>>>,
{
    fn as_ref(&self) -> &Self {
        self
    }
}

impl<M> AsMut<Self> for Mutation<M>
where
    M: Consistent + From<OwnedCore<Data<M>>> + Parametric + Into<OwnedCore<Data<M>>>,
{
    fn as_mut(&mut self) -> &mut Self {
        self
    }
}

impl<M> AsStorage<Arc<Data<M>>> for Mutation<M>
where
    M: Consistent + From<OwnedCore<Data<M>>> + Parametric + Into<OwnedCore<Data<M>>>,
{
    fn as_storage(&self) -> &Storage<Arc<Data<M>>> {
        self.inner.to_ref_core().unfuse().1
    }
}

impl<M> AsStorage<Edge<Data<M>>> for Mutation<M>
where
    M: Consistent + From<OwnedCore<Data<M>>> + Parametric + Into<OwnedCore<Data<M>>>,
{
    fn as_storage(&self) -> &Storage<Edge<Data<M>>> {
        self.inner.to_ref_core().unfuse().2
    }
}

impl<M> AsStorage<Face<Data<M>>> for Mutation<M>
where
    M: Consistent + From<OwnedCore<Data<M>>> + Parametric + Into<OwnedCore<Data<M>>>,
{
    fn as_storage(&self) -> &Storage<Face<Data<M>>> {
        self.inner.to_ref_core().unfuse().3
    }
}

impl<M> AsStorage<Vertex<Data<M>>> for Mutation<M>
where
    M: Consistent + From<OwnedCore<Data<M>>> + Parametric + Into<OwnedCore<Data<M>>>,
{
    fn as_storage(&self) -> &Storage<Vertex<Data<M>>> {
        self.inner.to_ref_core().unfuse().0
    }
}

// TODO: This is a hack. Replace this with delegation.
impl<M> Deref for Mutation<M>
where
    M: Consistent + From<OwnedCore<Data<M>>> + Parametric + Into<OwnedCore<Data<M>>>,
{
    type Target = FaceMutation<M>;

    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl<M> DerefMut for Mutation<M>
where
    M: Consistent + From<OwnedCore<Data<M>>> + Parametric + Into<OwnedCore<Data<M>>>,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.inner
    }
}

impl<M> From<M> for Mutation<M>
where
    M: Consistent + From<OwnedCore<Data<M>>> + Parametric + Into<OwnedCore<Data<M>>>,
{
    fn from(graph: M) -> Self {
        Mutation {
            inner: graph.into().into(),
        }
    }
}

impl<M> Parametric for Mutation<M>
where
    M: Consistent + From<OwnedCore<Data<M>>> + Parametric + Into<OwnedCore<Data<M>>>,
{
    type Data = Data<M>;
}

impl<M> Transact<M> for Mutation<M>
where
    M: Consistent + From<OwnedCore<Data<M>>> + Parametric + Into<OwnedCore<Data<M>>>,
{
    type Output = M;
    type Error = GraphError;

    fn commit(self) -> Result<Self::Output, Self::Error> {
        self.inner.commit().map(|core| core.into())
    }
}

pub trait Mutable:
    Consistent + From<OwnedCore<Data<Self>>> + Parametric + Into<OwnedCore<Data<Self>>>
{
}

impl<M> Mutable for M where
    M: Consistent + From<OwnedCore<Data<M>>> + Parametric + Into<OwnedCore<Data<M>>>
{
}
<commit_msg>Use type parameter for graph data in `Mutation` implementations.<commit_after>pub mod edge;
pub mod face;
pub mod path;
pub mod vertex;

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

use crate::entity::storage::{AsStorage, Storage};
use crate::graph::core::OwnedCore;
use crate::graph::data::{Data, Parametric};
use crate::graph::edge::{Arc, Edge};
use crate::graph::face::Face;
use crate::graph::mutation::face::FaceMutation;
use crate::graph::vertex::Vertex;
use crate::graph::{GraphData, GraphError};
use crate::transact::Transact;

/// Marker trait for graph representations that promise to be in a consistent
/// state.
///
/// This trait is only implemented by representations that ensure that their
/// storage is only ever mutated via the mutation API (and therefore is
/// consistent). Note that `Core` does not implement this trait and instead acts
/// as a raw container for topological storage that can be freely manipulated.
///
/// This trait allows code to make assumptions about the data it operates
/// against. For example, views expose an API to user code that assumes that
/// topologies are present and therefore unwraps values.
pub trait Consistent {}

impl<'a, T> Consistent for &'a T where T: Consistent {}

impl<'a, T> Consistent for &'a mut T where T: Consistent {}

/// Graph mutation.
pub struct Mutation<M>
where
    M: Consistent + From<OwnedCore<Data<M>>> + Parametric + Into<OwnedCore<Data<M>>>,
{
    inner: FaceMutation<M>,
}

impl<M, G> Mutation<M>
where
    M: Consistent + From<OwnedCore<G>> + Parametric<Data = G> + Into<OwnedCore<G>>,
    G: GraphData,
{
}

impl<M, G> AsRef<Self> for Mutation<M>
where
    M: Consistent + From<OwnedCore<G>> + Parametric<Data = G> + Into<OwnedCore<G>>,
    G: GraphData,
{
    fn as_ref(&self) -> &Self {
        self
    }
}

impl<M, G> AsMut<Self> for Mutation<M>
where
    M: Consistent + From<OwnedCore<G>> + Parametric<Data = G> + Into<OwnedCore<G>>,
    G: GraphData,
{
    fn as_mut(&mut self) -> &mut Self {
        self
    }
}

impl<M, G> AsStorage<Arc<G>> for Mutation<M>
where
    M: Consistent + From<OwnedCore<G>> + Parametric<Data = G> + Into<OwnedCore<G>>,
    G: GraphData,
{
    fn as_storage(&self) -> &Storage<Arc<G>> {
        self.inner.to_ref_core().unfuse().1
    }
}

impl<M, G> AsStorage<Edge<G>> for Mutation<M>
where
    M: Consistent + From<OwnedCore<G>> + Parametric<Data = G> + Into<OwnedCore<G>>,
    G: GraphData,
{
    fn as_storage(&self) -> &Storage<Edge<G>> {
        self.inner.to_ref_core().unfuse().2
    }
}

impl<M, G> AsStorage<Face<G>> for Mutation<M>
where
    M: Consistent + From<OwnedCore<G>> + Parametric<Data = G> + Into<OwnedCore<G>>,
    G: GraphData,
{
    fn as_storage(&self) -> &Storage<Face<G>> {
        self.inner.to_ref_core().unfuse().3
    }
}

impl<M, G> AsStorage<Vertex<G>> for Mutation<M>
where
    M: Consistent + From<OwnedCore<G>> + Parametric<Data = G> + Into<OwnedCore<G>>,
    G: GraphData,
{
    fn as_storage(&self) -> &Storage<Vertex<G>> {
        self.inner.to_ref_core().unfuse().0
    }
}

// TODO: This is a hack. Replace this with delegation.
impl<M, G> Deref for Mutation<M>
where
    M: Consistent + From<OwnedCore<G>> + Parametric<Data = G> + Into<OwnedCore<G>>,
    G: GraphData,
{
    type Target = FaceMutation<M>;

    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}

impl<M, G> DerefMut for Mutation<M>
where
    M: Consistent + From<OwnedCore<G>> + Parametric<Data = G> + Into<OwnedCore<G>>,
    G: GraphData,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.inner
    }
}

impl<M, G> From<M> for Mutation<M>
where
    M: Consistent + From<OwnedCore<G>> + Parametric<Data = G> + Into<OwnedCore<G>>,
    G: GraphData,
{
    fn from(graph: M) -> Self {
        Mutation {
            inner: graph.into().into(),
        }
    }
}

impl<M, G> Parametric for Mutation<M>
where
    M: Consistent + From<OwnedCore<G>> + Parametric<Data = G> + Into<OwnedCore<G>>,
    G: GraphData,
{
    type Data = G;
}

impl<M, G> Transact<M> for Mutation<M>
where
    M: Consistent + From<OwnedCore<G>> + Parametric<Data = G> + Into<OwnedCore<G>>,
    G: GraphData,
{
    type Output = M;
    type Error = GraphError;

    fn commit(self) -> Result<Self::Output, Self::Error> {
        self.inner.commit().map(|core| core.into())
    }
}

pub trait Mutable:
    Consistent + From<OwnedCore<Data<Self>>> + Parametric + Into<OwnedCore<Data<Self>>>
{
}

impl<M, G> Mutable for M
where
    M: Consistent + From<OwnedCore<G>> + Parametric<Data = G> + Into<OwnedCore<G>>,
    G: GraphData,
{
}
<|endoftext|>


<commit_before>use cocoa::base::{id, nil};
use cocoa::foundation::NSString;
use objc_bringup::NSError as _NSError;
use std::ffi::CStr;

#[derive(Debug)]
pub struct NSError(id);

impl NSError {
    pub fn new(raw: id) -> Option<Self> {
        if raw == nil { None } else { Some(NSError(raw)) }
    }

    pub fn code(&self) -> usize {
        unsafe { self.0.code() as usize }
    }

    pub fn domain(&self) -> &str {
        unsafe { CStr::from_ptr(self.0.domain().UTF8String()).to_str().unwrap_or(&"") }
    }

    pub fn localized_description(&self) -> &str {
        unsafe { CStr::from_ptr(self.0.localizedDescription().UTF8String()).to_str().unwrap_or(&"") }
    }
}
<commit_msg>Formatting<commit_after>use cocoa::base::{id, nil};
use cocoa::foundation::NSString;
use objc_bringup::NSError as _NSError;
use std::ffi::CStr;

#[derive(Debug)]
pub struct NSError(id);

impl NSError {
    pub fn new(raw: id) -> Option<Self> {
        if raw == nil { None } else { Some(NSError(raw)) }
    }

    pub fn code(&self) -> usize {
        unsafe { self.0.code() as usize }
    }

    pub fn domain(&self) -> &str {
        unsafe { CStr::from_ptr(self.0.domain().UTF8String()).to_str().unwrap_or(&"") }
    }

    pub fn localized_description(&self) -> &str {
        unsafe {
            CStr::from_ptr(self.0.localizedDescription().UTF8String()).to_str().unwrap_or(&"")
        }
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::{fmt, io};

/// This type represents the possible errors that can occur while
/// sending DogstatsD metrics.
#[derive(Debug)]
pub enum DogstatsdError {
    /// Chained IO errors.
    IoError(io::Error),
}

use self::DogstatsdError::*;

impl fmt::Display for DogstatsdError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            IoError(ref error) => write!(f, "{}", error),
        }
    }
}

impl Error for DogstatsdError {
    fn description(&self) -> &str {
        match *self {
            IoError(ref error) => error.description(),
        }
    }
}

impl From<io::Error> for DogstatsdError {
    fn from(e: io::Error) -> Self {
        IoError(e)
    }
}

#[cfg(test)]
mod tests {
    use super::DogstatsdError;
    use std::io;

    #[test]
    fn test_error_display() {
        let err = DogstatsdError::from(io::Error::new(io::ErrorKind::Other, "oh no!"));
        assert_eq!(format!("{}", err), "oh no!".to_owned());
    }
}
<commit_msg>impl Error::source rather than Error::description<commit_after>use std::error::Error;
use std::{fmt, io};

/// This type represents the possible errors that can occur while
/// sending DogstatsD metrics.
#[derive(Debug)]
pub enum DogstatsdError {
    /// Chained IO errors.
    IoError(io::Error),
}

use self::DogstatsdError::*;

impl fmt::Display for DogstatsdError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            IoError(ref error) => write!(f, "{}", error),
        }
    }
}

impl Error for DogstatsdError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match self {
            IoError(error) => Some(error),
        }
    }
}

impl From<io::Error> for DogstatsdError {
    fn from(e: io::Error) -> Self {
        IoError(e)
    }
}

#[cfg(test)]
mod tests {
    use super::DogstatsdError;
    use std::io;

    #[test]
    fn test_error_display() {
        let err = DogstatsdError::from(io::Error::new(io::ErrorKind::Other, "oh no!"));
        assert_eq!(format!("{}", err), "oh no!".to_owned());
    }
}
<|endoftext|>


<commit_before>//! Provides support for sending events to Sentry.
use std::env;
use std::fs;
use std::io::{BufRead, BufReader};
use std::collections::HashMap;
use std::process::Command;

#[cfg(not(windows))]
use uname::uname;
use chrono::Utc;
use serde_json::Value;
use username::get_user_name;
use hostname::get_hostname;
use anylog::LogEntry;
use regex::Regex;

use prelude::*;
use constants::{ARCH, PLATFORM};
use utils::{to_timestamp, get_model, get_family, detect_release_name};

lazy_static! {
    static ref COMPONENT_RE: Regex = Regex::new(
        r#"^([^:]+): (.*)$"#).unwrap();
}

#[derive(Serialize)]
pub struct Message {
    pub message: String,
    #[serde(skip_serializing_if="Vec::is_empty")]
    pub params: Vec<String>,
}

#[derive(Serialize)]
pub struct Exception {
    pub values: Vec<SingleException>,
}

#[derive(Serialize, Default)]
pub struct Frame {
    pub filename: String,
    pub abs_path: Option<String>,
    pub function: String,
    pub lineno: Option<u32>,
    pub context_line: Option<String>,
    pub pre_context: Option<Vec<String>>,
    pub post_context: Option<Vec<String>>,
}

#[derive(Serialize)]
pub struct Stacktrace {
    pub frames: Vec<Frame>,
}

#[derive(Serialize)]
pub struct SingleException {
    #[serde(rename="type")]
    pub ty: String,
    pub value: String,
    pub stacktrace: Option<Stacktrace>,
}

#[derive(Serialize)]
pub struct Breadcrumb {
    pub timestamp: Option<f64>,
    #[serde(rename="type")]
    pub ty: String,
    pub message: String,
    pub category: String,
}

/// Represents a Sentry event.
#[derive(Serialize)]
pub struct Event {
    pub tags: HashMap<String, String>,
    pub extra: HashMap<String, Value>,
    pub level: String,
    #[serde(skip_serializing_if="Option::is_none")]
    pub fingerprint: Option<Vec<String>>,
    #[serde(skip_serializing_if="Option::is_none", rename="sentry.interfaces.Message")]
    pub message: Option<Message>,
    pub platform: String,
    pub timestamp: f64,
    #[serde(skip_serializing_if="Option::is_none")]
    pub server_name: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub release: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub dist: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub environment: Option<String>,
    #[serde(skip_serializing_if="HashMap::is_empty")]
    pub user: HashMap<String, String>,
    #[serde(skip_serializing_if="HashMap::is_empty")]
    pub contexts: HashMap<String, HashMap<String, String>>,
    #[serde(skip_serializing_if="Vec::is_empty")]
    pub breadcrumbs: Vec<Breadcrumb>,
    pub exception: Option<Exception>,
}

fn get_server_name() -> Result<String> {
    let p = Command::new("uname").arg("-n").output()?;
    Ok(String::from_utf8(p.stdout)?.trim().to_owned())
}

impl Event {
    pub fn new() -> Event {
        Event {
            tags: HashMap::new(),
            extra: HashMap::new(),
            level: "error".into(),
            fingerprint: None,
            message: None,
            platform: "other".into(),
            timestamp: to_timestamp(Utc::now()),
            server_name: get_server_name().ok(),
            release: None,
            dist: None,
            environment: None,
            user: HashMap::new(),
            contexts: HashMap::new(),
            breadcrumbs: Vec::new(),
            exception: None,
        }
    }

    pub fn new_prefilled() -> Result<Event> {
        let mut event = Event::new();

        event.extra.insert("environ".into(), Value::Object(env::vars().map(|(k, v)| {
            (k, Value::String(v))
        }).collect()));

        event.user.insert("username".into(), get_user_name().unwrap_or("unknown".into()));

        let mut device = HashMap::new();
        if let Some(hostname) = get_hostname() {
            device.insert("name".into(), hostname);
        }
        if let Some(model) = get_model() {
            device.insert("model".into(), model);
        }
        if let Some(family) = get_family() {
            device.insert("family".into(), family);
        }
        device.insert("arch".into(), ARCH.into());
        event.contexts.insert("device".into(), device);

        let mut os = HashMap::new();
        #[cfg(not(windows))] {
            if let Ok(info) = uname() {
                os.insert("name".into(), info.sysname);
                os.insert("kernel_version".into(), info.version);
                os.insert("version".into(), info.release);
            }
        }
        if !os.contains_key("name") {
            os.insert("name".into(), PLATFORM.into());
        }
        event.contexts.insert("os".into(), os);
        Ok(event)
    }

    pub fn detect_release(&mut self) {
        self.release = detect_release_name().ok();
    }

    pub fn attach_logfile(&mut self, logfile: &str, with_component: bool) -> Result<()> {
        let f = fs::File::open(logfile)
            .chain_err(|| "Could not open logfile")?;
        let reader = BufReader::new(f);
        for line in reader.lines() {
            let line = line?;
            let rec = LogEntry::parse(line.as_bytes());
            let component;
            let message;

            if_chain! {
                if with_component;
                if let Some(caps) = COMPONENT_RE.captures(&rec.message());
                then {
                    component = caps.get(1).map(|x| x.as_str().to_string()).unwrap();
                    message = caps.get(2).map(|x| x.as_str().to_string()).unwrap();
                } else {
                    component = "log".to_string();
                    message = rec.message().to_string();
                }
            }

            self.breadcrumbs.push(Breadcrumb {
                timestamp: rec.utc_timestamp().map(|x| x.timestamp() as f64),
                message: message,
                ty: "default".to_string(),
                category: component.to_string(),
            })
        }

        if self.breadcrumbs.len() > 100 {
            let skip = self.breadcrumbs.len() - 100;
            self.breadcrumbs.drain(..skip);
        }

        Ok(())
    }
}
<commit_msg>feat(send): Use automatic IP addresses (#193)<commit_after>//! Provides support for sending events to Sentry.
use std::env;
use std::fs;
use std::io::{BufRead, BufReader};
use std::collections::HashMap;
use std::process::Command;

#[cfg(not(windows))]
use uname::uname;
use chrono::Utc;
use serde_json::Value;
use username::get_user_name;
use hostname::get_hostname;
use anylog::LogEntry;
use regex::Regex;

use prelude::*;
use constants::{ARCH, PLATFORM};
use utils::{to_timestamp, get_model, get_family, detect_release_name};

lazy_static! {
    static ref COMPONENT_RE: Regex = Regex::new(
        r#"^([^:]+): (.*)$"#).unwrap();
}

#[derive(Serialize)]
pub struct Message {
    pub message: String,
    #[serde(skip_serializing_if="Vec::is_empty")]
    pub params: Vec<String>,
}

#[derive(Serialize)]
pub struct Exception {
    pub values: Vec<SingleException>,
}

#[derive(Serialize, Default)]
pub struct Frame {
    pub filename: String,
    pub abs_path: Option<String>,
    pub function: String,
    pub lineno: Option<u32>,
    pub context_line: Option<String>,
    pub pre_context: Option<Vec<String>>,
    pub post_context: Option<Vec<String>>,
}

#[derive(Serialize)]
pub struct Stacktrace {
    pub frames: Vec<Frame>,
}

#[derive(Serialize)]
pub struct SingleException {
    #[serde(rename="type")]
    pub ty: String,
    pub value: String,
    pub stacktrace: Option<Stacktrace>,
}

#[derive(Serialize)]
pub struct Breadcrumb {
    pub timestamp: Option<f64>,
    #[serde(rename="type")]
    pub ty: String,
    pub message: String,
    pub category: String,
}

/// Represents a Sentry event.
#[derive(Serialize)]
pub struct Event {
    pub tags: HashMap<String, String>,
    pub extra: HashMap<String, Value>,
    pub level: String,
    #[serde(skip_serializing_if="Option::is_none")]
    pub fingerprint: Option<Vec<String>>,
    #[serde(skip_serializing_if="Option::is_none", rename="sentry.interfaces.Message")]
    pub message: Option<Message>,
    pub platform: String,
    pub timestamp: f64,
    #[serde(skip_serializing_if="Option::is_none")]
    pub server_name: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub release: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub dist: Option<String>,
    #[serde(skip_serializing_if="Option::is_none")]
    pub environment: Option<String>,
    #[serde(skip_serializing_if="HashMap::is_empty")]
    pub user: HashMap<String, String>,
    #[serde(skip_serializing_if="HashMap::is_empty")]
    pub contexts: HashMap<String, HashMap<String, String>>,
    #[serde(skip_serializing_if="Vec::is_empty")]
    pub breadcrumbs: Vec<Breadcrumb>,
    pub exception: Option<Exception>,
}

fn get_server_name() -> Result<String> {
    let p = Command::new("uname").arg("-n").output()?;
    Ok(String::from_utf8(p.stdout)?.trim().to_owned())
}

impl Event {
    pub fn new() -> Event {
        Event {
            tags: HashMap::new(),
            extra: HashMap::new(),
            level: "error".into(),
            fingerprint: None,
            message: None,
            platform: "other".into(),
            timestamp: to_timestamp(Utc::now()),
            server_name: get_server_name().ok(),
            release: None,
            dist: None,
            environment: None,
            user: HashMap::new(),
            contexts: HashMap::new(),
            breadcrumbs: Vec::new(),
            exception: None,
        }
    }

    pub fn new_prefilled() -> Result<Event> {
        let mut event = Event::new();

        event.extra.insert("environ".into(), Value::Object(env::vars().map(|(k, v)| {
            (k, Value::String(v))
        }).collect()));

        event.user.insert("username".into(), get_user_name().unwrap_or("unknown".into()));
        event.user.insert("ip_address".into(), String::from("{{auto}}"));

        let mut device = HashMap::new();
        if let Some(hostname) = get_hostname() {
            device.insert("name".into(), hostname);
        }
        if let Some(model) = get_model() {
            device.insert("model".into(), model);
        }
        if let Some(family) = get_family() {
            device.insert("family".into(), family);
        }
        device.insert("arch".into(), ARCH.into());
        event.contexts.insert("device".into(), device);

        let mut os = HashMap::new();
        #[cfg(not(windows))] {
            if let Ok(info) = uname() {
                os.insert("name".into(), info.sysname);
                os.insert("kernel_version".into(), info.version);
                os.insert("version".into(), info.release);
            }
        }
        if !os.contains_key("name") {
            os.insert("name".into(), PLATFORM.into());
        }
        event.contexts.insert("os".into(), os);
        Ok(event)
    }

    pub fn detect_release(&mut self) {
        self.release = detect_release_name().ok();
    }

    pub fn attach_logfile(&mut self, logfile: &str, with_component: bool) -> Result<()> {
        let f = fs::File::open(logfile)
            .chain_err(|| "Could not open logfile")?;
        let reader = BufReader::new(f);
        for line in reader.lines() {
            let line = line?;
            let rec = LogEntry::parse(line.as_bytes());
            let component;
            let message;

            if_chain! {
                if with_component;
                if let Some(caps) = COMPONENT_RE.captures(&rec.message());
                then {
                    component = caps.get(1).map(|x| x.as_str().to_string()).unwrap();
                    message = caps.get(2).map(|x| x.as_str().to_string()).unwrap();
                } else {
                    component = "log".to_string();
                    message = rec.message().to_string();
                }
            }

            self.breadcrumbs.push(Breadcrumb {
                timestamp: rec.utc_timestamp().map(|x| x.timestamp() as f64),
                message: message,
                ty: "default".to_string(),
                category: component.to_string(),
            })
        }

        if self.breadcrumbs.len() > 100 {
            let skip = self.breadcrumbs.len() - 100;
            self.breadcrumbs.drain(..skip);
        }

        Ok(())
    }
}
<|endoftext|>