<commit_before>extern crate hyper;
extern crate serde_json;

use request;

pub use types::{Account, CreateAccountResponse};

impl Account {
    pub fn new(short_name: &str, author_name: &str, author_url: &str) -> Account {
        Account {
            short_name: short_name.to_string(),
            author_name: author_name.to_string(),
            author_url: author_url.to_string(),
            access_token: "".to_string(),
            auth_url: "".to_string(),
            page_count: 0,
        }
    }

    pub fn set_short_name(&mut self, short_name: &str) -> &mut Account {
        self.short_name = short_name.to_string();
        self
    }

    pub fn set_author_name(&mut self, author_name: &str) -> &mut Account {
        self.author_name = author_name.to_string();
        self
    }

    pub fn set_author_url(&mut self, author_url: &str) -> &mut Account {
        self.author_url = author_url.to_string();
        self
    }

    pub fn set_auth_url(&mut self, auth_url: &str) -> &mut Account {
        self.auth_url = auth_url.to_string();
        self
    }

    pub fn set_access_token(&mut self, access_token: &str) -> &mut Account {
        self.access_token = access_token.to_string();
        self
    }

    pub fn create_account(&mut self) -> String {
        let url = format!(
            "https://api.telegra.ph/createAccount?short_name={}&author_name={}",
            self.short_name,
            self.author_name
        );
        let res_json = request::get(&url);
        let decoded: CreateAccountResponse = serde_json::from_str(&res_json).unwrap();

        self.set_access_token(&decoded.result.access_token)
            .set_auth_url(&decoded.result.auth_url);

        res_json
    }

    pub fn edit_accout_info(&self, acc: &Account) -> String {
        let url = String::from("https://api.telegra.ph/editAccountInfo?");
        let mut params: Vec<String> = vec![];

        let access_token = "access_token=".to_string() + &if acc.access_token.len() == 0 {
                self.access_token.clone()
            } else {
                acc.access_token.clone()
            };
        params.push(access_token);

        if acc.short_name.len() > 0 {
            let short_name = "short_name=".to_string() + &acc.short_name;
            params.push(short_name);
        }
        if acc.author_url.len() > 0 {
            let author_url = "author_url=".to_string() + &acc.author_url;
            params.push(author_url);
        }
        if acc.author_name.len() > 0 {
            let author_name = "author_name=".to_string() + &acc.author_name;
            params.push(author_name);
        }
        if acc.auth_url.len() > 0 {
            let auth_url = "auth_url=".to_string() + &acc.auth_url;
            params.push(auth_url);
        }

        let url = url + &params.join("&");

        request::get(&url)
    }

}
<commit_msg>added get_account_info method<commit_after>extern crate hyper;
extern crate serde_json;

use request;

pub use types::{Account, CreateAccountResponse};

impl Account {
    pub fn new(short_name: &str, author_name: &str, author_url: &str) -> Account {
        Account {
            short_name: short_name.to_string(),
            author_name: author_name.to_string(),
            author_url: author_url.to_string(),
            access_token: "".to_string(),
            auth_url: "".to_string(),
            page_count: 0,
        }
    }

    pub fn set_short_name(&mut self, short_name: &str) -> &mut Account {
        self.short_name = short_name.to_string();
        self
    }

    pub fn set_author_name(&mut self, author_name: &str) -> &mut Account {
        self.author_name = author_name.to_string();
        self
    }

    pub fn set_author_url(&mut self, author_url: &str) -> &mut Account {
        self.author_url = author_url.to_string();
        self
    }

    pub fn set_auth_url(&mut self, auth_url: &str) -> &mut Account {
        self.auth_url = auth_url.to_string();
        self
    }

    pub fn set_access_token(&mut self, access_token: &str) -> &mut Account {
        self.access_token = access_token.to_string();
        self
    }

    pub fn create_account(&mut self) -> String {
        let url = format!(
            "https://api.telegra.ph/createAccount?short_name={}&author_name={}",
            self.short_name,
            self.author_name
        );
        let res_json = request::get(&url);
        let decoded: CreateAccountResponse = serde_json::from_str(&res_json).unwrap();

        self.set_access_token(&decoded.result.access_token)
            .set_auth_url(&decoded.result.auth_url);

        res_json
    }

    pub fn edit_accout_info(&self, acc: &Account) -> String {
        let url = String::from("https://api.telegra.ph/editAccountInfo?");
        let mut params: Vec<String> = vec![];

        let access_token = "access_token=".to_string() + &if acc.access_token.len() == 0 {
                self.access_token.clone()
            } else {
                acc.access_token.clone()
            };
        params.push(access_token);

        if acc.short_name.len() > 0 {
            let short_name = "short_name=".to_string() + &acc.short_name;
            params.push(short_name);
        }
        if acc.author_url.len() > 0 {
            let author_url = "author_url=".to_string() + &acc.author_url;
            params.push(author_url);
        }
        if acc.author_name.len() > 0 {
            let author_name = "author_name=".to_string() + &acc.author_name;
            params.push(author_name);
        }
        if acc.auth_url.len() > 0 {
            let auth_url = "auth_url=".to_string() + &acc.auth_url;
            params.push(auth_url);
        }

        let url = url + &params.join("&");

        request::get(&url)
    }

    pub fn get_account_info(access_token: &String, fields_list: &Vec<&str>) -> String {
        let fields = fields_list.iter()
            .map(|&field| "\"".to_string() + field + "\"")
            .collect::<Vec<String>>()
            .join(",");
        let fields = "[".to_string() + &fields + "]";

        let url = format!(
            "https://api.telegra.ph/getAccountInfo?access_token={}&fields={}",
            access_token,
            fields
        );

        request::get(&url)
    }

}
<|endoftext|>


<commit_before>use curve25519_dalek::constants::ED25519_BASEPOINT;
use curve25519_dalek::scalar::Scalar;
use sha256::sha256_compress;
use std::fmt;
use util::bs58_encode_check;

pub const PAYMENT_ADDRESS_PREFIX: [u8; 2] = [0x16, 0x9a];
pub const SPENDING_KEY_PREFIX: [u8; 2] = [0xab, 0x36];
pub const VIEWING_KEY_PREFIX: [u8; 2] = [0x0b, 0x1c];

/// A Zcash spending key.
pub struct SpendingKey {
    a_sk: [u8; 32], // 252 bits; first 4 bits are always 0
}

/// A Zcash viewing key.
pub struct ViewingKey {
    pub sk_enc: [u8; 32],
    pub pk_enc: [u8; 32],
}

/// A Zcash payment address.
pub struct PaymentAddress {
    pub a_pk: [u8; 32],
    pub pk_enc: [u8; 32],
}

impl fmt::Display for SpendingKey {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut data = [0u8; 2 + 32];
        data[..2].copy_from_slice(&SPENDING_KEY_PREFIX);
        data[2..34].copy_from_slice(&self.a_sk);

        f.write_str(bs58_encode_check(&data).as_str())
    }
}

impl fmt::Display for ViewingKey {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut data = [0u8; 2 + 32 * 2];
        data[..2].copy_from_slice(&VIEWING_KEY_PREFIX);
        data[2..34].copy_from_slice(&self.sk_enc);
        data[34..66].copy_from_slice(&self.pk_enc);

        f.write_str(bs58_encode_check(&data).as_str())
    }
}

impl fmt::Display for PaymentAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut data = [0u8; 2 + 32 * 2];
        data[..2].copy_from_slice(&PAYMENT_ADDRESS_PREFIX);
        data[2..34].copy_from_slice(&self.a_pk);
        data[34..66].copy_from_slice(&self.pk_enc);

        f.write_str(bs58_encode_check(&data).as_str())
    }
}

impl SpendingKey {
    /// Creates a new spending key instance for a given 252-bit *a_sk*.
    /// *a_sk* is represented by 32 bytes; the first four bits of the first byte are zeroed.
    pub fn new(a_sk_u256: [u8; 32]) -> SpendingKey {
        let mut a_sk_u252 = [0u8; 32];
        a_sk_u252.copy_from_slice(&a_sk_u256);
        a_sk_u252[0] &= 0x0f;

        SpendingKey { a_sk: a_sk_u252 }
    }

    /// Calculates the payment address for this spending key
    pub fn address(&self) -> PaymentAddress {
        let mut a_pk = [0u8; 32];
        pseudorandom_function_a_pk(&mut a_pk, &self.a_sk);

        PaymentAddress {
            a_pk: a_pk,
            pk_enc: self.viewing_key().pk_enc,
        }
    }

    /// Computes a viewing key for this spending key.
    pub fn viewing_key(&self) -> ViewingKey {
        let mut sk_enc = [0u8; 32];
        pseudorandom_function_sk_enc(&mut sk_enc, &self.a_sk);
        clamp_curve25519(&mut sk_enc);
        let pk = &Scalar(sk_enc) * &ED25519_BASEPOINT;
        let pk_enc = pk.compress_montgomery().unwrap().to_bytes();

        ViewingKey {
            sk_enc: sk_enc,
            pk_enc: pk_enc,
        }
    }
}

pub fn pseudorandom_function_a_pk(a_pk: &mut [u8; 32], a_sk: &[u8; 32]) {
    pseudorandom_function(a_pk, a_sk, 0)
}

pub fn pseudorandom_function_sk_enc(sk_enc: &mut [u8; 32], a_sk: &[u8; 32]) {
    pseudorandom_function(sk_enc, a_sk, 1)
}

fn pseudorandom_function(dst: &mut [u8; 32], input: &[u8; 32], t: u8) {
    let mut data = [0u8; 64];
    data[..32].copy_from_slice(input);
    data[0] = 0xc0 | (data[0] & 0x0f);
    data[32] = t;
    sha256_compress(dst, &data);
}

fn clamp_curve25519(key: &mut [u8; 32]) {
    key[0] &= 248;
    key[31] &= 127;
    key[31] |= 64;
}

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

    static ENCODED: [(&str, &str); 5] = [
        (
            "SKxny894fJe2rmZjeuoE6GVfNkWoXfPp8337VrLLNWG56FfQtuS1",
            "zcbxovDeXGJJikZH5wQkcQvYx1gzsRt9mR5UnQir6NY8hhPHdgK7z7dE1vfa55Bq3JHJu7isfuWQGYrvMbLnud74z2vS4tS",
        ),
        (
            "SKxoo5QkFQgTbdc6EWRKyHPMdmtNDJhqudrAVhen9b4kjCwN6CeV",
            "zcRYvLiURno1LhXq95e8avXFcH2fKKToSFfhqaVKTy8mGH7i6SJbfuWcm4h9rEA6DvswrbxDhFGDQgpdDYV8zwUoHvwNvFX",
        ),
        (
            "SKxsVGKsCESoVb3Gfm762psjRtGHmjmv7HVjHckud5MnESfktUuG",
            "zcWGguu2UPfNhh1ygWW9Joo3osvncsuehtz5ewvXd78vFDdnDCRNG6QeKSZpwZmYmkfEutPVf8HzCfBytqXWsEcF2iBAM1e",
        ),
        (
            "SKxp72QGQ2qtovHSoVnPp8jRFQpHBhG1xF8s27iRFjPXXkYMQUA6",
            "zcWZomPYMEjJ49S4UHcvTnhjYqogfdYJuEDMURDpbkrz94bkzdTdJEZKWkkpQ8nK62eyLkZCvLZDFtLC2Cq5BmEK3WCKGMN",
        ),
        (
            "SKxpmLdykLu3xxSXtw1EA7iLJnXu8hFh8hhmW1B2J2194ijh5CR4",
            "zcgjj3fJF59QGBufopx3F51jCjUpXbgEzec7YQT6jRt4Ebu5EV3AW4jHPN6ZdXhmygBvQDRJrXoZLa3Lkh5GqnsFUzt7Qok",
        ),
    ];

    #[test]
    fn spending_keys_to_payment_addresses() {
        for &(spending_key_encoded, payment_address_encoded) in ENCODED.iter() {
            let mut a_sk = [0u8; 32];
            a_sk.copy_from_slice(
                &bs58::decode(spending_key_encoded).into_vec().unwrap()[2..34],
            );
            let spending_key = SpendingKey::new(a_sk);
            assert_eq!(spending_key_encoded, spending_key.to_string());
            let payment_address = spending_key.address();
            assert_eq!(payment_address_encoded, payment_address.to_string());
        }
    }
}
<commit_msg>Update the viewing key encoding to the latest Zcash Protocol changes and added some tests<commit_after>use curve25519_dalek::constants::ED25519_BASEPOINT;
use curve25519_dalek::scalar::Scalar;
use sha256::sha256_compress;
use std::fmt;
use util::bs58_encode_check;

pub const PAYMENT_ADDRESS_PREFIX: [u8; 2] = [0x16, 0x9a];
pub const SPENDING_KEY_PREFIX: [u8; 2] = [0xab, 0x36];
pub const VIEWING_KEY_PREFIX: [u8; 3] = [0xa8,0xab, 0xd3];

/// A Zcash spending key.
pub struct SpendingKey {
    a_sk: [u8; 32], // 252 bits; first 4 bits are always 0
}

/// A Zcash viewing key.
pub struct ViewingKey {
    pub sk_enc: [u8; 32],
    pub pk_enc: [u8; 32],
}

/// A Zcash payment address.
pub struct PaymentAddress {
    pub a_pk: [u8; 32],
    pub pk_enc: [u8; 32],
}

impl fmt::Display for SpendingKey {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut data = [0u8; 2 + 32];
        data[..2].copy_from_slice(&SPENDING_KEY_PREFIX);
        data[2..34].copy_from_slice(&self.a_sk);

        f.write_str(bs58_encode_check(&data).as_str())
    }
}

impl fmt::Display for ViewingKey {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut data = [0u8; 3 + 32 * 2];
        data[..3].copy_from_slice(&VIEWING_KEY_PREFIX);
        data[2..34].copy_from_slice(&self.sk_enc);
        data[34..66].copy_from_slice(&self.pk_enc);

        f.write_str(bs58_encode_check(&data).as_str())
    }
}

impl fmt::Display for PaymentAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut data = [0u8; 2 + 32 * 2];
        data[..2].copy_from_slice(&PAYMENT_ADDRESS_PREFIX);
        data[2..34].copy_from_slice(&self.a_pk);
        data[34..66].copy_from_slice(&self.pk_enc);

        f.write_str(bs58_encode_check(&data).as_str())
    }
}

impl SpendingKey {
    /// Creates a new spending key instance for a given 252-bit *a_sk*.
    /// *a_sk* is represented by 32 bytes; the first four bits of the first byte are zeroed.
    pub fn new(a_sk_u256: [u8; 32]) -> SpendingKey {
        let mut a_sk_u252 = [0u8; 32];
        a_sk_u252.copy_from_slice(&a_sk_u256);
        a_sk_u252[0] &= 0x0f;

        SpendingKey { a_sk: a_sk_u252 }
    }

    /// Calculates the payment address for this spending key
    pub fn address(&self) -> PaymentAddress {
        let mut a_pk = [0u8; 32];
        pseudorandom_function_a_pk(&mut a_pk, &self.a_sk);

        PaymentAddress {
            a_pk: a_pk,
            pk_enc: self.viewing_key().pk_enc,
        }
    }

    /// Computes a viewing key for this spending key.
    pub fn viewing_key(&self) -> ViewingKey {
        let mut sk_enc = [0u8; 32];
        pseudorandom_function_sk_enc(&mut sk_enc, &self.a_sk);
        clamp_curve25519(&mut sk_enc);
        let pk = &Scalar(sk_enc) * &ED25519_BASEPOINT;
        let pk_enc = pk.compress_montgomery().unwrap().to_bytes();

        ViewingKey {
            sk_enc: sk_enc,
            pk_enc: pk_enc,
        }
    }
}

pub fn pseudorandom_function_a_pk(a_pk: &mut [u8; 32], a_sk: &[u8; 32]) {
    pseudorandom_function(a_pk, a_sk, 0)
}

pub fn pseudorandom_function_sk_enc(sk_enc: &mut [u8; 32], a_sk: &[u8; 32]) {
    pseudorandom_function(sk_enc, a_sk, 1)
}

fn pseudorandom_function(dst: &mut [u8; 32], input: &[u8; 32], t: u8) {
    let mut data = [0u8; 64];
    data[..32].copy_from_slice(input);
    data[0] = 0xc0 | (data[0] & 0x0f);
    data[32] = t;
    sha256_compress(dst, &data);
}

fn clamp_curve25519(key: &mut [u8; 32]) {
    key[0] &= 248;
    key[31] &= 127;
    key[31] |= 64;
}

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

    static ENCODED: [(&str, &str, &str); 5] = [
        (
            "SKxny894fJe2rmZjeuoE6GVfNkWoXfPp8337VrLLNWG56FfQtuS1",
            "zcbxovDeXGJJikZH5wQkcQvYx1gzsRt9mR5UnQir6NY8hhPHdgK7z7dE1vfa55Bq3JHJu7isfuWQGYrvMbLnud74z2vS4tS",
            "ZiUBSSMXjXXeFEJVTNiEh3frFcxpBwuCWHEjnobHfGS2keQNF3LTJGGaBRcfamK4rBZHve1kh4YjSCLGwtZpt35WuzHSBTvC3",
        ),
        (
            "SKxoo5QkFQgTbdc6EWRKyHPMdmtNDJhqudrAVhen9b4kjCwN6CeV",
            "zcRYvLiURno1LhXq95e8avXFcH2fKKToSFfhqaVKTy8mGH7i6SJbfuWcm4h9rEA6DvswrbxDhFGDQgpdDYV8zwUoHvwNvFX",
            "ZiTn6ZX2k5RyZ2pUZDtNMA97FK2pYNzAt2cZwMc1ZN8SwUNUKFWSbAahYakDUSWcJZYQuUBzdfDMqYdJ6VNxa8G4388qgSHFq",
        ),
        (
            "SKxsVGKsCESoVb3Gfm762psjRtGHmjmv7HVjHckud5MnESfktUuG",
            "zcWGguu2UPfNhh1ygWW9Joo3osvncsuehtz5ewvXd78vFDdnDCRNG6QeKSZpwZmYmkfEutPVf8HzCfBytqXWsEcF2iBAM1e",
            "ZiVgrhGoZJzDZQn6whow6sHZEcLMSsU6iwghsqdbbFdG7XjDppunWwGEUm4jjjffpqzNCmF9g6DcteQQk4GYwkknWP3TLdr3C",
        ),
        (
            "SKxp72QGQ2qtovHSoVnPp8jRFQpHBhG1xF8s27iRFjPXXkYMQUA6",
            "zcWZomPYMEjJ49S4UHcvTnhjYqogfdYJuEDMURDpbkrz94bkzdTdJEZKWkkpQ8nK62eyLkZCvLZDFtLC2Cq5BmEK3WCKGMN",
            "ZiThWXyRSm1gWKLi3Z17CZPEqrqwrpbWeGeR6HT9iMzSYkGs7shmeyDypffhS3CMyRxJ6D2XaoY1gSU4MGSpzXXq9JXvPTnPS",
        ),
        (
            "SKxpmLdykLu3xxSXtw1EA7iLJnXu8hFh8hhmW1B2J2194ijh5CR4",
            "zcgjj3fJF59QGBufopx3F51jCjUpXbgEzec7YQT6jRt4Ebu5EV3AW4jHPN6ZdXhmygBvQDRJrXoZLa3Lkh5GqnsFUzt7Qok",
            "ZiVhAKxsvDeBoATdHsPwDAUuBeKYHwovTz841wNmemSnesn4PqHCYikBdFrCfdxY464yYuJZVoZs5fC3AQz9hQhSTf7q4LEb7",
        ),
    ];

    #[test]
    fn spending_keys_to_payment_addresses() {
        for &(spending_key_encoded, payment_address_encoded, _) in ENCODED.iter() {
            let mut a_sk = [0u8; 32];
            a_sk.copy_from_slice(
                &bs58::decode(spending_key_encoded).into_vec().unwrap()[2..34],
            );
            let spending_key = SpendingKey::new(a_sk);
            assert_eq!(spending_key_encoded, spending_key.to_string());
            let payment_address = spending_key.address();
            assert_eq!(payment_address_encoded, payment_address.to_string());
        }
    }

    #[test]
    fn spending_keys_to_viewing_keys() {
        for &(spending_key_encoded, _,viewing_key_encoded) in ENCODED.iter() {
            let mut a_sk = [0u8; 32];
            a_sk.copy_from_slice(
                &bs58::decode(spending_key_encoded).into_vec().unwrap()[2..34],
            );
            let spending_key = SpendingKey::new(a_sk);
            assert_eq!(spending_key_encoded, spending_key.to_string());
            let viewing_key = spending_key.viewing_key();
            assert_eq!(viewing_key_encoded, viewing_key.to_string());
        }
    }
}
<|endoftext|>


<commit_before>use regex::Regex;
use std::sync::mpsc::channel;

use adapter::ChatAdapter;
use handler::MessageHandler;

/// The Chatbot is the central data structure of the chatbot platform. It contains a `run` method
/// which listens for messages from adapters and routes them to handlers. Any program which uses
/// chatbot will need to minimally create a Chatbot, add an adapter, add a handler, and call Chatbot
/// [`run`](chatbot/struct.Chatbot.html#method.run).
pub struct Chatbot {
    name: String,
    adapters: Vec<Box<ChatAdapter>>,
    handlers: Vec<Box<MessageHandler>>,
    addresser: Option<Regex>
}

impl Chatbot {
    /// Create a new chatbot instance.
    ///
    /// The name provided here will be used for message filtering and in handlers for whatever they
    /// want. You'll want to make your binding mutable so you can call `add_adapter` and
    /// `add_handler`.
    pub fn new(name: &str) -> Chatbot {
        Chatbot {
            name: name.to_owned(),
            adapters: Vec::new(),
            handlers: Vec::new(),
            addresser: None
        }
    }

    /// Return the name provided in initialization
    pub fn get_name(&self) -> &str {
        self.name.as_ref()
    }

    pub fn get_addresser(&self) -> Option<&Regex> {
        self.addresser.as_ref()
    }

    pub fn address_by_name(&mut self) {
        let addresser_str = format!(r"^\s*@?{}[:,\s]\s*", self.get_name());
        let addresser = Regex::new(addresser_str.as_ref());

        self.addresser = addresser.ok();
    }

    /// Add a ChatAdapter to the bot
    ///
    /// Add as many adapters as you like. The IncomingMessages sent by adapters are made available
    /// to all handlers regardless of how many adapters exist. The IncomingMessage.reply method
    /// makes sure the response is sent back to the adapter from whence the message came.
    pub fn add_adapter<T>(&mut self, adapter: T)
        where T: ChatAdapter + 'static
    {
        println!("Adding adapter {}", adapter.get_name());
        self.adapters.push(Box::new(adapter))
    }

    /// Add a MessageHandler to the bot
    ///
    /// The more handlers you have the more useful your bot becomes (for potentially loose
    /// definitions of useful :P). Check out the handler! macro for making simple handlers and also
    /// see the `MessageHandler` implementors section for a list of built in handlers.
    pub fn add_handler<T>(&mut self, handler: T)
        where T: MessageHandler + 'static
    {
        println!("Adding handler {}", handler.name());
        self.handlers.push(Box::new(handler))
    }

    /// Start processing messages
    ///
    /// Call process_events on all of the adapters and `recv` on the `IncomingMessage` channel.
    /// Distribute IncomingMessages to list of handlers.
    pub fn run(&self) {

        assert!(self.adapters.len() > 0);
        assert!(self.handlers.len() > 0);

        println!("Chatbot: {} adapters", self.adapters.len());
        println!("Chatbot: {} handlers", self.handlers.len());

        let (incoming_tx, incoming_rx) = channel();

        for adapter in &self.adapters {
            adapter.process_events(self, incoming_tx.clone());
        }

        loop {
            // Get message from adapter
            let msg = match incoming_rx.recv() {
                Ok(msg) => msg,
                Err(_) => break
            };

            // Distribute to handlers
            for handler in &self.handlers {
                let msg_str = msg.get_contents();

                if handler.can_handle(msg_str) {
                    if let Some(ref addresser) = self.addresser {
                      if !addresser.is_match(msg_str) {
                        continue;
                      }
                    }

                    match handler.handle(&msg) {
                        Err(e) => {
                            println!("Error in handler `{}`", handler.name());
                            println!("{:?}", e);
                            println!("The incoming message was {}", msg_str);

                            // TODO remove handler?
                        },
                        _ => ()
                    }
                }
            }
        }

        println!("chatbot shutting down");
    }
}

#[cfg(test)]
mod tests {
    use chatbot::Chatbot;
    use adapter::CliAdapter;

    #[test]
    fn test_create_chatbot() {
        let name = "testbot";
        let bot = Chatbot::new("testbot");
        assert_eq!(bot.get_name(), name);
    }

    #[test]
    fn test_chatbot_add_adapter() {
        let mut bot = Chatbot::new("testbot");
        let cli = CliAdapter::new();
        bot.add_adapter(cli);
    }

    #[test]
    fn test_chatbot_add_handler() {
        let mut bot = Chatbot::new("testbot");
        let echo = handler!("EchoHandler", r"echo .+", |_, msg| {
            Some(msg.to_owned())
        });
        bot.add_handler(echo);
    }

    #[test]
    fn test_chatbot_address_by_name() {
        let mut bot = Chatbot::new("testbot");
        bot.address_by_name();
    }

    #[test]
    fn test_chatbot_address_matches() {
        let mut bot = Chatbot::new("testbot");
        bot.address_by_name();
        let addresser = bot.get_addresser().unwrap();

        assert!(!addresser.is_match("testbotping"),
                "Shouldn't match bot name without a break (space, colon, comma)");
        assert!(!addresser.is_match("@testbotping"),
                "Shouldn't match bot name with '@' sign minus a break (space, colon, comma)");

        // Space separation
        assert!(addresser.is_match("testbot ping"), "Should match bot name with space");
        assert!(addresser.is_match("@testbot ping"),
                "Should match bot name with '@' sign plus '@' space");

        // Colon separation
        assert!(addresser.is_match("testbot:ping"), "Should match bot name with colon");
        assert!(addresser.is_match("testbot: ping"), "Should match bot name with colon and space");
        assert!(addresser.is_match("@testbot:ping"),
                "Should match bot name with '@' sign plus colon");
        assert!(addresser.is_match("@testbot: ping"),
                "Should match bot name with '@' sign plus colon and space");

        // Comma separation
        assert!(addresser.is_match("testbot,ping"), "Should match bot name with comma");
        assert!(addresser.is_match("testbot, ping"), "Should match bot name with comma and space");
        assert!(addresser.is_match("@testbot,ping"),
                "Should match bot name with '@' sign plus comma");
        assert!(addresser.is_match("@testbot, ping"),
                "Should match bot name with '@' sign plus comma and space");
    }
}
<commit_msg>Add documentation and comments<commit_after>use regex::Regex;
use std::sync::mpsc::channel;

use adapter::ChatAdapter;
use handler::MessageHandler;

/// The Chatbot is the central data structure of the chatbot platform. It contains a `run` method
/// which listens for messages from adapters and routes them to handlers. Any program which uses
/// chatbot will need to minimally create a Chatbot, add an adapter, add a handler, and call Chatbot
/// [`run`](chatbot/struct.Chatbot.html#method.run).
pub struct Chatbot {
    name: String,
    adapters: Vec<Box<ChatAdapter>>,
    handlers: Vec<Box<MessageHandler>>,
    addresser: Option<Regex>
}

impl Chatbot {
    /// Create a new chatbot instance.
    ///
    /// The name provided here will be used for message filtering and in handlers for whatever they
    /// want. You'll want to make your binding mutable so you can call `add_adapter` and
    /// `add_handler`.
    pub fn new(name: &str) -> Chatbot {
        Chatbot {
            name: name.to_owned(),
            adapters: Vec::new(),
            handlers: Vec::new(),
            addresser: None
        }
    }

    /// Return the name provided in initialization
    pub fn get_name(&self) -> &str {
        self.name.as_ref()
    }

    /// Return the regular expression of what the bot will be addressed by, if present
    pub fn get_addresser(&self) -> Option<&Regex> {
        self.addresser.as_ref()
    }

    /// Turns on the requirement of addressing the bot before a handler is triggered
    pub fn address_by_name(&mut self) {
        let addresser_str = format!(r"^\s*@?{}[:,\s]\s*", self.get_name());
        let addresser = Regex::new(addresser_str.as_ref());

        self.addresser = addresser.ok();
    }

    /// Add a ChatAdapter to the bot
    ///
    /// Add as many adapters as you like. The IncomingMessages sent by adapters are made available
    /// to all handlers regardless of how many adapters exist. The IncomingMessage.reply method
    /// makes sure the response is sent back to the adapter from whence the message came.
    pub fn add_adapter<T>(&mut self, adapter: T)
        where T: ChatAdapter + 'static
    {
        println!("Adding adapter {}", adapter.get_name());
        self.adapters.push(Box::new(adapter))
    }

    /// Add a MessageHandler to the bot
    ///
    /// The more handlers you have the more useful your bot becomes (for potentially loose
    /// definitions of useful :P). Check out the handler! macro for making simple handlers and also
    /// see the `MessageHandler` implementors section for a list of built in handlers.
    pub fn add_handler<T>(&mut self, handler: T)
        where T: MessageHandler + 'static
    {
        println!("Adding handler {}", handler.name());
        self.handlers.push(Box::new(handler))
    }

    /// Start processing messages
    ///
    /// Call process_events on all of the adapters and `recv` on the `IncomingMessage` channel.
    /// Distribute IncomingMessages to list of handlers.
    pub fn run(&self) {

        assert!(self.adapters.len() > 0);
        assert!(self.handlers.len() > 0);

        println!("Chatbot: {} adapters", self.adapters.len());
        println!("Chatbot: {} handlers", self.handlers.len());

        let (incoming_tx, incoming_rx) = channel();

        for adapter in &self.adapters {
            adapter.process_events(self, incoming_tx.clone());
        }

        loop {
            // Get message from adapter
            let msg = match incoming_rx.recv() {
                Ok(msg) => msg,
                Err(_) => break
            };

            // Distribute to handlers
            for handler in &self.handlers {
                let msg_str = msg.get_contents();

                if handler.can_handle(msg_str) {
                    // When addresser is present, ignore handlers that don't directly call the
                    // bot's name
                    if let Some(ref addresser) = self.addresser {
                      if !addresser.is_match(msg_str) {
                        continue;
                      }
                    }

                    match handler.handle(&msg) {
                        Err(e) => {
                            println!("Error in handler `{}`", handler.name());
                            println!("{:?}", e);
                            println!("The incoming message was {}", msg_str);

                            // TODO remove handler?
                        },
                        _ => ()
                    }
                }
            }
        }

        println!("chatbot shutting down");
    }
}

#[cfg(test)]
mod tests {
    use chatbot::Chatbot;
    use adapter::CliAdapter;

    #[test]
    fn test_create_chatbot() {
        let name = "testbot";
        let bot = Chatbot::new("testbot");
        assert_eq!(bot.get_name(), name);
    }

    #[test]
    fn test_chatbot_add_adapter() {
        let mut bot = Chatbot::new("testbot");
        let cli = CliAdapter::new();
        bot.add_adapter(cli);
    }

    #[test]
    fn test_chatbot_add_handler() {
        let mut bot = Chatbot::new("testbot");
        let echo = handler!("EchoHandler", r"echo .+", |_, msg| {
            Some(msg.to_owned())
        });
        bot.add_handler(echo);
    }

    #[test]
    fn test_chatbot_address_by_name() {
        let mut bot = Chatbot::new("testbot");
        bot.address_by_name();
    }

    #[test]
    fn test_chatbot_address_matches() {
        let mut bot = Chatbot::new("testbot");
        bot.address_by_name();
        let addresser = bot.get_addresser().unwrap();

        assert!(!addresser.is_match("testbotping"),
                "Shouldn't match bot name without a break (space, colon, comma)");
        assert!(!addresser.is_match("@testbotping"),
                "Shouldn't match bot name with '@' sign minus a break (space, colon, comma)");

        // Space separation
        assert!(addresser.is_match("testbot ping"), "Should match bot name with space");
        assert!(addresser.is_match("@testbot ping"),
                "Should match bot name with '@' sign plus '@' space");

        // Colon separation
        assert!(addresser.is_match("testbot:ping"), "Should match bot name with colon");
        assert!(addresser.is_match("testbot: ping"), "Should match bot name with colon and space");
        assert!(addresser.is_match("@testbot:ping"),
                "Should match bot name with '@' sign plus colon");
        assert!(addresser.is_match("@testbot: ping"),
                "Should match bot name with '@' sign plus colon and space");

        // Comma separation
        assert!(addresser.is_match("testbot,ping"), "Should match bot name with comma");
        assert!(addresser.is_match("testbot, ping"), "Should match bot name with comma and space");
        assert!(addresser.is_match("@testbot,ping"),
                "Should match bot name with '@' sign plus comma");
        assert!(addresser.is_match("@testbot, ping"),
                "Should match bot name with '@' sign plus comma and space");
    }
}
<|endoftext|>


<commit_before>use std::path::PathBuf;
use std::process::Command;
use std::env;

fn main() {
    let target = env::var("TARGET").unwrap();
    // let out_dir = env::var("OUT_DIR").unwrap();
    let current_dir = env::current_dir().unwrap();

    // println!("target:      {:?}", target);
    // println!("out_dir:     {:?}", out_dir);
    // println!("current_dir: {:?}", current_dir);

    let libqmlbind_dir = current_dir.join("libqmlbind");
    let libqmlbind_build_dir = libqmlbind_dir.join("build");

    std::fs::create_dir_all(&libqmlbind_build_dir).unwrap();

    // Initialize git submodule
    if !libqmlbind_dir.join(".git").exists() {
        let _ = Command::new("git").args(&["submodule", "update", "--init"])
                                   .status();
    }

    Command::new("qmake").arg("../qmlbind").current_dir(&libqmlbind_build_dir).output().unwrap();
    Command::new("make").current_dir(&libqmlbind_build_dir).output().unwrap();
    Command::new("make").arg("staticlib").current_dir(&libqmlbind_build_dir).output().unwrap();

    println!("cargo:rustc-link-search={}", libqmlbind_build_dir.to_str().unwrap());
    println!("cargo:rustc-link-lib=static=qmlbind");

    let qt_dir = env::var("QT_DIR").map(|p| PathBuf::from(p)).unwrap_or({
        println!("Environnement variable 'QT_DIR' not set!");
        println!("Defaulting to ${{HOME}}/Qt/${{QT_VER}}/${{QT_COMP}} where:");
        let home_dir = env::home_dir().map(|p| PathBuf::from(p)).unwrap();
        let default_qt_ver = "5.7".to_string();
        let default_qt_comp = if target.contains("linux") {
            "gcc_64".to_string()
        } else if target.contains("darwin") {
            "clang_64".to_string()
        } else {
            panic!("Unsuported platform in gallery's build.rs!")
        };
        println!("    QT_VER:  {}", default_qt_ver);
        println!("    QT_COMP: {}", default_qt_comp);
        let qt_dir_default = home_dir.join("Qt")
                                  .join(env::var("QT_VER").unwrap_or(default_qt_ver))
                                  .join(env::var("QT_COMP").unwrap_or(default_qt_comp));
        qt_dir_default
    });
    println!("Using Qt directory: {:?}", qt_dir);
    println!("Use QT_DIR environment variable to ovewrite.");

    let qt_lib_dir = qt_dir.join("lib").to_str().unwrap().to_string();

    let osx_framework = if target.contains("darwin") { "=framework" }
                        else  { "" };
    // On Linux, libraries are name "Qt5Core", not "QtCore" as on OSX
    let linux_qt_lib_ver = if target.contains("linux") { "5" }
                           else  { "" };

    println!("cargo:rustc-link-search{}={}", osx_framework, qt_lib_dir);

    println!("cargo:rustc-link-lib{}=Qt{}Core", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Network", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Gui", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Qml", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Widgets", osx_framework, linux_qt_lib_ver);

    // On Linux, Qt needs icui18n, icuuc and icudata
    if target.contains("linux") {
        println!("cargo:rustc-link-lib=icui18n");
        println!("cargo:rustc-link-lib=icuuc");
        println!("cargo:rustc-link-lib=icudata");
    }

    println!("cargo:rustc-flags=-l stdc++");
}
<commit_msg>libqmlbind-sys: Catch qmake/make output and print it.<commit_after>use std::path::PathBuf;
use std::process::Command;
use std::env;

fn main() {
    let target = env::var("TARGET").unwrap();
    // let out_dir = env::var("OUT_DIR").unwrap();
    let current_dir = env::current_dir().unwrap();

    // println!("target:      {:?}", target);
    // println!("out_dir:     {:?}", out_dir);
    // println!("current_dir: {:?}", current_dir);

    let libqmlbind_dir = current_dir.join("libqmlbind");
    let libqmlbind_build_dir = libqmlbind_dir.join("build");

    std::fs::create_dir_all(&libqmlbind_build_dir).unwrap();

    // Initialize git submodule
    if !libqmlbind_dir.join(".git").exists() {
        let _ = Command::new("git").args(&["submodule", "update", "--init"])
                                   .status();
    }

    let output = Command::new("qmake").arg("../qmlbind")
                                      .current_dir(&libqmlbind_build_dir)
                                      .output().unwrap();
    println!("output.status: {}", output.status);
    println!("output.stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("output.stderr: {}", String::from_utf8_lossy(&output.stderr));
    assert!(output.status.success(), "failed to execute qmake process");

    let output = Command::new("make").current_dir(&libqmlbind_build_dir).output().unwrap();
    println!("output.status: {}", output.status);
    println!("output.stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("output.stderr: {}", String::from_utf8_lossy(&output.stderr));
    assert!(output.status.success(), "failed to execute make process");

    let output = Command::new("make").arg("staticlib")
                                     .current_dir(&libqmlbind_build_dir)
                                     .output().unwrap();
    println!("output.status: {}", output.status);
    println!("output.stdout: {}", String::from_utf8_lossy(&output.stdout));
    println!("output.stderr: {}", String::from_utf8_lossy(&output.stderr));
    assert!(output.status.success(), "failed to execute 'make staticlib' process");

    println!("cargo:rustc-link-search={}", libqmlbind_build_dir.to_str().unwrap());
    println!("cargo:rustc-link-lib=static=qmlbind");

    let qt_dir = env::var("QT_DIR").map(|p| PathBuf::from(p)).unwrap_or({
        println!("Environnement variable 'QT_DIR' not set!");
        println!("Defaulting to ${{HOME}}/Qt/${{QT_VER}}/${{QT_COMP}} where:");
        let home_dir = env::home_dir().map(|p| PathBuf::from(p)).unwrap();
        let default_qt_ver = "5.7".to_string();
        let default_qt_comp = if target.contains("linux") {
            "gcc_64".to_string()
        } else if target.contains("darwin") {
            "clang_64".to_string()
        } else {
            panic!("Unsuported platform in gallery's build.rs!")
        };
        println!("    QT_VER:  {}", default_qt_ver);
        println!("    QT_COMP: {}", default_qt_comp);
        let qt_dir_default = home_dir.join("Qt")
                                  .join(env::var("QT_VER").unwrap_or(default_qt_ver))
                                  .join(env::var("QT_COMP").unwrap_or(default_qt_comp));
        qt_dir_default
    });
    println!("Using Qt directory: {:?}", qt_dir);
    println!("Use QT_DIR environment variable to ovewrite.");

    let qt_lib_dir = qt_dir.join("lib").to_str().unwrap().to_string();

    let osx_framework = if target.contains("darwin") { "=framework" }
                        else  { "" };
    // On Linux, libraries are name "Qt5Core", not "QtCore" as on OSX
    let linux_qt_lib_ver = if target.contains("linux") { "5" }
                           else  { "" };

    println!("cargo:rustc-link-search{}={}", osx_framework, qt_lib_dir);

    println!("cargo:rustc-link-lib{}=Qt{}Core", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Network", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Gui", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Qml", osx_framework, linux_qt_lib_ver);
    println!("cargo:rustc-link-lib{}=Qt{}Widgets", osx_framework, linux_qt_lib_ver);

    // On Linux, Qt needs icui18n, icuuc and icudata
    if target.contains("linux") {
        println!("cargo:rustc-link-lib=icui18n");
        println!("cargo:rustc-link-lib=icuuc");
        println!("cargo:rustc-link-lib=icudata");
    }

    println!("cargo:rustc-flags=-l stdc++");
}
<|endoftext|>


<commit_before>use std::mem;
use super::gl;
use super::gl_lib::types::*;
use super::{Buffer, ArrayBufferBinder, ElementArrayBufferBinder};
use super::{Shader, ShaderType};

pub struct Context {
    pub array_buffer: ArrayBufferBinder,
    pub element_array_buffer: ElementArrayBufferBinder
}

impl Context {
    pub unsafe fn current_context() -> Self {
        Context {
            array_buffer: ArrayBufferBinder,
            element_array_buffer: ElementArrayBufferBinder
        }
    }

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

    pub fn clear(&mut self, buffers: super::BufferBits) {
        unsafe {
            gl::Clear(buffers.bits())
        }
    }

    pub fn vertex_attrib_pointer(&self,
                                 attrib: super::ProgramAttrib,
                                 components: i8,
                                 gl_type: super::DataType,
                                 normalized: bool,
                                 stride: usize,
                                 offset: usize)
    {
        unsafe {
            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);
        }
    }

    pub fn gen_buffer(&self) -> Buffer {
        unsafe {
            let mut id : GLuint = mem::uninitialized();
            gl::GenBuffers(1, &mut id as *mut GLuint);
            Buffer::from_id(id)
        }
    }

    pub fn create_shader(&self, shader_type: ShaderType) -> Result<Shader, ()> {
        unsafe {
            let id = gl::CreateShader(shader_type as GLenum);
            if id > 0 {
                Ok(Shader::from_id(id))
            }
            else {
                Err(())
            }
        }
    }
}

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

#[macro_export]
macro_rules! bind_element_array_buffer {
    ($gl:expr, $buffer:expr) => {
        $gl.element_array_buffer.bind($buffer)
    }
}
<commit_msg>Add `Context.enable_vertex_attrib_array`<commit_after>use std::mem;
use super::gl;
use super::gl_lib::types::*;
use super::{Buffer, ArrayBufferBinder, ElementArrayBufferBinder};
use super::{Shader, ShaderType};

pub struct Context {
    pub array_buffer: ArrayBufferBinder,
    pub element_array_buffer: ElementArrayBufferBinder
}

impl Context {
    pub unsafe fn current_context() -> Self {
        Context {
            array_buffer: ArrayBufferBinder,
            element_array_buffer: ElementArrayBufferBinder
        }
    }

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

    pub fn clear(&mut self, buffers: super::BufferBits) {
        unsafe {
            gl::Clear(buffers.bits())
        }
    }

    pub fn vertex_attrib_pointer(&self,
                                 attrib: super::ProgramAttrib,
                                 components: i8,
                                 gl_type: super::DataType,
                                 normalized: bool,
                                 stride: usize,
                                 offset: usize)
    {
        unsafe {
            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);
        }
    }

    pub fn enable_vertex_attrib_array(&self, attrib: super::ProgramAttrib) {
        unsafe {
            gl::EnableVertexAttribArray(attrib.gl_index);
        }
    }

    pub fn gen_buffer(&self) -> Buffer {
        unsafe {
            let mut id : GLuint = mem::uninitialized();
            gl::GenBuffers(1, &mut id as *mut GLuint);
            Buffer::from_id(id)
        }
    }

    pub fn create_shader(&self, shader_type: ShaderType) -> Result<Shader, ()> {
        unsafe {
            let id = gl::CreateShader(shader_type as GLenum);
            if id > 0 {
                Ok(Shader::from_id(id))
            }
            else {
                Err(())
            }
        }
    }
}

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

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


<commit_before>//! Convert sdf files to other formats.

use std::iter::repeat;
use std::path::Path;

use peakbag::{PeakDetector, Peak};
use sdc;

use error::SdfError;
use file::{Block, Channel, File, FileInfo, Record};
use result::Result;

const HIGH_WIDTH: usize = 2;
const HIGH_FLOOR: u16 = 15;
const HIGH_CEILING: u16 = 255;
const LOW_WIDTHS: (usize, usize) = (3, 2);
const LOW_FLOOR: u16 = 15;
const LOW_CEILINGS: (u16, u16) = (250, 255); // heh
const MIN_HEIGHT_ABOVE_BACKGROUND: f64 = 5.0;
const MAX_KURTOSIS: f64 = 0.04;

/// Turns a single sdf record into zero or more `Point`s.
///
/// At this point, we assume that the timestamps are absolute. TODO make this smarter to handle the
/// case when the user has called `File::set_sosbl_mode(SosblMode::Relative)`.
///
/// # Panics
///
/// Panics if there are zero or more than one reference blocks in the record.
///
/// # Examples
///
/// ```
/// use sdf::convert::discretize;
/// use sdf::file::File;
/// let mut file = File::open("data/110630_174316.sdf").unwrap();
/// let ref file_info = file.info().unwrap();
/// file.reindex().unwrap();
/// let ref record = file.read().unwrap();
/// let points = discretize(record, file_info).unwrap();
/// ```
pub fn discretize(record: &Record, file_info: &FileInfo) -> Result<Vec<Point>> {
    let mut high_blocks = Vec::new();
    let mut low_blocks = Vec::new();
    let mut reference_block = None;
    for block in &record.blocks {
        match block.channel {
            Channel::High => high_blocks.push(block),
            Channel::Low => low_blocks.push(block),
            Channel::Reference => {
                if reference_block.is_some() {
                    panic!("More than one reference block in this record");
                } else {
                    reference_block = Some(block);
                }
            }
            _ => {}
        }
    }
    let reference_block = reference_block.unwrap();
    let high_detector = PeakDetector::new(HIGH_WIDTH, HIGH_FLOOR, HIGH_CEILING)
                            .min_height_above_background(MIN_HEIGHT_ABOVE_BACKGROUND)
                            .max_kurtosis(MAX_KURTOSIS);
    let (low_width, low_ceiling) = match high_blocks.len() {
        0 => (LOW_WIDTHS.0, LOW_CEILINGS.0),
        _ => (LOW_WIDTHS.1, LOW_CEILINGS.1),
    };
    let low_detector = PeakDetector::new(low_width, LOW_FLOOR, low_ceiling)
                           .min_height_above_background(MIN_HEIGHT_ABOVE_BACKGROUND)
                           .max_kurtosis(MAX_KURTOSIS)
                           .saturation(LOW_CEILINGS.1);
    let reference_detector = high_detector;

    let reference_peaks = reference_detector.detect_peaks(&reference_block.samples[..]);
    if reference_peaks.len() != 1 {
        return Err(SdfError::NeedSingleReferencePeak(reference_peaks.len()));
    }
    let ref reference_peak = reference_peaks[0];
    let t_ref = timestamp(reference_peak, &reference_block, file_info);

    let mut points = Vec::new();
    for (block, detector) in low_blocks.iter()
                                       .zip(repeat(low_detector))
                                       .chain(high_blocks.iter().zip(repeat(high_detector))) {
        let peaks = detector.detect_peaks(&block.samples[..]);
        for peak in peaks {
            let time = timestamp(&peak, block, file_info);
            let range = file_info.v_group / 2.0 * (time - t_ref);
            // x is straight out of the scanner, and the mirror pans it along the
            // z axis.
            let theta = (record.direction[2] / record.direction[0])
                            .atan()
                            .to_degrees();
            let point = Point {
                time: time,
                range: range as f32,
                theta: theta as f32,
                x: (record.origin[0] + record.direction[0] * range) as f32,
                y: (record.origin[1] + record.direction[1] * range) as f32,
                z: (record.origin[2] + record.direction[2] * range) as f32,
                peak: peak,
                high_channel: block.channel == Channel::High,
            };
            points.push(point);
        }
    }

    Ok(points)
}

fn timestamp(peak: &Peak<u16>, block: &Block, file_info: &FileInfo) -> f64 {
    block.time_sosbl + peak.index as f64 * file_info.sampling_time
}

/// A 3D point in the scanner's own coordiante frame.
#[derive(Clone, Copy, Debug)]
pub struct Point {
    time: f64,
    range: f32,
    theta: f32,
    x: f32,
    y: f32,
    z: f32,
    peak: Peak<u16>,
    high_channel: bool,
}

impl File {
    /// Writes all points from an .sdf file to an .sdc file.
    ///
    /// # Example
    ///
    /// ```no_run
    /// use sdf::file::File;
    /// File::convert("110630_174316.sdf", "110630_174316.sdc").unwrap();
    /// ```
    pub fn convert<T: Into<Vec<u8>>, P: AsRef<Path>>(sdf_path: T, sdc_path: P) -> Result<()> {
        let mut sdf_file = try!(File::open(sdf_path));
        let ref file_info = try!(sdf_file.info());
        let mut sdc_file = try!(sdc::File::create(sdc_path));
        for (i, record) in sdf_file.into_iter().enumerate() {
            let points = match discretize(&record, file_info) {
                Ok(points) => points,
                Err(SdfError::NeedSingleReferencePeak(_)) => {
                    warn!("No reference peak detected for pulse {}, skipping", i);
                    continue;
                }
                Err(err) => return Err(err),
            };
            for (i, p) in points.iter().enumerate() {
                let ref point = sdc::Point {
                    time: p.time,
                    range: p.range,
                    theta: p.theta,
                    x: p.x,
                    y: p.y,
                    z: p.z,
                    amplitude: p.peak.amplitude,
                    // FIXME actually calculate this value
                    width: 1,
                    target_type: sdc::TargetType::Peak,
                    // Riegl one-indexes its target counts. Bah.
                    target: (i + 1) as u8,
                    num_target: points.len() as u8,
                    // FIXME I have no idea what this means
                    rg_index: 1,
                    facet_number: record.facet as u8,
                    high_channel: p.high_channel,
                };
                try!(sdc_file.write_point(point));
            }
        }
        Ok(())
    }
}

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

    use file::File;

    #[test]
    fn first_point() {
        let mut file = File::open("data/110630_174316.sdf").unwrap();
        file.reindex().unwrap();
        let ref file_info = file.info().unwrap();
        let ref record = file.read().unwrap();
        let points = discretize(record, file_info).unwrap();
        assert_eq!(4, points.len());
    }
}
<commit_msg>Add debug line for missing reference peaks<commit_after>//! Convert sdf files to other formats.

use std::iter::repeat;
use std::path::Path;

use peakbag::{PeakDetector, Peak};
use sdc;

use error::SdfError;
use file::{Block, Channel, File, FileInfo, Record};
use result::Result;

const HIGH_WIDTH: usize = 2;
const HIGH_FLOOR: u16 = 15;
const HIGH_CEILING: u16 = 255;
const LOW_WIDTHS: (usize, usize) = (3, 2);
const LOW_FLOOR: u16 = 15;
const LOW_CEILINGS: (u16, u16) = (250, 255); // heh
const MIN_HEIGHT_ABOVE_BACKGROUND: f64 = 5.0;
const MAX_KURTOSIS: f64 = 0.04;

/// Turns a single sdf record into zero or more `Point`s.
///
/// At this point, we assume that the timestamps are absolute. TODO make this smarter to handle the
/// case when the user has called `File::set_sosbl_mode(SosblMode::Relative)`.
///
/// # Panics
///
/// Panics if there are zero or more than one reference blocks in the record.
///
/// # Examples
///
/// ```
/// use sdf::convert::discretize;
/// use sdf::file::File;
/// let mut file = File::open("data/110630_174316.sdf").unwrap();
/// let ref file_info = file.info().unwrap();
/// file.reindex().unwrap();
/// let ref record = file.read().unwrap();
/// let points = discretize(record, file_info).unwrap();
/// ```
pub fn discretize(record: &Record, file_info: &FileInfo) -> Result<Vec<Point>> {
    let mut high_blocks = Vec::new();
    let mut low_blocks = Vec::new();
    let mut reference_block = None;
    for block in &record.blocks {
        match block.channel {
            Channel::High => high_blocks.push(block),
            Channel::Low => low_blocks.push(block),
            Channel::Reference => {
                if reference_block.is_some() {
                    panic!("More than one reference block in this record");
                } else {
                    reference_block = Some(block);
                }
            }
            _ => {}
        }
    }
    let reference_block = reference_block.unwrap();
    let high_detector = PeakDetector::new(HIGH_WIDTH, HIGH_FLOOR, HIGH_CEILING)
                            .min_height_above_background(MIN_HEIGHT_ABOVE_BACKGROUND)
                            .max_kurtosis(MAX_KURTOSIS);
    let (low_width, low_ceiling) = match high_blocks.len() {
        0 => (LOW_WIDTHS.0, LOW_CEILINGS.0),
        _ => (LOW_WIDTHS.1, LOW_CEILINGS.1),
    };
    let low_detector = PeakDetector::new(low_width, LOW_FLOOR, low_ceiling)
                           .min_height_above_background(MIN_HEIGHT_ABOVE_BACKGROUND)
                           .max_kurtosis(MAX_KURTOSIS)
                           .saturation(LOW_CEILINGS.1);
    let reference_detector = high_detector;

    let reference_peaks = reference_detector.detect_peaks(&reference_block.samples[..]);
    if reference_peaks.len() != 1 {
        debug!("Could not get a single reference peak out of: {:?}", reference_block.samples);
        return Err(SdfError::NeedSingleReferencePeak(reference_peaks.len()));
    }
    let ref reference_peak = reference_peaks[0];
    let t_ref = timestamp(reference_peak, &reference_block, file_info);

    let mut points = Vec::new();
    for (block, detector) in low_blocks.iter()
                                       .zip(repeat(low_detector))
                                       .chain(high_blocks.iter().zip(repeat(high_detector))) {
        let peaks = detector.detect_peaks(&block.samples[..]);
        for peak in peaks {
            let time = timestamp(&peak, block, file_info);
            let range = file_info.v_group / 2.0 * (time - t_ref);
            // x is straight out of the scanner, and the mirror pans it along the
            // z axis.
            let theta = (record.direction[2] / record.direction[0])
                            .atan()
                            .to_degrees();
            let point = Point {
                time: time,
                range: range as f32,
                theta: theta as f32,
                x: (record.origin[0] + record.direction[0] * range) as f32,
                y: (record.origin[1] + record.direction[1] * range) as f32,
                z: (record.origin[2] + record.direction[2] * range) as f32,
                peak: peak,
                high_channel: block.channel == Channel::High,
            };
            points.push(point);
        }
    }

    Ok(points)
}

fn timestamp(peak: &Peak<u16>, block: &Block, file_info: &FileInfo) -> f64 {
    block.time_sosbl + peak.index as f64 * file_info.sampling_time
}

/// A 3D point in the scanner's own coordiante frame.
#[derive(Clone, Copy, Debug)]
pub struct Point {
    time: f64,
    range: f32,
    theta: f32,
    x: f32,
    y: f32,
    z: f32,
    peak: Peak<u16>,
    high_channel: bool,
}

impl File {
    /// Writes all points from an .sdf file to an .sdc file.
    ///
    /// # Example
    ///
    /// ```no_run
    /// use sdf::file::File;
    /// File::convert("110630_174316.sdf", "110630_174316.sdc").unwrap();
    /// ```
    pub fn convert<T: Into<Vec<u8>>, P: AsRef<Path>>(sdf_path: T, sdc_path: P) -> Result<()> {
        let mut sdf_file = try!(File::open(sdf_path));
        let ref file_info = try!(sdf_file.info());
        let mut sdc_file = try!(sdc::File::create(sdc_path));
        for (i, record) in sdf_file.into_iter().enumerate() {
            let points = match discretize(&record, file_info) {
                Ok(points) => points,
                Err(SdfError::NeedSingleReferencePeak(_)) => {
                    warn!("No reference peak detected for pulse {}, skipping", i);
                    continue;
                }
                Err(err) => return Err(err),
            };
            for (i, p) in points.iter().enumerate() {
                let ref point = sdc::Point {
                    time: p.time,
                    range: p.range,
                    theta: p.theta,
                    x: p.x,
                    y: p.y,
                    z: p.z,
                    amplitude: p.peak.amplitude,
                    // FIXME actually calculate this value
                    width: 1,
                    target_type: sdc::TargetType::Peak,
                    // Riegl one-indexes its target counts. Bah.
                    target: (i + 1) as u8,
                    num_target: points.len() as u8,
                    // FIXME I have no idea what this means
                    rg_index: 1,
                    facet_number: record.facet as u8,
                    high_channel: p.high_channel,
                };
                try!(sdc_file.write_point(point));
            }
        }
        Ok(())
    }
}

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

    use file::File;

    #[test]
    fn first_point() {
        let mut file = File::open("data/110630_174316.sdf").unwrap();
        file.reindex().unwrap();
        let ref file_info = file.info().unwrap();
        let ref record = file.read().unwrap();
        let points = discretize(record, file_info).unwrap();
        assert_eq!(4, points.len());
    }
}
<|endoftext|>


<commit_before>use super::item::TokenSet;
use super::token_conflicts::TokenConflictMap;
use crate::generate::grammars::{SyntaxGrammar, VariableType};
use crate::generate::rules::{AliasMap, Symbol};
use crate::generate::tables::{ParseAction, ParseState, ParseTable, ParseTableEntry};
use hashbrown::{HashMap, HashSet};

pub(crate) fn minimize_parse_table(
    parse_table: &mut ParseTable,
    syntax_grammar: &SyntaxGrammar,
    simple_aliases: &AliasMap,
    token_conflict_map: &TokenConflictMap,
    keywords: &TokenSet,
) {
    let mut minimizer = Minimizer {
        parse_table,
        syntax_grammar,
        token_conflict_map,
        keywords,
        simple_aliases,
    };
    minimizer.remove_unit_reductions();
    minimizer.merge_compatible_states();
    minimizer.remove_unused_states();
}

struct Minimizer<'a> {
    parse_table: &'a mut ParseTable,
    syntax_grammar: &'a SyntaxGrammar,
    token_conflict_map: &'a TokenConflictMap<'a>,
    keywords: &'a TokenSet,
    simple_aliases: &'a AliasMap,
}

impl<'a> Minimizer<'a> {
    fn remove_unit_reductions(&mut self) {
        let mut aliased_symbols = HashSet::new();
        for variable in &self.syntax_grammar.variables {
            for production in &variable.productions {
                for step in &production.steps {
                    if step.alias.is_some() {
                        aliased_symbols.insert(step.symbol);
                    }
                }
            }
        }

        let mut unit_reduction_symbols_by_state = HashMap::new();
        for (i, state) in self.parse_table.states.iter().enumerate() {
            let mut only_unit_reductions = true;
            let mut unit_reduction_symbol = None;
            for (_, entry) in &state.terminal_entries {
                for action in &entry.actions {
                    match action {
                        ParseAction::ShiftExtra => continue,
                        ParseAction::Reduce {
                            child_count: 1,
                            alias_sequence_id: 0,
                            symbol,
                            ..
                        } => {
                            if !self.simple_aliases.contains_key(&symbol)
                                && !aliased_symbols.contains(&symbol)
                                && self.syntax_grammar.variables[symbol.index].kind
                                    != VariableType::Named
                                && (unit_reduction_symbol.is_none()
                                    || unit_reduction_symbol == Some(symbol))
                            {
                                unit_reduction_symbol = Some(symbol);
                                continue;
                            }
                        }
                        _ => {}
                    }
                    only_unit_reductions = false;
                    break;
                }

                if !only_unit_reductions {
                    break;
                }
            }

            if let Some(symbol) = unit_reduction_symbol {
                if only_unit_reductions {
                    unit_reduction_symbols_by_state.insert(i, *symbol);
                }
            }
        }

        for state in self.parse_table.states.iter_mut() {
            let mut done = false;
            while !done {
                done = true;
                state.update_referenced_states(|other_state_id, state| {
                    if let Some(symbol) = unit_reduction_symbols_by_state.get(&other_state_id) {
                        done = false;
                        state.nonterminal_entries[symbol]
                    } else {
                        other_state_id
                    }
                })
            }
        }
    }

    fn merge_compatible_states(&mut self) {
        let mut state_ids_by_signature = HashMap::new();
        for (i, state) in self.parse_table.states.iter().enumerate() {
            state_ids_by_signature
                .entry(state.unfinished_item_signature)
                .or_insert(Vec::new())
                .push(i);
        }

        let mut deleted_states = HashSet::new();
        loop {
            let mut state_replacements = HashMap::new();
            for (_, state_ids) in &state_ids_by_signature {
                for i in state_ids {
                    for j in state_ids {
                        if j == i {
                            break;
                        }
                        if deleted_states.contains(j) || deleted_states.contains(i) {
                            continue;
                        }
                        if self.merge_parse_state(*j, *i) {
                            deleted_states.insert(*i);
                            state_replacements.insert(*i, *j);
                        }
                    }
                }
            }

            if state_replacements.is_empty() {
                break;
            }

            for state in self.parse_table.states.iter_mut() {
                state.update_referenced_states(|other_state_id, _| {
                    *state_replacements
                        .get(&other_state_id)
                        .unwrap_or(&other_state_id)
                });
            }
        }
    }

    fn merge_parse_state(&mut self, left: usize, right: usize) -> bool {
        let left_state = &self.parse_table.states[left];
        let right_state = &self.parse_table.states[right];

        if left_state.nonterminal_entries != right_state.nonterminal_entries {
            return false;
        }

        for (symbol, left_entry) in &left_state.terminal_entries {
            if let Some(right_entry) = right_state.terminal_entries.get(symbol) {
                if right_entry.actions != left_entry.actions {
                    return false;
                }
            } else if !self.can_add_entry_to_state(right_state, *symbol, left_entry) {
                return false;
            }
        }

        let mut symbols_to_add = Vec::new();
        for (symbol, right_entry) in &right_state.terminal_entries {
            if !left_state.terminal_entries.contains_key(&symbol) {
                if !self.can_add_entry_to_state(left_state, *symbol, right_entry) {
                    return false;
                }
                symbols_to_add.push(*symbol);
            }
        }

        for symbol in symbols_to_add {
            let entry = self.parse_table.states[right].terminal_entries[&symbol].clone();
            self.parse_table.states[left]
                .terminal_entries
                .insert(symbol, entry);
        }

        true
    }

    fn can_add_entry_to_state(
        &self,
        state: &ParseState,
        token: Symbol,
        entry: &ParseTableEntry,
    ) -> bool {
        // Do not add external tokens; they could conflict lexically with any of the state's
        // existing lookahead tokens.
        if token.is_external() {
            return false;
        }

        // Only merge_compatible_states parse states by allowing existing reductions to happen
        // with additional lookahead tokens. Do not alter parse states in ways
        // that allow entirely new types of actions to happen.
        if state.terminal_entries.iter().all(|(_, e)| e != entry) {
            return false;
        }
        match entry.actions.last() {
            Some(ParseAction::Reduce { .. }) => {}
            _ => return false,
        }

        // Do not add tokens which are both internal and external. Their validity could
        // influence the behavior of the external scanner.
        if self
            .syntax_grammar
            .external_tokens
            .iter()
            .any(|t| t.corresponding_internal_token == Some(token))
        {
            return false;
        }

        let is_word_token = self.syntax_grammar.word_token == Some(token);
        let is_keyword = self.keywords.contains(&token);

        // Do not add a token if it conflicts with an existing token.
        if token.is_terminal() {
            for existing_token in state.terminal_entries.keys() {
                if (is_word_token && self.keywords.contains(existing_token))
                    || is_keyword && self.syntax_grammar.word_token.as_ref() == Some(existing_token)
                {
                    continue;
                }
                if self
                    .token_conflict_map
                    .does_conflict(token.index, existing_token.index)
                    || self
                        .token_conflict_map
                        .does_match_same_string(token.index, existing_token.index)
                {
                    return false;
                }
            }
        }

        true
    }

    fn remove_unused_states(&mut self) {
        let mut state_usage_map = vec![false; self.parse_table.states.len()];

        state_usage_map[0] = true;
        state_usage_map[1] = true;

        for state in &self.parse_table.states {
            for referenced_state in state.referenced_states() {
                state_usage_map[referenced_state] = true;
            }
        }
        let mut removed_predecessor_count = 0;
        let mut state_replacement_map = vec![0; self.parse_table.states.len()];
        for state_id in 0..self.parse_table.states.len() {
            state_replacement_map[state_id] = state_id - removed_predecessor_count;
            if !state_usage_map[state_id] {
                removed_predecessor_count += 1;
            }
        }
        let mut state_id = 0;
        let mut original_state_id = 0;
        while state_id < self.parse_table.states.len() {
            if state_usage_map[original_state_id] {
                self.parse_table.states[state_id].update_referenced_states(|other_state_id, _| {
                    state_replacement_map[other_state_id]
                });
                state_id += 1;
            } else {
                self.parse_table.states.remove(state_id);
            }
            original_state_id += 1;
        }
    }
}
<commit_msg>Add logging when deciding not to merge parse states<commit_after>use super::item::TokenSet;
use super::token_conflicts::TokenConflictMap;
use crate::generate::grammars::{LexicalGrammar, SyntaxGrammar, VariableType};
use crate::generate::rules::{AliasMap, Symbol};
use crate::generate::tables::{ParseAction, ParseState, ParseTable, ParseTableEntry};
use hashbrown::{HashMap, HashSet};

pub(crate) fn minimize_parse_table(
    parse_table: &mut ParseTable,
    syntax_grammar: &SyntaxGrammar,
    lexical_grammar: &LexicalGrammar,
    simple_aliases: &AliasMap,
    token_conflict_map: &TokenConflictMap,
    keywords: &TokenSet,
) {
    let mut minimizer = Minimizer {
        parse_table,
        syntax_grammar,
        lexical_grammar,
        token_conflict_map,
        keywords,
        simple_aliases,
    };
    minimizer.remove_unit_reductions();
    minimizer.merge_compatible_states();
    minimizer.remove_unused_states();
}

struct Minimizer<'a> {
    parse_table: &'a mut ParseTable,
    syntax_grammar: &'a SyntaxGrammar,
    lexical_grammar: &'a LexicalGrammar,
    token_conflict_map: &'a TokenConflictMap<'a>,
    keywords: &'a TokenSet,
    simple_aliases: &'a AliasMap,
}

impl<'a> Minimizer<'a> {
    fn remove_unit_reductions(&mut self) {
        let mut aliased_symbols = HashSet::new();
        for variable in &self.syntax_grammar.variables {
            for production in &variable.productions {
                for step in &production.steps {
                    if step.alias.is_some() {
                        aliased_symbols.insert(step.symbol);
                    }
                }
            }
        }

        let mut unit_reduction_symbols_by_state = HashMap::new();
        for (i, state) in self.parse_table.states.iter().enumerate() {
            let mut only_unit_reductions = true;
            let mut unit_reduction_symbol = None;
            for (_, entry) in &state.terminal_entries {
                for action in &entry.actions {
                    match action {
                        ParseAction::ShiftExtra => continue,
                        ParseAction::Reduce {
                            child_count: 1,
                            alias_sequence_id: 0,
                            symbol,
                            ..
                        } => {
                            if !self.simple_aliases.contains_key(&symbol)
                                && !aliased_symbols.contains(&symbol)
                                && self.syntax_grammar.variables[symbol.index].kind
                                    != VariableType::Named
                                && (unit_reduction_symbol.is_none()
                                    || unit_reduction_symbol == Some(symbol))
                            {
                                unit_reduction_symbol = Some(symbol);
                                continue;
                            }
                        }
                        _ => {}
                    }
                    only_unit_reductions = false;
                    break;
                }

                if !only_unit_reductions {
                    break;
                }
            }

            if let Some(symbol) = unit_reduction_symbol {
                if only_unit_reductions {
                    unit_reduction_symbols_by_state.insert(i, *symbol);
                }
            }
        }

        for state in self.parse_table.states.iter_mut() {
            let mut done = false;
            while !done {
                done = true;
                state.update_referenced_states(|other_state_id, state| {
                    if let Some(symbol) = unit_reduction_symbols_by_state.get(&other_state_id) {
                        done = false;
                        state.nonterminal_entries[symbol]
                    } else {
                        other_state_id
                    }
                })
            }
        }
    }

    fn merge_compatible_states(&mut self) {
        let mut state_ids_by_signature = HashMap::new();
        for (i, state) in self.parse_table.states.iter().enumerate() {
            state_ids_by_signature
                .entry(state.unfinished_item_signature)
                .or_insert(Vec::new())
                .push(i);
        }

        let mut deleted_states = HashSet::new();
        loop {
            let mut state_replacements = HashMap::new();
            for (_, state_ids) in &state_ids_by_signature {
                for i in state_ids {
                    for j in state_ids {
                        if j == i {
                            break;
                        }
                        if deleted_states.contains(j) || deleted_states.contains(i) {
                            continue;
                        }
                        if self.merge_parse_state(*j, *i) {
                            deleted_states.insert(*i);
                            state_replacements.insert(*i, *j);
                        }
                    }
                }
            }

            if state_replacements.is_empty() {
                break;
            }

            for state in self.parse_table.states.iter_mut() {
                state.update_referenced_states(|other_state_id, _| {
                    *state_replacements
                        .get(&other_state_id)
                        .unwrap_or(&other_state_id)
                });
            }
        }
    }

    fn merge_parse_state(&mut self, left: usize, right: usize) -> bool {
        let left_state = &self.parse_table.states[left];
        let right_state = &self.parse_table.states[right];

        if left_state.nonterminal_entries != right_state.nonterminal_entries {
            return false;
        }

        for (symbol, left_entry) in &left_state.terminal_entries {
            if let Some(right_entry) = right_state.terminal_entries.get(symbol) {
                if right_entry.actions != left_entry.actions {
                    return false;
                }
            } else if !self.can_add_entry_to_state(right_state, *symbol, left_entry) {
                return false;
            }
        }

        let mut symbols_to_add = Vec::new();
        for (symbol, right_entry) in &right_state.terminal_entries {
            if !left_state.terminal_entries.contains_key(&symbol) {
                if !self.can_add_entry_to_state(left_state, *symbol, right_entry) {
                    return false;
                }
                symbols_to_add.push(*symbol);
            }
        }

        for symbol in symbols_to_add {
            let entry = self.parse_table.states[right].terminal_entries[&symbol].clone();
            self.parse_table.states[left]
                .terminal_entries
                .insert(symbol, entry);
        }

        true
    }

    fn can_add_entry_to_state(
        &self,
        state: &ParseState,
        token: Symbol,
        entry: &ParseTableEntry,
    ) -> bool {
        // Do not add external tokens; they could conflict lexically with any of the state's
        // existing lookahead tokens.
        if token.is_external() {
            return false;
        }

        // Only merge_compatible_states parse states by allowing existing reductions to happen
        // with additional lookahead tokens. Do not alter parse states in ways
        // that allow entirely new types of actions to happen.
        if state.terminal_entries.iter().all(|(_, e)| e != entry) {
            return false;
        }
        match entry.actions.last() {
            Some(ParseAction::Reduce { .. }) => {}
            _ => return false,
        }

        // Do not add tokens which are both internal and external. Their validity could
        // influence the behavior of the external scanner.
        if self
            .syntax_grammar
            .external_tokens
            .iter()
            .any(|t| t.corresponding_internal_token == Some(token))
        {
            return false;
        }

        let is_word_token = self.syntax_grammar.word_token == Some(token);
        let is_keyword = self.keywords.contains(&token);

        // Do not add a token if it conflicts with an existing token.
        if token.is_terminal() {
            for existing_token in state.terminal_entries.keys() {
                if (is_word_token && self.keywords.contains(existing_token))
                    || is_keyword && self.syntax_grammar.word_token.as_ref() == Some(existing_token)
                {
                    continue;
                }
                if self
                    .token_conflict_map
                    .does_conflict(token.index, existing_token.index)
                    || self
                        .token_conflict_map
                        .does_match_same_string(token.index, existing_token.index)
                {
                    info!(
                        "can't merge parse states because of conflict between {} and {}",
                        self.lexical_grammar.variables[token.index].name,
                        self.lexical_grammar.variables[existing_token.index].name
                    );
                    return false;
                }
            }
        }

        true
    }

    fn remove_unused_states(&mut self) {
        let mut state_usage_map = vec![false; self.parse_table.states.len()];

        state_usage_map[0] = true;
        state_usage_map[1] = true;

        for state in &self.parse_table.states {
            for referenced_state in state.referenced_states() {
                state_usage_map[referenced_state] = true;
            }
        }
        let mut removed_predecessor_count = 0;
        let mut state_replacement_map = vec![0; self.parse_table.states.len()];
        for state_id in 0..self.parse_table.states.len() {
            state_replacement_map[state_id] = state_id - removed_predecessor_count;
            if !state_usage_map[state_id] {
                removed_predecessor_count += 1;
            }
        }
        let mut state_id = 0;
        let mut original_state_id = 0;
        while state_id < self.parse_table.states.len() {
            if state_usage_map[original_state_id] {
                self.parse_table.states[state_id].update_referenced_states(|other_state_id, _| {
                    state_replacement_map[other_state_id]
                });
                state_id += 1;
            } else {
                self.parse_table.states.remove(state_id);
            }
            original_state_id += 1;
        }
    }
}
<|endoftext|>


<commit_before>pub mod dummy;
pub mod full;
pub mod stack_trace;

use super::{heap::Pointer, ChannelId, FiberId, Heap};
use crate::{compiler::hir::Id, module::Module};

/// An event that happened inside a VM.
#[derive(Clone)]
pub enum VmEvent<'event> {
    FiberCreated {
        fiber: FiberId,
    },
    FiberDone {
        fiber: FiberId,
    },
    FiberPanicked {
        fiber: FiberId,
        panicked_child: Option<FiberId>,
    },
    FiberCanceled {
        fiber: FiberId,
    },
    FiberExecutionStarted {
        fiber: FiberId,
    },
    FiberExecutionEnded {
        fiber: FiberId,
    },
    ChannelCreated {
        channel: ChannelId,
    },
    InFiber {
        fiber: FiberId,
        event: FiberEvent<'event>,
    },
}

/// An event that happened inside a fiber.
#[derive(Clone)]
pub enum FiberEvent<'event> {
    ModuleStarted {
        module: Module,
    },
    ModuleEnded {
        export_map: Pointer,
        heap: &'event Heap,
    },
    ValueEvaluated {
        id: Id,
        value: Pointer,
        heap: &'event Heap,
    },
    FoundFuzzableClosure {
        id: Id,
        closure: Pointer,
        heap: &'event Heap,
    },
    CallStarted {
        id: Id,
        closure: Pointer,
        args: Vec<Pointer>,
        heap: &'event Heap,
    },
    CallEnded {
        return_value: Pointer,
        heap: &'event Heap,
    },
    NeedsStarted {
        id: Id,
        condition: Pointer,
        reason: Pointer,
        heap: &'event Heap,
    },
    NeedsEnded,
}

pub trait Tracer {
    fn add(&mut self, event: VmEvent);

    fn fiber_created(&mut self, fiber: FiberId) {
        self.add(VmEvent::FiberCreated { fiber });
    }
    fn fiber_done(&mut self, fiber: FiberId) {
        self.add(VmEvent::FiberDone { fiber });
    }
    fn fiber_panicked(&mut self, fiber: FiberId, panicked_child: Option<FiberId>) {
        self.add(VmEvent::FiberPanicked {
            fiber,
            panicked_child,
        });
    }
    fn fiber_canceled(&mut self, fiber: FiberId) {
        self.add(VmEvent::FiberCanceled { fiber });
    }
    fn fiber_execution_started(&mut self, fiber: FiberId) {
        self.add(VmEvent::FiberExecutionStarted { fiber });
    }
    fn fiber_execution_ended(&mut self, fiber: FiberId) {
        self.add(VmEvent::FiberExecutionEnded { fiber });
    }
    fn channel_created(&mut self, channel: ChannelId) {
        self.add(VmEvent::ChannelCreated { channel });
    }

    // fn in_fiber_tracer<'a>(&'a mut self, fiber: FiberId) -> Box<dyn InFiberTracer<'a> + 'a>
    // where
    //     Self: 'a,
    // {
    //     Box::new(FullInFiberTracer {
    //         tracer: self,
    //         fiber,
    //     })
    // }

    fn for_fiber<'a, 'fiber>(&'a mut self, fiber: FiberId) -> FiberTracer<'fiber>
    where
        Self: Sized,
        'a: 'fiber,
    {
        FiberTracer::<'fiber> {
            tracer: self,
            fiber,
        }
    }
}
pub struct FiberTracer<'fiber> {
    tracer: &'fiber mut dyn Tracer,
    fiber: FiberId,
}
impl<'fiber> FiberTracer<'fiber> {
    fn add(&mut self, event: FiberEvent) {
        self.tracer.add(VmEvent::InFiber {
            fiber: self.fiber,
            event,
        });
    }

    pub fn module_started(&mut self, module: Module) {
        self.add(FiberEvent::ModuleStarted { module });
    }
    pub fn module_ended(&mut self, export_map: Pointer, heap: &Heap) {
        self.add(FiberEvent::ModuleEnded { export_map, heap });
    }
    pub fn value_evaluated(&mut self, id: Id, value: Pointer, heap: &Heap) {
        self.add(FiberEvent::ValueEvaluated { id, value, heap });
    }
    pub fn found_fuzzable_closure(&mut self, id: Id, closure: Pointer, heap: &Heap) {
        self.add(FiberEvent::FoundFuzzableClosure { id, closure, heap });
    }
    pub fn call_started(&mut self, id: Id, closure: Pointer, args: Vec<Pointer>, heap: &Heap) {
        self.add(FiberEvent::CallStarted {
            id,
            closure,
            args,
            heap,
        });
    }
    pub fn call_ended(&mut self, return_value: Pointer, heap: &Heap) {
        self.add(FiberEvent::CallEnded { return_value, heap });
    }
    pub fn needs_started(&mut self, id: Id, condition: Pointer, reason: Pointer, heap: &Heap) {
        self.add(FiberEvent::NeedsStarted {
            id,
            condition,
            reason,
            heap,
        });
    }
    pub fn needs_ended(&mut self) {
        self.add(FiberEvent::NeedsEnded);
    }
}
<commit_msg>Remove commented out code<commit_after>pub mod dummy;
pub mod full;
pub mod stack_trace;

use super::{heap::Pointer, ChannelId, FiberId, Heap};
use crate::{compiler::hir::Id, module::Module};

/// An event that happened inside a VM.
#[derive(Clone)]
pub enum VmEvent<'event> {
    FiberCreated {
        fiber: FiberId,
    },
    FiberDone {
        fiber: FiberId,
    },
    FiberPanicked {
        fiber: FiberId,
        panicked_child: Option<FiberId>,
    },
    FiberCanceled {
        fiber: FiberId,
    },
    FiberExecutionStarted {
        fiber: FiberId,
    },
    FiberExecutionEnded {
        fiber: FiberId,
    },
    ChannelCreated {
        channel: ChannelId,
    },
    InFiber {
        fiber: FiberId,
        event: FiberEvent<'event>,
    },
}

/// An event that happened inside a fiber.
#[derive(Clone)]
pub enum FiberEvent<'event> {
    ModuleStarted {
        module: Module,
    },
    ModuleEnded {
        export_map: Pointer,
        heap: &'event Heap,
    },
    ValueEvaluated {
        id: Id,
        value: Pointer,
        heap: &'event Heap,
    },
    FoundFuzzableClosure {
        id: Id,
        closure: Pointer,
        heap: &'event Heap,
    },
    CallStarted {
        id: Id,
        closure: Pointer,
        args: Vec<Pointer>,
        heap: &'event Heap,
    },
    CallEnded {
        return_value: Pointer,
        heap: &'event Heap,
    },
    NeedsStarted {
        id: Id,
        condition: Pointer,
        reason: Pointer,
        heap: &'event Heap,
    },
    NeedsEnded,
}

pub trait Tracer {
    fn add(&mut self, event: VmEvent);

    fn fiber_created(&mut self, fiber: FiberId) {
        self.add(VmEvent::FiberCreated { fiber });
    }
    fn fiber_done(&mut self, fiber: FiberId) {
        self.add(VmEvent::FiberDone { fiber });
    }
    fn fiber_panicked(&mut self, fiber: FiberId, panicked_child: Option<FiberId>) {
        self.add(VmEvent::FiberPanicked {
            fiber,
            panicked_child,
        });
    }
    fn fiber_canceled(&mut self, fiber: FiberId) {
        self.add(VmEvent::FiberCanceled { fiber });
    }
    fn fiber_execution_started(&mut self, fiber: FiberId) {
        self.add(VmEvent::FiberExecutionStarted { fiber });
    }
    fn fiber_execution_ended(&mut self, fiber: FiberId) {
        self.add(VmEvent::FiberExecutionEnded { fiber });
    }
    fn channel_created(&mut self, channel: ChannelId) {
        self.add(VmEvent::ChannelCreated { channel });
    }

    fn for_fiber<'a, 'fiber>(&'a mut self, fiber: FiberId) -> FiberTracer<'fiber>
    where
        Self: Sized,
        'a: 'fiber,
    {
        FiberTracer::<'fiber> {
            tracer: self,
            fiber,
        }
    }
}
pub struct FiberTracer<'fiber> {
    tracer: &'fiber mut dyn Tracer,
    fiber: FiberId,
}
impl<'fiber> FiberTracer<'fiber> {
    fn add(&mut self, event: FiberEvent) {
        self.tracer.add(VmEvent::InFiber {
            fiber: self.fiber,
            event,
        });
    }

    pub fn module_started(&mut self, module: Module) {
        self.add(FiberEvent::ModuleStarted { module });
    }
    pub fn module_ended(&mut self, export_map: Pointer, heap: &Heap) {
        self.add(FiberEvent::ModuleEnded { export_map, heap });
    }
    pub fn value_evaluated(&mut self, id: Id, value: Pointer, heap: &Heap) {
        self.add(FiberEvent::ValueEvaluated { id, value, heap });
    }
    pub fn found_fuzzable_closure(&mut self, id: Id, closure: Pointer, heap: &Heap) {
        self.add(FiberEvent::FoundFuzzableClosure { id, closure, heap });
    }
    pub fn call_started(&mut self, id: Id, closure: Pointer, args: Vec<Pointer>, heap: &Heap) {
        self.add(FiberEvent::CallStarted {
            id,
            closure,
            args,
            heap,
        });
    }
    pub fn call_ended(&mut self, return_value: Pointer, heap: &Heap) {
        self.add(FiberEvent::CallEnded { return_value, heap });
    }
    pub fn needs_started(&mut self, id: Id, condition: Pointer, reason: Pointer, heap: &Heap) {
        self.add(FiberEvent::NeedsStarted {
            id,
            condition,
            reason,
            heap,
        });
    }
    pub fn needs_ended(&mut self) {
        self.add(FiberEvent::NeedsEnded);
    }
}
<|endoftext|>


<commit_before>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use anyhow::Result;
use opentitanlib::test_utils::status::Status;
use opentitanlib::with_unknown;
use std::io::{Read, Write};
use std::process::{Command, Stdio};

mod example {
    // Bring in the auto-generated sources.
    include!(env!("example"));
}

with_unknown! {
    enum FuzzyBool: u32 {
        False = 0,
        True = 100,
    }
}

fn roundtrip(name: &str, data: &str) -> Result<String> {
    let mut command = Command::new(&std::env::var("ROUNDTRIP_CLIENT")?);
    command.args(&[name]);
    let mut child = command
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::inherit())
        .spawn()?;

    let mut stdin = child.stdin.take().unwrap();
    eprintln!("sent: {}", data);
    stdin.write_all(data.as_bytes())?;
    stdin.write_all(b"\n")?;

    let mut s = String::new();
    let mut stdout = child.stdout.take().unwrap();
    stdout.read_to_string(&mut s)?;
    eprintln!("recv: {}", s);
    Ok(s)
}

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

    #[test]
    fn test_foo() -> Result<()> {
        let before = example::Foo {
            foo: 5,
            bar: 10,
            message: "Hello".into(),
        };
        let after = roundtrip("foo", &serde_json::to_string_pretty(&before)?)?;
        let after = serde_json::from_str::<example::Foo>(&after)?;
        assert_eq!(before, after);
        Ok(())
    }

    #[test]
    fn test_rect() -> Result<()> {
        let before = example::Rect {
            top_left: example::Coord { x: 10, y: 20 },
            bottom_right: example::Coord { x: 30, y: 40 },
        };
        let after = roundtrip("rect", &serde_json::to_string(&before)?)?;
        let after = serde_json::from_str::<example::Rect>(&after)?;
        assert_eq!(before, after);
        Ok(())
    }

    #[test]
    fn test_matrix() -> Result<()> {
        let before = example::Matrix {
            k: [
                [0, 1, 2, 3, 4],
                [100, 200, 300, 400, 500],
                [-1, -2, -3, -4, -5],
            ],
        };
        let after = roundtrip("matrix", &serde_json::to_string(&before)?)?;
        let after = serde_json::from_str::<example::Matrix>(&after)?;
        assert_eq!(before, after);
        Ok(())
    }

    #[test]
    fn test_direction() -> Result<()> {
        let before = example::Direction::North;
        let after = roundtrip("direction", &serde_json::to_string(&before)?)?;
        let after = serde_json::from_str::<example::Direction>(&after)?;
        assert_eq!(before, after);
        Ok(())
    }

    #[test]
    fn test_direction_intvalue() -> Result<()> {
        let before = example::Direction::IntValue(45);
        let after = roundtrip("direction", &serde_json::to_string(&before)?)?;
        let after = serde_json::from_str::<example::Direction>(&after)?;
        assert_eq!(before, after);
        Ok(())
    }

    #[test]
    fn test_fuzzy_true() -> Result<()> {
        let before = FuzzyBool::True;
        let after = roundtrip("fuzzy_bool", &serde_json::to_string(&before)?)?;
        let after = serde_json::from_str::<FuzzyBool>(&after)?;
        assert_eq!(before, after);
        Ok(())
    }

    #[test]
    fn test_fuzzy_false() -> Result<()> {
        let before = FuzzyBool::False;
        let after = roundtrip("fuzzy_bool", &serde_json::to_string(&before)?)?;
        let after = serde_json::from_str::<FuzzyBool>(&after)?;
        assert_eq!(before, after);
        Ok(())
    }

    #[test]
    fn test_fuzzy_maybe() -> Result<()> {
        let before = FuzzyBool(49);
        let after = roundtrip("fuzzy_bool", &serde_json::to_string(&before)?)?;
        let after = serde_json::from_str::<FuzzyBool>(&after)?;
        assert_eq!(before, after);
        Ok(())
    }

    #[test]
    fn test_misc() -> Result<()> {
        let before = example::Misc {
            value: true,
            status: Status::InvalidArgument("FOO".into(), 5),
        };
        let after = roundtrip("misc", &serde_json::to_string(&before)?)?;
        let after = serde_json::from_str::<example::Misc>(&after)?;
        assert_eq!(before, after);
        Ok(())
    }
}
<commit_msg>[cleanup] Fix clippy lints on usjon roundtrip_test<commit_after>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use anyhow::Result;
use opentitanlib::test_utils::status::Status;
use opentitanlib::with_unknown;
use std::io::{Read, Write};
use std::process::{Command, Stdio};

mod example {
    // Bring in the auto-generated sources.
    include!(env!("example"));
}

with_unknown! {
    enum FuzzyBool: u32 {
        False = 0,
        True = 100,
    }
}

fn roundtrip(name: &str, data: &str) -> Result<String> {
    let mut command = Command::new(&std::env::var("ROUNDTRIP_CLIENT")?);
    command.args([name]);
    let mut child = command
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::inherit())
        .spawn()?;

    let mut stdin = child.stdin.take().unwrap();
    eprintln!("sent: {}", data);
    stdin.write_all(data.as_bytes())?;
    stdin.write_all(b"\n")?;

    let mut s = String::new();
    let mut stdout = child.stdout.take().unwrap();
    stdout.read_to_string(&mut s)?;
    eprintln!("recv: {}", s);
    Ok(s)
}

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

    #[test]
    fn test_foo() -> Result<()> {
        let before = example::Foo {
            foo: 5,
            bar: 10,
            message: "Hello".into(),
        };
        let after = roundtrip("foo", &serde_json::to_string_pretty(&before)?)?;
        let after = serde_json::from_str::<example::Foo>(&after)?;
        assert_eq!(before, after);
        Ok(())
    }

    #[test]
    fn test_rect() -> Result<()> {
        let before = example::Rect {
            top_left: example::Coord { x: 10, y: 20 },
            bottom_right: example::Coord { x: 30, y: 40 },
        };
        let after = roundtrip("rect", &serde_json::to_string(&before)?)?;
        let after = serde_json::from_str::<example::Rect>(&after)?;
        assert_eq!(before, after);
        Ok(())
    }

    #[test]
    fn test_matrix() -> Result<()> {
        let before = example::Matrix {
            k: [
                [0, 1, 2, 3, 4],
                [100, 200, 300, 400, 500],
                [-1, -2, -3, -4, -5],
            ],
        };
        let after = roundtrip("matrix", &serde_json::to_string(&before)?)?;
        let after = serde_json::from_str::<example::Matrix>(&after)?;
        assert_eq!(before, after);
        Ok(())
    }

    #[test]
    fn test_direction() -> Result<()> {
        let before = example::Direction::North;
        let after = roundtrip("direction", &serde_json::to_string(&before)?)?;
        let after = serde_json::from_str::<example::Direction>(&after)?;
        assert_eq!(before, after);
        Ok(())
    }

    #[test]
    fn test_direction_intvalue() -> Result<()> {
        let before = example::Direction::IntValue(45);
        let after = roundtrip("direction", &serde_json::to_string(&before)?)?;
        let after = serde_json::from_str::<example::Direction>(&after)?;
        assert_eq!(before, after);
        Ok(())
    }

    #[test]
    fn test_fuzzy_true() -> Result<()> {
        let before = FuzzyBool::True;
        let after = roundtrip("fuzzy_bool", &serde_json::to_string(&before)?)?;
        let after = serde_json::from_str::<FuzzyBool>(&after)?;
        assert_eq!(before, after);
        Ok(())
    }

    #[test]
    fn test_fuzzy_false() -> Result<()> {
        let before = FuzzyBool::False;
        let after = roundtrip("fuzzy_bool", &serde_json::to_string(&before)?)?;
        let after = serde_json::from_str::<FuzzyBool>(&after)?;
        assert_eq!(before, after);
        Ok(())
    }

    #[test]
    fn test_fuzzy_maybe() -> Result<()> {
        let before = FuzzyBool(49);
        let after = roundtrip("fuzzy_bool", &serde_json::to_string(&before)?)?;
        let after = serde_json::from_str::<FuzzyBool>(&after)?;
        assert_eq!(before, after);
        Ok(())
    }

    #[test]
    fn test_misc() -> Result<()> {
        let before = example::Misc {
            value: true,
            status: Status::InvalidArgument("FOO".into(), 5),
        };
        let after = roundtrip("misc", &serde_json::to_string(&before)?)?;
        let after = serde_json::from_str::<example::Misc>(&after)?;
        assert_eq!(before, after);
        Ok(())
    }
}
<|endoftext|>