<commit_before>use std::io::Result as IoResult;
use std::io::Read;
use std::io::Error as IoError;
use std::io::ErrorKind;
use std::fmt;
use std::error::Error;

/// Reads HTTP chunks and sends back real data.
pub struct ChunksDecoder<R> {
    // where the chunks come from
    source: R,

    // remaining size of the chunk being read
    // none if we are not in a chunk
    remaining_chunks_size: Option<usize>,

    // data from the start of the current chunk
    buffer: Vec<u8>,
}

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

impl fmt::Display for ChunksError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "Error while decoding chunks")
    }
}

impl Error for ChunksError {
    fn description(&self) -> &str {
        "Error while decoding chunks"
    }
}

impl<R> ChunksDecoder<R> where R: Read {
    pub fn new(source: R) -> ChunksDecoder<R> {
        ChunksDecoder {
            source: source,
            remaining_chunks_size: None,
            buffer: Vec::with_capacity(128),
        }
    }
}

impl<R> Read for ChunksDecoder<R> where R: Read {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        // first possibility: we are not in a chunk
        if self.remaining_chunks_size.is_none() {
            // trying the read the chunk size
            let mut chunk_size = Vec::new();

            loop {
                let byte = match self.source.by_ref().bytes().next() {
                    Some(b) => try!(b),
                    None => return Err(IoError::new(ErrorKind::InvalidInput, ChunksError)),
                };

                if byte == b'\r' {
                    break;
                }

                chunk_size.push(byte);
            }

            match self.source.by_ref().bytes().next() {
                Some(Ok(b'\n')) => (),
                _ => return Err(IoError::new(ErrorKind::InvalidInput, ChunksError)),
            }

            let chunk_size = match String::from_utf8(chunk_size) {
                Ok(c) => c,
                Err(_) => return Err(IoError::new(ErrorKind::InvalidInput, ChunksError))
            };

            let chunk_size = match usize::from_str_radix(&chunk_size, 16) {
                Ok(c) => c,
                Err(_) => return Err(IoError::new(ErrorKind::InvalidInput, ChunksError))
            };

            // if the chunk size is 0, we are at EOF
            if chunk_size == 0 {
                if try!(self.source.by_ref().bytes().next().unwrap_or(Ok(0))) != b'\r' {
                    return Err(IoError::new(ErrorKind::InvalidInput, ChunksError));
                }
                if try!(self.source.by_ref().bytes().next().unwrap_or(Ok(0))) != b'\n' {
                    return Err(IoError::new(ErrorKind::InvalidInput, ChunksError));
                }
                return Ok(0);
            }

            // now that we now the current chunk size, calling ourselves recursively
            self.remaining_chunks_size = Some(chunk_size);
            return self.read(buf);
        }

        assert!(self.remaining_chunks_size.is_some());

        // second possibility: we continue reading from a chunk
        if buf.len() < *self.remaining_chunks_size.as_ref().unwrap() {
            let read = try!(self.source.read(buf));
            *self.remaining_chunks_size.as_mut().unwrap() -= read;
            return Ok(read);
        }

        // third possibility: the read request goes further than the current chunk
        // we simply read until the end of the chunk and return
        assert!(buf.len() >= *self.remaining_chunks_size.as_ref().unwrap());

        let remaining_chunks_size = *self.remaining_chunks_size.as_ref().unwrap();

        let buf = &mut buf[.. remaining_chunks_size];
        let read = try!(self.source.read(buf));
        *self.remaining_chunks_size.as_mut().unwrap() -= read;

        if read == remaining_chunks_size {
            self.remaining_chunks_size = None;

            if try!(self.source.by_ref().bytes().next().unwrap_or(Ok(0))) != b'\r' {
                return Err(IoError::new(ErrorKind::InvalidInput, ChunksError));
            }
            if try!(self.source.by_ref().bytes().next().unwrap_or(Ok(0))) != b'\n' {
                return Err(IoError::new(ErrorKind::InvalidInput, ChunksError));
            }
        }

        return Ok(read);
    }
}

#[cfg(test)]
mod test {
    use super::ChunksDecoder;
    use std::io;
    use std::io::Read;

    #[test]
    fn test_valid_chunk_decode() {
        let source = io::Cursor::new("3\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n".to_string().into_bytes());
        let mut decoded = ChunksDecoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).unwrap();

        assert_eq!(string, "hello world!!!");
    }

    #[test]
    #[should_panic]
    fn invalid_input1() {
        let source = io::Cursor::new("2\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n".to_string().into_bytes());
        let mut decoded = ChunksDecoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).unwrap();
    }

    #[test]
    #[should_panic]
    fn invalid_input2() {
        let source = io::Cursor::new("3\rhel\r\nb\r\nlo world!!!\r\n0\r\n".to_string().into_bytes());
        let mut decoded = ChunksDecoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).unwrap();
    }
}
<commit_msg>Fix chunk decoder bug. We already parse \r\n for 0<commit_after>use std::io::Result as IoResult;
use std::io::Read;
use std::io::Error as IoError;
use std::io::ErrorKind;
use std::fmt;
use std::error::Error;

/// Reads HTTP chunks and sends back real data.
pub struct ChunksDecoder<R> {
    // where the chunks come from
    source: R,

    // remaining size of the chunk being read
    // none if we are not in a chunk
    remaining_chunks_size: Option<usize>,

    // data from the start of the current chunk
    buffer: Vec<u8>,
}

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

impl fmt::Display for ChunksError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "Error while decoding chunks")
    }
}

impl Error for ChunksError {
    fn description(&self) -> &str {
        "Error while decoding chunks"
    }
}

impl<R> ChunksDecoder<R> where R: Read {
    pub fn new(source: R) -> ChunksDecoder<R> {
        ChunksDecoder {
            source: source,
            remaining_chunks_size: None,
            buffer: Vec::with_capacity(128),
        }
    }
}

impl<R> Read for ChunksDecoder<R> where R: Read {
    fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
        // first possibility: we are not in a chunk
        if self.remaining_chunks_size.is_none() {
            // trying the read the chunk size
            let mut chunk_size = Vec::new();

            loop {
                let byte = match self.source.by_ref().bytes().next() {
                    Some(b) => try!(b),
                    None => return Err(IoError::new(ErrorKind::InvalidInput, ChunksError)),
                };

                if byte == b'\r' {
                    break;
                }

                chunk_size.push(byte);
            }

            match self.source.by_ref().bytes().next() {
                Some(Ok(b'\n')) => (),
                _ => return Err(IoError::new(ErrorKind::InvalidInput, ChunksError)),
            }

            let chunk_size = match String::from_utf8(chunk_size) {
                Ok(c) => c,
                Err(_) => return Err(IoError::new(ErrorKind::InvalidInput, ChunksError))
            };

            let chunk_size = match usize::from_str_radix(&chunk_size, 16) {
                Ok(c) => c,
                Err(_) => return Err(IoError::new(ErrorKind::InvalidInput, ChunksError))
            };

            // if the chunk size is 0, we are at EOF
            if chunk_size == 0 {
                return Ok(0);
            }

            // now that we now the current chunk size, calling ourselves recursively
            self.remaining_chunks_size = Some(chunk_size);
            return self.read(buf);
        }

        assert!(self.remaining_chunks_size.is_some());

        // second possibility: we continue reading from a chunk
        if buf.len() < *self.remaining_chunks_size.as_ref().unwrap() {
            let read = try!(self.source.read(buf));
            *self.remaining_chunks_size.as_mut().unwrap() -= read;
            return Ok(read);
        }

        // third possibility: the read request goes further than the current chunk
        // we simply read until the end of the chunk and return
        assert!(buf.len() >= *self.remaining_chunks_size.as_ref().unwrap());

        let remaining_chunks_size = *self.remaining_chunks_size.as_ref().unwrap();

        let buf = &mut buf[.. remaining_chunks_size];
        let read = try!(self.source.read(buf));
        *self.remaining_chunks_size.as_mut().unwrap() -= read;

        if read == remaining_chunks_size {
            self.remaining_chunks_size = None;

            if try!(self.source.by_ref().bytes().next().unwrap_or(Ok(0))) != b'\r' {
                return Err(IoError::new(ErrorKind::InvalidInput, ChunksError));
            }
            if try!(self.source.by_ref().bytes().next().unwrap_or(Ok(0))) != b'\n' {
                return Err(IoError::new(ErrorKind::InvalidInput, ChunksError));
            }
        }

        return Ok(read);
    }
}

#[cfg(test)]
mod test {
    use super::ChunksDecoder;
    use std::io;
    use std::io::Read;

    #[test]
    fn test_valid_chunk_decode() {
        let source = io::Cursor::new("3\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n".to_string().into_bytes());
        let mut decoded = ChunksDecoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).unwrap();

        assert_eq!(string, "hello world!!!");
    }

    #[test]
    #[should_panic]
    fn invalid_input1() {
        let source = io::Cursor::new("2\r\nhel\r\nb\r\nlo world!!!\r\n0\r\n".to_string().into_bytes());
        let mut decoded = ChunksDecoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).unwrap();
    }

    #[test]
    #[should_panic]
    fn invalid_input2() {
        let source = io::Cursor::new("3\rhel\r\nb\r\nlo world!!!\r\n0\r\n".to_string().into_bytes());
        let mut decoded = ChunksDecoder::new(source);

        let mut string = String::new();
        decoded.read_to_string(&mut string).unwrap();
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

//! Non-modal input dialogs.

use std::collections::HashMap;
use std::sync::mpsc::{Receiver, SyncSender, sync_channel};

use gtk;
use mg_settings::{EnumFromStr, EnumMetaData, SettingCompletion, SpecialCommand};
use mg_settings::key::Key;
use mg_settings::settings;
use relm::{
    ContainerComponent,
    EventStream,
    Relm,
    Update,
    Widget,
};

use app::{Mg, BLOCKING_INPUT_MODE, INPUT_MODE};
use app::color::color_blue;
use app::Msg::{
    BlockingInput,
    BlockingQuestion,
    BlockingYesNoQuestion,
    EnterNormalModeAndReset,
    Input,
    Question,
    ResetInput,
};
use app::status_bar::Msg::{Identifier, ShowIdentifier};
use completion::completion_view::Msg::SetOriginalInput;
use self::DialogResult::{Answer, Shortcut};

/// A Responder is a way to send back the answer of a dialog to the code that showed this dialog.
pub trait Responder {
    /// Send the answer back.
    /// It can be to a widget or a channel.
    fn respond(&self, answer: DialogResult);
}

/// Blocking input dialog responder.
/// This is used to send the message to a channel when the user answers the dialog.
pub struct BlockingInputDialog {
    tx: SyncSender<Option<String>>,
}

impl BlockingInputDialog {
    fn new() -> (Self, Receiver<Option<String>>) {
        let (tx, rx) = sync_channel(1);
        (BlockingInputDialog {
            tx,
        }, rx)
    }
}

impl Responder for BlockingInputDialog {
    fn respond(&self, answer: DialogResult) {
        match answer {
            Answer(answer) => {
                self.tx.send(answer).expect("Sending answer shouldn't fail")
            },
            _ => unimplemented!(),
        }
        gtk::main_quit();
    }
}

/// Input dialog responder.
/// This is used to specify which message to send to which widget when the user answers the dialog.
pub struct InputDialog<WIDGET: Widget> {
    callback: fn(Option<String>) -> WIDGET::Msg,
    stream: EventStream<WIDGET::Msg>,
}

impl<WIDGET: Widget> InputDialog<WIDGET> {
    fn new(relm: &Relm<WIDGET>, callback: fn(Option<String>) -> WIDGET::Msg) -> Self {
        InputDialog {
            callback,
            stream: relm.stream().clone(),
        }
    }
}

impl<WIDGET: Widget> Responder for InputDialog<WIDGET> {
    fn respond(&self, answer: DialogResult) {
        match answer {
            Answer(answer) => self.stream.emit((self.callback)(answer)),
            _ => unimplemented!(),
        }
    }
}

/// Builder to create a new dialog.
pub struct DialogBuilder {
    /// Whether the dialog should block the calling function.
    blocking: bool,
    /// The available choices to the question.
    choices: Vec<char>,
    /// The text completer identifier for the input.
    completer: Option<String>,
    /// The default answer to the question.
    default_answer: String,
    /// The message/question to show to the user.
    message: String,
    /// The wrapper over the callback function to call for an asynchronous input dialog.
    responder: Option<Box<Responder>>,
    /// The available shortcuts.
    shortcuts: HashMap<Key, String>,
}

impl DialogBuilder {
    /// Create a new dialog builder.
    #[allow(new_without_default_derive, unknown_lints)]
    pub fn new() -> Self {
        DialogBuilder {
            blocking: false,
            choices: vec![],
            completer: None,
            default_answer: String::new(),
            message: String::new(),
            responder: None,
            shortcuts: HashMap::new(),
        }
    }

    /// Set whether the dialog will block or not.
    pub fn blocking(mut self, blocking: bool) -> Self {
        self.blocking = blocking;
        self
    }

    /// Set the choices available for the input.
    pub fn choices(mut self, choices: Vec<char>) -> Self {
        self.choices = choices;
        self
    }

    /// Set the text completer for the input.
    pub fn completer(mut self, completer: &str) -> Self {
        self.completer = Some(completer.to_string());
        self
    }

    /// Set the default answer for the input.
    pub fn default_answer(mut self, answer: String) -> Self {
        self.default_answer = answer;
        self
    }

    /// Set the message/question to show to the user.
    pub fn message(mut self, message: String) -> Self {
        self.message = message;
        self
    }

    /// Set a responder for an asynchronous dialog.
    pub fn responder(mut self, responder: Box<Responder>) -> Self {
        self.responder = Some(responder);
        self
    }

    /// Add a shortcut.
    pub fn shortcut(mut self, shortcut: Key, value: &str) -> Self {
        self.shortcuts.insert(shortcut, value.to_string());
        self
    }
}

/// Struct representing a dialog result.
/// A dialog result is either what the user typed in the input (Answer) or the string associated
/// with the shortcut.
pub enum DialogResult {
    /// A string typed by the user or None if the user closed the dialog (with Escape).
    Answer(Option<String>),
    /// A shortcut pressd by the user.
    Shortcut(String),
}

impl<COMM, SETT> Mg<COMM, SETT>
where COMM: Clone + EnumFromStr + EnumMetaData + SpecialCommand + 'static,
      SETT: Default + EnumMetaData + settings::Settings + SettingCompletion + 'static,
{
    /// Ask a question to the user and block until the user provides it (or cancel).
    pub fn blocking_input(&mut self, responder: Box<Responder>, message: String, default_answer: String) {
        let builder = DialogBuilder::new()
            .blocking(true)
            .default_answer(default_answer)
            .message(message)
            .responder(responder);
        self.show_dialog_without_shortcuts(builder);
    }

    /// Ask a multiple-choice question to the user and block until the user provides it (or cancel).
    pub fn blocking_question(&mut self, responder: Box<Responder>, message: String, choices: Vec<char>) {
        let builder = DialogBuilder::new()
            .blocking(true)
            .choices(choices)
            .message(message)
            .responder(responder);
        self.show_dialog_without_shortcuts(builder);
    }

    /// Show a blocking yes/no question.
    pub fn blocking_yes_no_question(&mut self, responder: Box<Responder>, message: String) {
        let builder = DialogBuilder::new()
            .blocking(true)
            .choices(vec!['y', 'n'])
            .message(message)
            .responder(responder);
        self.show_dialog_without_shortcuts(builder);
    }

    /// Ask a question to the user.
    pub fn input(&mut self, responder: Box<Responder>, message: String, default_answer: String) {
        let builder = DialogBuilder::new()
            .default_answer(default_answer)
            .message(message)
            .responder(responder);
        self.show_dialog(builder);
    }

    /// Ask a multiple-choice question to the user.
    pub fn question(&mut self, responder: Box<Responder>, message: String, choices: &[char]) {
        let builder = DialogBuilder::new()
            .responder(responder)
            .message(message)
            .choices(choices.to_vec());
        self.show_dialog(builder);
    }

    /// Set the answer to return to the caller of the dialog.
    pub fn set_dialog_answer(&mut self, answer: &str) {
        let mut should_reset = false;
        if let Some(callback) = self.model.input_callback.take() {
            callback(Some(answer.to_string()), self.model.shortcut_pressed);
            self.model.choices.clear();
            should_reset = true;
        }
        if should_reset {
            self.model.relm.stream().emit(EnterNormalModeAndReset);
        }
    }

    /// Show a dialog created with a `DialogBuilder`.
    pub fn show_dialog(&mut self, mut dialog_builder: DialogBuilder) {
        self.model.shortcut_pressed = false;

        self.model.shortcuts.clear();
        for (key, value) in dialog_builder.shortcuts {
            self.model.shortcuts.insert(key, value);
        }

        let choices = dialog_builder.choices.clone();
        if !choices.is_empty() {
            self.model.choices.clear();
            self.model.choices.append(&mut dialog_builder.choices);
            let choices: Vec<_> = choices.iter().map(|c| c.to_string()).collect();
            let choices = choices.join("/");
            self.status_bar.emit(Identifier(format!("{} ({}) ", dialog_builder.message, choices)));
            self.status_bar.emit(ShowIdentifier);
        }
        else {
            self.status_bar.emit(Identifier(format!("{} ", dialog_builder.message)));
            self.show_entry();
            self.set_input(&dialog_builder.default_answer);
        }

        if let Some(completer) = dialog_builder.completer {
            self.set_completer(&completer);
            self.completion_view.emit(SetOriginalInput(dialog_builder.default_answer));
            self.show_completion();
        }

        self.model.answer = None;
        if dialog_builder.blocking {
            /*self.model.input_callback = Some(Box::new(|_, _| {
                // TODO: is it still needed?
                //gtk::main_quit();
            }));*/
        }
        if dialog_builder.blocking {
            self.set_mode(BLOCKING_INPUT_MODE);
        }
        else {
            self.set_mode(INPUT_MODE);
        }
        if let Some(responder) = dialog_builder.responder {
            self.model.input_callback = Some(Box::new(move |answer, shortcut_pressed| {
                let answer =
                    if shortcut_pressed {
                        if let Some(answer) = answer.clone() {
                            Shortcut(answer)
                        }
                        else {
                            Answer(None)
                        }
                    }
                    else {
                        Answer(answer.clone())
                    };
                responder.respond(answer);
            }));
        }
        color_blue(self.status_bar.widget());
    }

    /// Show a dialog created with a `DialogBuilder` which does not contain shortcut.
    pub fn show_dialog_without_shortcuts(&mut self, dialog_builder: DialogBuilder) {
        self.show_dialog(dialog_builder);
            /*Answer(answer) => answer,
            Shortcut(_) => panic!("cannot return a shortcut in show_dialog_without_shortcuts()"),
        }*/
        // TODO
    }
}

/// Ask a question to the user and block until the user provides it (or cancel).
pub fn blocking_input<COMM, SETT>(mg: &EventStream<<Mg<COMM, SETT> as Update>::Msg>, msg: String,
    default_answer: String) -> Option<String>
where COMM: Clone + EnumFromStr + EnumMetaData + SpecialCommand + 'static,
      SETT: Default + EnumMetaData + settings::Settings + SettingCompletion + 'static,
{
    let (blocking_input_dialog, rx) = BlockingInputDialog::new();
    let responder = Box::new(blocking_input_dialog);
    mg.emit(BlockingInput(responder, msg, default_answer));
    gtk::main();
    mg.emit(ResetInput);
    rx.recv().unwrap_or(None)
}

/// Ask a multiple-choice question to the user and block until the user provides it (or cancel).
pub fn blocking_question<COMM, SETT>(mg: &EventStream<<Mg<COMM, SETT> as Update>::Msg>, msg: String,
    choices: &[char]) -> Option<String>
where COMM: Clone + EnumFromStr + EnumMetaData + SpecialCommand + 'static,
      SETT: Default + EnumMetaData + settings::Settings + SettingCompletion + 'static,
{
    let (blocking_input_dialog, rx) = BlockingInputDialog::new();
    let responder = Box::new(blocking_input_dialog);
    mg.emit(BlockingQuestion(responder, msg, choices.to_vec()));
    gtk::main();
    mg.emit(ResetInput);
    rx.recv().unwrap_or(None)
}

/// Show a blocking yes/no question.
pub fn blocking_yes_no_question<COMM, SETT>(mg: &EventStream<<Mg<COMM, SETT> as Update>::Msg>, msg: String)
    -> bool
where COMM: Clone + EnumFromStr + EnumMetaData + SpecialCommand + 'static,
      SETT: Default + EnumMetaData + settings::Settings + SettingCompletion + 'static,
{
    let (blocking_input_dialog, rx) = BlockingInputDialog::new();
    let responder = Box::new(blocking_input_dialog);
    mg.emit(BlockingYesNoQuestion(responder, msg));
    gtk::main();
    mg.emit(ResetInput);
    rx.recv() == Ok(Some("y".to_string()))
}

/// Ask a question to the user.
pub fn input<COMM, SETT, WIDGET: Widget>(mg: &ContainerComponent<Mg<COMM, SETT>>, relm: &Relm<WIDGET>, msg: String,
    default_answer: String, callback: fn(Option<String>) -> WIDGET::Msg)
where COMM: Clone + EnumFromStr + EnumMetaData + SpecialCommand + 'static,
      SETT: Default + EnumMetaData + settings::Settings + SettingCompletion + 'static,
      WIDGET: 'static,
{
    let responder = Box::new(InputDialog::new(relm, callback));
    mg.emit(Input(responder, msg, default_answer));
}

/// Ask a multiple-choice question to the user.
pub fn question<COMM, SETT, WIDGET: Widget>(mg: &ContainerComponent<Mg<COMM, SETT>>, relm: &Relm<WIDGET>, msg: String,
    choices: &'static [char], callback: fn(Option<String>) -> WIDGET::Msg)
where COMM: Clone + EnumFromStr + EnumMetaData + SpecialCommand + 'static,
      SETT: Default + EnumMetaData + settings::Settings + SettingCompletion + 'static,
      WIDGET: 'static,
{
    let responder = Box::new(InputDialog::new(relm, callback));
    mg.emit(Question(responder, msg, choices));
}
<commit_msg>Fix to allow closures for dialog callback<commit_after>/*
 * Copyright (c) 2016 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

//! Non-modal input dialogs.

use std::collections::HashMap;
use std::sync::mpsc::{Receiver, SyncSender, sync_channel};

use gtk;
use mg_settings::{EnumFromStr, EnumMetaData, SettingCompletion, SpecialCommand};
use mg_settings::key::Key;
use mg_settings::settings;
use relm::{
    ContainerComponent,
    EventStream,
    Relm,
    Update,
    Widget,
};

use app::{Mg, BLOCKING_INPUT_MODE, INPUT_MODE};
use app::color::color_blue;
use app::Msg::{
    BlockingInput,
    BlockingQuestion,
    BlockingYesNoQuestion,
    EnterNormalModeAndReset,
    Input,
    Question,
    ResetInput,
};
use app::status_bar::Msg::{Identifier, ShowIdentifier};
use completion::completion_view::Msg::SetOriginalInput;
use self::DialogResult::{Answer, Shortcut};

/// A Responder is a way to send back the answer of a dialog to the code that showed this dialog.
pub trait Responder {
    /// Send the answer back.
    /// It can be to a widget or a channel.
    fn respond(&self, answer: DialogResult);
}

/// Blocking input dialog responder.
/// This is used to send the message to a channel when the user answers the dialog.
pub struct BlockingInputDialog {
    tx: SyncSender<Option<String>>,
}

impl BlockingInputDialog {
    fn new() -> (Self, Receiver<Option<String>>) {
        let (tx, rx) = sync_channel(1);
        (BlockingInputDialog {
            tx,
        }, rx)
    }
}

impl Responder for BlockingInputDialog {
    fn respond(&self, answer: DialogResult) {
        match answer {
            Answer(answer) => {
                self.tx.send(answer).expect("Sending answer shouldn't fail")
            },
            _ => unimplemented!(),
        }
        gtk::main_quit();
    }
}

/// Input dialog responder.
/// This is used to specify which message to send to which widget when the user answers the dialog.
pub struct InputDialog<WIDGET: Widget> {
    callback: Box<Fn(Option<String>) -> WIDGET::Msg>,
    stream: EventStream<WIDGET::Msg>,
}

impl<WIDGET: Widget> InputDialog<WIDGET> {
    fn new<F>(relm: &Relm<WIDGET>, callback: F) -> Self
        where F: Fn(Option<String>) -> WIDGET::Msg + 'static,
    {
        InputDialog {
            callback: Box::new(callback),
            stream: relm.stream().clone(),
        }
    }
}

impl<WIDGET: Widget> Responder for InputDialog<WIDGET> {
    fn respond(&self, answer: DialogResult) {
        match answer {
            Answer(answer) => self.stream.emit((self.callback)(answer)),
            _ => unimplemented!(),
        }
    }
}

/// Builder to create a new dialog.
pub struct DialogBuilder {
    /// Whether the dialog should block the calling function.
    blocking: bool,
    /// The available choices to the question.
    choices: Vec<char>,
    /// The text completer identifier for the input.
    completer: Option<String>,
    /// The default answer to the question.
    default_answer: String,
    /// The message/question to show to the user.
    message: String,
    /// The wrapper over the callback function to call for an asynchronous input dialog.
    responder: Option<Box<Responder>>,
    /// The available shortcuts.
    shortcuts: HashMap<Key, String>,
}

impl DialogBuilder {
    /// Create a new dialog builder.
    #[allow(new_without_default_derive, unknown_lints)]
    pub fn new() -> Self {
        DialogBuilder {
            blocking: false,
            choices: vec![],
            completer: None,
            default_answer: String::new(),
            message: String::new(),
            responder: None,
            shortcuts: HashMap::new(),
        }
    }

    /// Set whether the dialog will block or not.
    pub fn blocking(mut self, blocking: bool) -> Self {
        self.blocking = blocking;
        self
    }

    /// Set the choices available for the input.
    pub fn choices(mut self, choices: Vec<char>) -> Self {
        self.choices = choices;
        self
    }

    /// Set the text completer for the input.
    pub fn completer(mut self, completer: &str) -> Self {
        self.completer = Some(completer.to_string());
        self
    }

    /// Set the default answer for the input.
    pub fn default_answer(mut self, answer: String) -> Self {
        self.default_answer = answer;
        self
    }

    /// Set the message/question to show to the user.
    pub fn message(mut self, message: String) -> Self {
        self.message = message;
        self
    }

    /// Set a responder for an asynchronous dialog.
    pub fn responder(mut self, responder: Box<Responder>) -> Self {
        self.responder = Some(responder);
        self
    }

    /// Add a shortcut.
    pub fn shortcut(mut self, shortcut: Key, value: &str) -> Self {
        self.shortcuts.insert(shortcut, value.to_string());
        self
    }
}

/// Struct representing a dialog result.
/// A dialog result is either what the user typed in the input (Answer) or the string associated
/// with the shortcut.
pub enum DialogResult {
    /// A string typed by the user or None if the user closed the dialog (with Escape).
    Answer(Option<String>),
    /// A shortcut pressd by the user.
    Shortcut(String),
}

impl<COMM, SETT> Mg<COMM, SETT>
where COMM: Clone + EnumFromStr + EnumMetaData + SpecialCommand + 'static,
      SETT: Default + EnumMetaData + settings::Settings + SettingCompletion + 'static,
{
    /// Ask a question to the user and block until the user provides it (or cancel).
    pub fn blocking_input(&mut self, responder: Box<Responder>, message: String, default_answer: String) {
        let builder = DialogBuilder::new()
            .blocking(true)
            .default_answer(default_answer)
            .message(message)
            .responder(responder);
        self.show_dialog_without_shortcuts(builder);
    }

    /// Ask a multiple-choice question to the user and block until the user provides it (or cancel).
    pub fn blocking_question(&mut self, responder: Box<Responder>, message: String, choices: Vec<char>) {
        let builder = DialogBuilder::new()
            .blocking(true)
            .choices(choices)
            .message(message)
            .responder(responder);
        self.show_dialog_without_shortcuts(builder);
    }

    /// Show a blocking yes/no question.
    pub fn blocking_yes_no_question(&mut self, responder: Box<Responder>, message: String) {
        let builder = DialogBuilder::new()
            .blocking(true)
            .choices(vec!['y', 'n'])
            .message(message)
            .responder(responder);
        self.show_dialog_without_shortcuts(builder);
    }

    /// Ask a question to the user.
    pub fn input(&mut self, responder: Box<Responder>, message: String, default_answer: String) {
        let builder = DialogBuilder::new()
            .default_answer(default_answer)
            .message(message)
            .responder(responder);
        self.show_dialog(builder);
    }

    /// Ask a multiple-choice question to the user.
    pub fn question(&mut self, responder: Box<Responder>, message: String, choices: &[char]) {
        let builder = DialogBuilder::new()
            .responder(responder)
            .message(message)
            .choices(choices.to_vec());
        self.show_dialog(builder);
    }

    /// Set the answer to return to the caller of the dialog.
    pub fn set_dialog_answer(&mut self, answer: &str) {
        let mut should_reset = false;
        if let Some(callback) = self.model.input_callback.take() {
            callback(Some(answer.to_string()), self.model.shortcut_pressed);
            self.model.choices.clear();
            should_reset = true;
        }
        if should_reset {
            self.model.relm.stream().emit(EnterNormalModeAndReset);
        }
    }

    /// Show a dialog created with a `DialogBuilder`.
    pub fn show_dialog(&mut self, mut dialog_builder: DialogBuilder) {
        self.model.shortcut_pressed = false;

        self.model.shortcuts.clear();
        for (key, value) in dialog_builder.shortcuts {
            self.model.shortcuts.insert(key, value);
        }

        let choices = dialog_builder.choices.clone();
        if !choices.is_empty() {
            self.model.choices.clear();
            self.model.choices.append(&mut dialog_builder.choices);
            let choices: Vec<_> = choices.iter().map(|c| c.to_string()).collect();
            let choices = choices.join("/");
            self.status_bar.emit(Identifier(format!("{} ({}) ", dialog_builder.message, choices)));
            self.status_bar.emit(ShowIdentifier);
        }
        else {
            self.status_bar.emit(Identifier(format!("{} ", dialog_builder.message)));
            self.show_entry();
            self.set_input(&dialog_builder.default_answer);
        }

        if let Some(completer) = dialog_builder.completer {
            self.set_completer(&completer);
            self.completion_view.emit(SetOriginalInput(dialog_builder.default_answer));
            self.show_completion();
        }

        self.model.answer = None;
        if dialog_builder.blocking {
            /*self.model.input_callback = Some(Box::new(|_, _| {
                // TODO: is it still needed?
                //gtk::main_quit();
            }));*/
        }
        if dialog_builder.blocking {
            self.set_mode(BLOCKING_INPUT_MODE);
        }
        else {
            self.set_mode(INPUT_MODE);
        }
        if let Some(responder) = dialog_builder.responder {
            self.model.input_callback = Some(Box::new(move |answer, shortcut_pressed| {
                let answer =
                    if shortcut_pressed {
                        if let Some(answer) = answer.clone() {
                            Shortcut(answer)
                        }
                        else {
                            Answer(None)
                        }
                    }
                    else {
                        Answer(answer.clone())
                    };
                responder.respond(answer);
            }));
        }
        color_blue(self.status_bar.widget());
    }

    /// Show a dialog created with a `DialogBuilder` which does not contain shortcut.
    pub fn show_dialog_without_shortcuts(&mut self, dialog_builder: DialogBuilder) {
        self.show_dialog(dialog_builder);
            /*Answer(answer) => answer,
            Shortcut(_) => panic!("cannot return a shortcut in show_dialog_without_shortcuts()"),
        }*/
        // TODO
    }
}

/// Ask a question to the user and block until the user provides it (or cancel).
pub fn blocking_input<COMM, SETT>(mg: &EventStream<<Mg<COMM, SETT> as Update>::Msg>, msg: String,
    default_answer: String) -> Option<String>
where COMM: Clone + EnumFromStr + EnumMetaData + SpecialCommand + 'static,
      SETT: Default + EnumMetaData + settings::Settings + SettingCompletion + 'static,
{
    let (blocking_input_dialog, rx) = BlockingInputDialog::new();
    let responder = Box::new(blocking_input_dialog);
    mg.emit(BlockingInput(responder, msg, default_answer));
    gtk::main();
    mg.emit(ResetInput);
    rx.recv().unwrap_or(None)
}

/// Ask a multiple-choice question to the user and block until the user provides it (or cancel).
pub fn blocking_question<COMM, SETT>(mg: &EventStream<<Mg<COMM, SETT> as Update>::Msg>, msg: String,
    choices: &[char]) -> Option<String>
where COMM: Clone + EnumFromStr + EnumMetaData + SpecialCommand + 'static,
      SETT: Default + EnumMetaData + settings::Settings + SettingCompletion + 'static,
{
    let (blocking_input_dialog, rx) = BlockingInputDialog::new();
    let responder = Box::new(blocking_input_dialog);
    mg.emit(BlockingQuestion(responder, msg, choices.to_vec()));
    gtk::main();
    mg.emit(ResetInput);
    rx.recv().unwrap_or(None)
}

/// Show a blocking yes/no question.
pub fn blocking_yes_no_question<COMM, SETT>(mg: &EventStream<<Mg<COMM, SETT> as Update>::Msg>, msg: String)
    -> bool
where COMM: Clone + EnumFromStr + EnumMetaData + SpecialCommand + 'static,
      SETT: Default + EnumMetaData + settings::Settings + SettingCompletion + 'static,
{
    let (blocking_input_dialog, rx) = BlockingInputDialog::new();
    let responder = Box::new(blocking_input_dialog);
    mg.emit(BlockingYesNoQuestion(responder, msg));
    gtk::main();
    mg.emit(ResetInput);
    rx.recv() == Ok(Some("y".to_string()))
}

/// Ask a question to the user.
pub fn input<CALLBACK, COMM, SETT, WIDGET>(mg: &ContainerComponent<Mg<COMM, SETT>>, relm: &Relm<WIDGET>, msg: String,
    default_answer: String, callback: CALLBACK)
where CALLBACK: Fn(Option<String>) -> WIDGET::Msg + 'static,
      COMM: Clone + EnumFromStr + EnumMetaData + SpecialCommand + 'static,
      SETT: Default + EnumMetaData + settings::Settings + SettingCompletion + 'static,
      WIDGET: Widget + 'static,
{
    let responder = Box::new(InputDialog::new(relm, callback));
    mg.emit(Input(responder, msg, default_answer));
}

/// Ask a multiple-choice question to the user.
pub fn question<CALLBACK, COMM, SETT, WIDGET>(mg: &ContainerComponent<Mg<COMM, SETT>>, relm: &Relm<WIDGET>, msg: String,
    choices: &'static [char], callback: CALLBACK)
where CALLBACK: Fn(Option<String>) -> WIDGET::Msg + 'static,
      COMM: Clone + EnumFromStr + EnumMetaData + SpecialCommand + 'static,
      SETT: Default + EnumMetaData + settings::Settings + SettingCompletion + 'static,
      WIDGET: Widget + 'static,
{
    let responder = Box::new(InputDialog::new(relm, callback));
    mg.emit(Question(responder, msg, choices));
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::BindingDeclarations::HTMLDataElementBinding;
use dom::bindings::codegen::InheritTypes::HTMLDataElementDerived;
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::error::ErrorResult;
use dom::document::Document;
use dom::element::HTMLDataElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId};
use servo_util::str::DOMString;

#[deriving(Encodable)]
pub struct HTMLDataElement {
    pub htmlelement: HTMLElement
}

impl HTMLDataElementDerived for EventTarget {
    fn is_htmldataelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLDataElementTypeId))
    }
}

impl HTMLDataElement {
    pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLDataElement {
        HTMLDataElement {
            htmlelement: HTMLElement::new_inherited(HTMLDataElementTypeId, localName, document)
        }
    }

    pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLDataElement> {
        let element = HTMLDataElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLDataElementBinding::Wrap)
    }
}

pub trait HTMLDataElementMethods {
    fn Value(&self) -> DOMString;
    fn SetValue(&mut self, _value: DOMString) -> ErrorResult;
}

impl<'a> HTMLDataElementMethods for JSRef<'a, HTMLDataElement> {
    fn Value(&self) -> DOMString {
        "".to_owned()
    }

    fn SetValue(&mut self, _value: DOMString) -> ErrorResult {
        Ok(())
    }
}
<commit_msg>Remove needless '&mut self' from HTMLDataElementMethods.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::BindingDeclarations::HTMLDataElementBinding;
use dom::bindings::codegen::InheritTypes::HTMLDataElementDerived;
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::error::ErrorResult;
use dom::document::Document;
use dom::element::HTMLDataElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId};
use servo_util::str::DOMString;

#[deriving(Encodable)]
pub struct HTMLDataElement {
    pub htmlelement: HTMLElement
}

impl HTMLDataElementDerived for EventTarget {
    fn is_htmldataelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLDataElementTypeId))
    }
}

impl HTMLDataElement {
    pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLDataElement {
        HTMLDataElement {
            htmlelement: HTMLElement::new_inherited(HTMLDataElementTypeId, localName, document)
        }
    }

    pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLDataElement> {
        let element = HTMLDataElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLDataElementBinding::Wrap)
    }
}

pub trait HTMLDataElementMethods {
    fn Value(&self) -> DOMString;
    fn SetValue(&self, _value: DOMString) -> ErrorResult;
}

impl<'a> HTMLDataElementMethods for JSRef<'a, HTMLDataElement> {
    fn Value(&self) -> DOMString {
        "".to_owned()
    }

    fn SetValue(&self, _value: DOMString) -> ErrorResult {
        Ok(())
    }
}
<|endoftext|>


<commit_before>#![feature(core)]
extern crate cql_ffi_safe;

use cql_ffi_safe::CassStatement;
use cql_ffi_safe::CassSession;
use cql_ffi_safe::CassCluster;
use cql_ffi_safe::FromCol;
use cql_ffi_safe::CassError;

static SELECT_QUERY_CMD:&'static str = "SELECT keyspace_name,durable_writes FROM system.schema_keyspaces;";
static CONTACT_POINTS:&'static str = "127.0.0.1,127.0.0.2,127.0.0.3";

fn main() {
    match CassCluster::new().set_contact_points(CONTACT_POINTS) {
        Err(err) => println!("{:?}",err),
        Ok(cluster) => {
            let mut session = CassSession::new();
            session.connect(cluster).wait();
            let result_iter = session.execute(&CassStatement::new(SELECT_QUERY_CMD,0))
                .wait()
                .get_result()
                .unwrap()
                .iter();
            for row in result_iter {
                let value:Result<String,CassError> = FromCol::from_col(row.get_column(0));
                match value {
                    Err(err) => println!("Error: {:?}", err),
                    Ok(ks) => println!("ks: {:?}",ks)
                }
            }
        }
    }
}
<commit_msg>cleaner<commit_after>#![feature(core)]
extern crate cql_ffi_safe;

use cql_ffi_safe::*;

static SELECT_QUERY_CMD:&'static str = "SELECT keyspace_name,durable_writes FROM system.schema_keyspaces;";
static CONTACT_POINTS:&'static str = "127.0.0.1,127.0.0.2,127.0.0.3";

fn main() {
    match CassCluster::new().set_contact_points(CONTACT_POINTS) {
        Err(err) => println!("{:?}",err),
        Ok(cluster) => {
            let mut session = CassSession::new();
            session.connect(cluster).wait();
            let result_iter = session.execute(&CassStatement::new(SELECT_QUERY_CMD,0))
                .wait()
                .get_result()
                .unwrap()
                .iter();
            for row in result_iter {
                let value:Result<String,CassError> = FromCol::from_col(row.get_column(0));
                match value {
                    Err(err) => println!("Error: {:?}", err),
                    Ok(ks) => println!("ks: {:?}",ks)
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::io::{self, Write};

use config::WriteMode;
use rustfmt_diff::{DiffLine, Mismatch};

pub fn output_header<T>(out: &mut T, mode: WriteMode) -> Result<(), io::Error>
where
    T: Write,
{
    if mode == WriteMode::Checkstyle {
        let mut xml_heading = String::new();
        xml_heading.push_str("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
        xml_heading.push_str("\n");
        xml_heading.push_str("<checkstyle version=\"4.3\">");
        write!(out, "{}", xml_heading)?;
    }
    Ok(())
}

pub fn output_footer<T>(out: &mut T, mode: WriteMode) -> Result<(), io::Error>
where
    T: Write,
{
    if mode == WriteMode::Checkstyle {
        let mut xml_tail = String::new();
        xml_tail.push_str("</checkstyle>");
        write!(out, "{}", xml_tail)?;
    }
    Ok(())
}

pub fn output_checkstyle_file<T>(
    mut writer: T,
    filename: &str,
    diff: Vec<Mismatch>,
) -> Result<(), io::Error>
where
    T: Write,
{
    write!(writer, "<file name=\"{}\">", filename)?;
    for mismatch in diff {
        for line in mismatch.lines {
            // Do nothing with `DiffLine::Context` and `DiffLine::Resulting`.
            if let DiffLine::Expected(ref str) = line {
                let message = xml_escape_str(str);
                write!(
                    writer,
                    "<error line=\"{}\" severity=\"warning\" message=\"Should be `{}`\" \
                     />",
                    mismatch.line_number,
                    message
                )?;
            }
        }
    }
    write!(writer, "</file>")?;
    Ok(())
}

// Convert special characters into XML entities.
// This is needed for checkstyle output.
fn xml_escape_str(string: &str) -> String {
    let mut out = String::new();
    for c in string.chars() {
        match c {
            '<' => out.push_str("<"),
            '>' => out.push_str(">"),
            '"' => out.push_str("""),
            '\'' => out.push_str("'"),
            '&' => out.push_str("&"),
            _ => out.push(c),
        }
    }
    out
}
<commit_msg>Fix checkstyle test.<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::io::{self, Write};

use config::WriteMode;
use rustfmt_diff::{DiffLine, Mismatch};

pub fn output_header<T>(out: &mut T, mode: WriteMode) -> Result<(), io::Error>
where
    T: Write,
{
    if mode == WriteMode::Checkstyle {
        let mut xml_heading = String::new();
        xml_heading.push_str("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
        xml_heading.push_str("\n");
        xml_heading.push_str("<checkstyle version=\"4.3\">");
        write!(out, "{}", xml_heading)?;
    }
    Ok(())
}

pub fn output_footer<T>(out: &mut T, mode: WriteMode) -> Result<(), io::Error>
where
    T: Write,
{
    if mode == WriteMode::Checkstyle {
        let mut xml_tail = String::new();
        xml_tail.push_str("</checkstyle>\n");
        write!(out, "{}", xml_tail)?;
    }
    Ok(())
}

pub fn output_checkstyle_file<T>(
    mut writer: T,
    filename: &str,
    diff: Vec<Mismatch>,
) -> Result<(), io::Error>
where
    T: Write,
{
    write!(writer, "<file name=\"{}\">", filename)?;
    for mismatch in diff {
        for line in mismatch.lines {
            // Do nothing with `DiffLine::Context` and `DiffLine::Resulting`.
            if let DiffLine::Expected(ref str) = line {
                let message = xml_escape_str(str);
                write!(
                    writer,
                    "<error line=\"{}\" severity=\"warning\" message=\"Should be `{}`\" \
                     />",
                    mismatch.line_number,
                    message
                )?;
            }
        }
    }
    write!(writer, "</file>")?;
    Ok(())
}

// Convert special characters into XML entities.
// This is needed for checkstyle output.
fn xml_escape_str(string: &str) -> String {
    let mut out = String::new();
    for c in string.chars() {
        match c {
            '<' => out.push_str("<"),
            '>' => out.push_str(">"),
            '"' => out.push_str("""),
            '\'' => out.push_str("'"),
            '&' => out.push_str("&"),
            _ => out.push(c),
        }
    }
    out
}
<|endoftext|>


<commit_before>extern crate stem;

use tokenize::tokenize;
use stem::get;
use std::collections::HashMap;
use std::collections::hashmap::{Occupied, Vacant};

pub struct NaiveBayesClassifier {
  documents: HashMap<String, HashMap<String, uint>>,
  total_document_count: uint
}

impl NaiveBayesClassifier {
  pub fn new() -> NaiveBayesClassifier {
    NaiveBayesClassifier{ documents: HashMap::new(), total_document_count: 0 }
  }

  pub fn train(&mut self, text: String, classification: String) {
    let classification_map = match self.documents.entry(classification) {
      Vacant(entry) => entry.set(HashMap::new()),
      Occupied(entry) => entry.into_mut()
    };

    let stemmed_and_tokenized = get_tokenized_and_stemmed(text);
    for stemmed_word in stemmed_and_tokenized.into_iter() {
      match classification_map.entry(stemmed_word) {
        Vacant(entry) => { entry.set(1); },
        Occupied(mut entry) => *entry.get_mut() += 1
      }
    }
    self.total_document_count += 1;
  }

  pub fn guess(&self, text: String) -> String {
    let stemmed_and_tokenized = get_tokenized_and_stemmed(text);

    let mut label_probabilities = HashMap::new();
    for (k,v) in self.documents.iter() {
      //Get the probability that the passed-in text is each class
      let mut probability: f32 = 0.0;
      for stemmed_word in stemmed_and_tokenized.iter() {
        if v.contains_key(stemmed_word) {
          probability += (1.0 / v.len() as f32).ln();
        }
      }
      if probability.abs() < 0.0001 {
        label_probabilities.insert(k, 0.0);
      }
      else {
        label_probabilities.insert(k, (v.len() as f32 * probability.exp() / self.total_document_count as f32));
      }

    }

    let mut answer_label: String = String::from_str("");
    let mut answer_probability = 0.0;
    for (k,v) in label_probabilities.into_iter() {
      if answer_probability <= v {
        answer_label = k.clone();
        answer_probability = v;
      }
    }

    answer_label
  }
}

fn get_tokenized_and_stemmed(text: String) -> Vec<String> {
  let tokenized_text = tokenize(text.as_slice());
  Vec::from_fn(tokenized_text.len(), |idx| stem::get(tokenized_text[idx]).unwrap())
}<commit_msg>Fixed bug with large datasets resulting in zero probability for naive bayes<commit_after>extern crate stem;

use tokenize::tokenize;
use stem::get;
use std::collections::HashMap;
use std::collections::hashmap::{Occupied, Vacant};

pub struct NaiveBayesClassifier {
  documents: HashMap<String, HashMap<String, uint>>,
  total_document_count: uint
}

impl NaiveBayesClassifier {
  pub fn new() -> NaiveBayesClassifier {
    NaiveBayesClassifier{ documents: HashMap::new(), total_document_count: 0 }
  }

  pub fn train(&mut self, text: String, classification: String) {
    let classification_map = match self.documents.entry(classification) {
      Vacant(entry) => entry.set(HashMap::new()),
      Occupied(entry) => entry.into_mut()
    };

    let stemmed_and_tokenized = get_tokenized_and_stemmed(text);
    for stemmed_word in stemmed_and_tokenized.into_iter() {
      match classification_map.entry(stemmed_word) {
        Vacant(entry) => { entry.set(1); }, // Arm must return ()
        Occupied(mut entry) => *entry.get_mut() += 1
      }
    }
    self.total_document_count += 1;
  }

  pub fn guess(&self, text: String) -> String {
    let stemmed_and_tokenized = get_tokenized_and_stemmed(text);

    let mut label_probabilities = HashMap::new();
    for (k,v) in self.documents.iter() {
      //Get the probability that the passed-in text is each class
      let mut probability: f32 = 0.0;
      for stemmed_word in stemmed_and_tokenized.iter() {
        if v.contains_key(stemmed_word) {
          probability += (1.0 / v.len() as f32).ln();
        }
      }
      if probability.abs() < 0.0001 {
        label_probabilities.insert(k, 0.0);
      }
      else {
        label_probabilities.insert(k, (v.len() as f32 * probability.abs() / self.total_document_count as f32));
      }

    }

    let mut answer_label: String = String::from_str("");
    let mut answer_probability = 0.0;
    for (k,v) in label_probabilities.into_iter() {
      if answer_probability <= v {
        answer_label = k.clone();
        answer_probability = v;
      }
    }

    answer_label
  }
}

fn get_tokenized_and_stemmed(text: String) -> Vec<String> {
  let tokenized_text = tokenize(text.as_slice());
  Vec::from_fn(tokenized_text.len(), |idx| stem::get(tokenized_text[idx]).unwrap())
}<|endoftext|>


<commit_before>//! HTTP Client implementation
//!
//! Currently we aim to provide only HTTP/1.x implementation. We want to
//! provide HTTP/2.0 and TLS implementation with exactly the same protocol.
//! But it's yet unproven if it is possible.
//!
//! Also DNS resolving is not implemented yet.
//!

use std::net::SocketAddr;

use rotor::{Scope, Response, Void};
use rotor::mio::tcp::TcpStream;
use rotor_stream::{Stream};

mod request;
mod head;
mod protocol;
mod parser;
mod context;

pub use self::request::{Request};
pub use self::protocol::Client;
pub use self::head::Head;
pub use self::context::Context;
pub use recvmode::RecvMode;

use self::parser::Parser;

// TODO(tailhook) MAX_HEADERS_SIZE can be moved to Context
// (i.e. made non-constant), but it's more of a problem for MAX_HEADERS_NUM
// because that would mean we can't allocate array of headers on the stack
// so performance will degrade. Customizing MAX_HEADERS_SIZE is not very
// useful on it's own

/// Note httparse requires we preallocate array of this size so be wise
pub const MAX_HEADERS_NUM: usize = 256;
/// This one is not preallocated, but too large buffer is of limited use
/// because of previous parameter.
pub const MAX_HEADERS_SIZE: usize = 16384;
/// Maximum length of chunk size line. it would be okay with 12 bytes, but in
/// theory there might be some extensions which we probably should skip
///
/// Note: we don't have a limit on chunk body size. In buffered request mode
/// it's limited by either memory or artificial limit returned from handler.
/// In unbuffered mode we can process chunk of unlimited size as long as
/// request handler is able to handle it.
pub const MAX_CHUNK_HEAD: usize = 128;

pub type Fsm<P, S> = Stream<Parser<P, S>>;

pub fn connect_tcp<P:Client>(scope: &mut Scope<P::Context>,
    addr: &SocketAddr, req: P)
    -> Response<Fsm<P, TcpStream>, Void>
{
    let sock = match TcpStream::connect(&addr) {
        Ok(sock) => sock,
        Err(e) => return Response::error(Box::new(e)),
    };
    Stream::new(sock, req, scope)
}
<commit_msg>Expose `Persistent`'ly connected http client<commit_after>//! HTTP Client implementation
//!
//! Currently we aim to provide only HTTP/1.x implementation. We want to
//! provide HTTP/2.0 and TLS implementation with exactly the same protocol.
//! But it's yet unproven if it is possible.
//!
//! Also DNS resolving is not implemented yet.
//!

use std::net::SocketAddr;

use rotor::{Scope, Response, Void};
use rotor::mio::tcp::TcpStream;
use rotor_stream;

mod request;
mod head;
mod protocol;
mod parser;
mod context;

pub use self::request::{Request};
pub use self::protocol::Client;
pub use self::head::Head;
pub use self::context::Context;
pub use recvmode::RecvMode;

use self::parser::Parser;

// TODO(tailhook) MAX_HEADERS_SIZE can be moved to Context
// (i.e. made non-constant), but it's more of a problem for MAX_HEADERS_NUM
// because that would mean we can't allocate array of headers on the stack
// so performance will degrade. Customizing MAX_HEADERS_SIZE is not very
// useful on it's own

/// Note httparse requires we preallocate array of this size so be wise
pub const MAX_HEADERS_NUM: usize = 256;
/// This one is not preallocated, but too large buffer is of limited use
/// because of previous parameter.
pub const MAX_HEADERS_SIZE: usize = 16384;
/// Maximum length of chunk size line. it would be okay with 12 bytes, but in
/// theory there might be some extensions which we probably should skip
///
/// Note: we don't have a limit on chunk body size. In buffered request mode
/// it's limited by either memory or artificial limit returned from handler.
/// In unbuffered mode we can process chunk of unlimited size as long as
/// request handler is able to handle it.
pub const MAX_CHUNK_HEAD: usize = 128;

/// A state machine for ad-hoc requests
pub type Fsm<P, S> = rotor_stream::Stream<Parser<P, S>>;
/// A state machine for persistent connections
pub type Persistent<P, S> = rotor_stream::Persistent<Parser<P, S>>;

pub fn connect_tcp<P:Client>(scope: &mut Scope<P::Context>,
    addr: &SocketAddr, req: P)
    -> Response<Fsm<P, TcpStream>, Void>
{
    let sock = match TcpStream::connect(&addr) {
        Ok(sock) => sock,
        Err(e) => return Response::error(Box::new(e)),
    };
    rotor_stream::Stream::new(sock, req, scope)
}
<|endoftext|>


<commit_before>/*
 * I2C Support for the Atmel SAM4L.
 *
 * Uses the TWIM peripheral.
 */

use helpers::*;
use core::mem;

use common::take_cell::TakeCell;

use hil;
use pm;
use dma::{DMAChannel, DMAClient, DMAPeripheral};
use nvic;

// Listing of all registers related to the TWIM peripheral.
// Section 27.9 of the datasheet
#[repr(C, packed)]
#[allow(dead_code)]
struct Registers {
    control:                         usize,
    clock_waveform_generator:        usize,
    smbus_timing:                    usize,
    command:                         usize,
    next_command:                    usize,
    receive_holding:                 usize,
    transmit_holding:                usize,
    status:                          usize,
    interrupt_enable:                usize,
    interrupt_disable:               usize,
    interrupt_mask:                  usize,
    status_clear:                    usize,
    parameter:                       usize,
    version:                         usize,
    hsmode_clock_waveform_generator: usize,
    slew_rate:                       usize,
    hsmod_slew_rate:                 usize
}

// The addresses in memory (7.1 of manual) of the TWIM peripherals
const I2C_BASE_ADDRS: [*mut Registers; 4] =
    [ 0x40018000 as *mut Registers
    , 0x4001C000 as *mut Registers
    , 0x40078000 as *mut Registers
    , 0x4007C000 as *mut Registers];

// There are four TWIM (two wire master interface) peripherals on the SAM4L.
// These likely won't all be used for I2C, but we let the platform decide
// which one to use.
#[derive(Clone,Copy)]
pub enum Location {
    I2C00,  // TWIMS0
    I2C01,  // TWIMS1
    I2C02,  // TWIM2
    I2C03   // TWIM3
}

// Three main I2C speeds
#[derive(Clone,Copy)]
pub enum Speed {
    Standard100k,
    Fast400k,
    FastPlus1M
}

// This is instantiated when an I2C device is created by the device tree.
// This represents an abstraction of the peripheral hardware.
pub struct I2CDevice {
    registers: *mut Registers,  // Pointer to the I2C registers in memory
    clock: pm::Clock,
    dma: TakeCell<&'static DMAChannel>,
    dma_pids: (DMAPeripheral, DMAPeripheral),
    nvic: nvic::NvicIdx,
    client: TakeCell<&'static hil::i2c::I2CClient>,
    on_deck: TakeCell<(DMAPeripheral, usize)>,
}

pub static mut I2C0 : I2CDevice =
    I2CDevice::new(I2C_BASE_ADDRS[0], pm::PBAClock::TWIM0, nvic::NvicIdx::TWIM0,
                   DMAPeripheral::TWIM0_RX, DMAPeripheral::TWIM0_TX);
pub static mut I2C1 : I2CDevice =
    I2CDevice::new(I2C_BASE_ADDRS[1], pm::PBAClock::TWIM1, nvic::NvicIdx::TWIM1,
                   DMAPeripheral::TWIM1_RX, DMAPeripheral::TWIM1_TX);
pub static mut I2C2 : I2CDevice =
    I2CDevice::new(I2C_BASE_ADDRS[2], pm::PBAClock::TWIM2, nvic::NvicIdx::TWIM2,
                   DMAPeripheral::TWIM2_RX, DMAPeripheral::TWIM2_TX);
pub static mut I2C3 : I2CDevice =
    I2CDevice::new(I2C_BASE_ADDRS[3], pm::PBAClock::TWIM3, nvic::NvicIdx::TWIM3,
                   DMAPeripheral::TWIM3_RX, DMAPeripheral::TWIM3_TX);

pub const START : usize = 1 << 13;
pub const STOP : usize = 1 << 14;
pub const ACKLAST : usize = 1 << 24;

// Need to implement the `new` function on the I2C device as a constructor.
// This gets called from the device tree.
impl I2CDevice {
    const fn new(base_addr: *mut Registers, clock: pm::PBAClock,
                 nvic: nvic::NvicIdx,
                 dma_rx: DMAPeripheral, dma_tx: DMAPeripheral) -> I2CDevice {
        I2CDevice {
            registers: base_addr as *mut Registers,
            clock: pm::Clock::PBA(clock),
            dma: TakeCell::empty(),
            dma_pids: (dma_rx, dma_tx),
            nvic: nvic,
            client: TakeCell::empty(),
            on_deck: TakeCell::empty()
        }
    }

    /// Set the clock prescaler and the time widths of the I2C signals
    /// in the CWGR register to make the bus run at a particular I2C speed.
    fn set_bus_speed (&self) {

        // Set the clock speed parameters. This could be made smarter, but for
        // now we just use precomputed constants based on a 48MHz clock.
        // See line 320 in asf-2.31.0/sam/drivers/twim/twim.c for where I
        // got these values.
        // clock_speed / bus_speed / 2
        let (exp, data, stasto, high, low) = (7, 10, 200, 100, 100);

        let cwgr = ((exp & 0x7) << 28) |
                   ((data & 0xF) << 24) |
                   ((stasto & 0xFF) << 16) |
                   ((high & 0xFF) << 8) |
                   ((low & 0xFF) << 0);
        let regs : &mut Registers = unsafe {mem::transmute(self.registers)};
        volatile_store(&mut regs.clock_waveform_generator, cwgr);
    }

    pub fn set_dma(&self, dma: &'static DMAChannel) {
        self.dma.replace(dma);
    }

    pub fn set_client(&self, client: &'static hil::i2c::I2CClient) {
        self.client.replace(client);
    }

    pub fn handle_interrupt(&self) {
        use hil::i2c::Error;
        let regs : &mut Registers = unsafe {mem::transmute(self.registers)};

        let old_status = volatile_load(&regs.status);

        volatile_store(&mut regs.command, 0);
        volatile_store(&mut regs.next_command, 0);
        volatile_store(&mut regs.status_clear, !0);

        let err = match old_status {
            x if x & (1 <<  8) != 0 /*ANACK*/  => Some(Error::AddressNak),
            x if x & (1 <<  9) != 0 /*DNACK*/  => Some(Error::DataNak),
            x if x & (1 << 10) != 0 /*ARBLST*/ => Some(Error::ArbitrationLost),
            x if x & (1 <<  3) != 0 /*CCOMP*/   => Some(Error::CommandComplete),
            _ => None
        };

        err.map(|err| {
            // enable, reset, disable
            volatile_store(&mut regs.control, 0x1 << 0);
            volatile_store(&mut regs.control, 0x1 << 7);
            volatile_store(&mut regs.control, 0x1 << 1);

            self.client.map(|client| {
                let buf = match self.dma.take() {
                    Some(dma) => {
                        let b = dma.abort_xfer();
                        self.dma.replace(dma);
                        b
                    },
                    None => None
                };
                buf.map(|buf| {
                    client.command_complete(buf, err);
                });
            });
        });
    }

    fn setup_xfer(&self, chip: u8, flags: usize, read: bool, len: u8) {
        let regs : &mut Registers = unsafe {mem::transmute(self.registers)};

        // disable before configuring
        volatile_store(&mut regs.control, 0x1 << 1);

        let read = if read { 1 } else { 0 };
        let command = (0 << 1) // Not read
                    | ((chip as usize) << 1) // 7 bit address at offset 1 (8th
                                             // bit is ignored anyway)
                    | flags  // START, STOP & ACKLAST flags
                    | (1 << 15) // VALID
                    | (len as usize) << 16 // NBYTES (at most 255)
                    | read;
        volatile_store(&mut regs.command, command);
        volatile_store(&mut regs.next_command, 0);

        // Enable to begin transfer
        volatile_store(&mut regs.control, 0x1 << 0);

        // Enable transaction error interrupts
        volatile_store(&mut regs.interrupt_enable,
                         (1 << 3)    // CCOMP   - Command completed
                       | (1 << 8)    // ANAK   - Address not ACKd
                       | (1 << 9)    // DNAK   - Data not ACKd
                       | (1 << 10)); // ARBLST - Abitration lost
    }

    fn setup_nextfer(&self, chip: u8, flags: usize, read: bool, len: u8) {
        let regs : &mut Registers = unsafe {mem::transmute(self.registers)};

        // disable before configuring
        volatile_store(&mut regs.control, 0x1 << 1);

        let read = if read { 1 } else { 0 };
        let command = (0 << 1) // Not read
                    | ((chip as usize) << 1) // 7 bit address at offset 1 (8th
                                             // bit is ignored anyway)
                    | flags  // START, STOP & ACKLAST flags
                    | (1 << 15) // VALID
                    | (len as usize) << 16 // NBYTES (at most 255)
                    | read;
        volatile_store(&mut regs.next_command, command);

        // Enable
        volatile_store(&mut regs.control, 0x1 << 0);
    }

    pub fn write(&self, chip: u8, flags: usize, data: &'static mut [u8], len: u8) {
        self.dma.map(move |dma| {
            dma.enable();
            dma.prepare_xfer(self.dma_pids.1, data, len as usize);
            self.setup_xfer(chip, flags, false, len);
            dma.start_xfer();
        });
    }

    pub fn read(&self, chip: u8, flags: usize, data: &'static mut [u8], len: u8) {
        self.dma.map(move |dma| {
            dma.enable();
            dma.prepare_xfer(self.dma_pids.0, data, len as usize);
            self.setup_xfer(chip, flags, true, len);
            dma.start_xfer();
        });
    }

    pub fn write_read(&self, chip: u8, data: &'static mut [u8], split: u8, read_len: u8) {
        self.dma.map(move |dma| {
           dma.enable();
           dma.prepare_xfer(self.dma_pids.1, data, split as usize);
           self.setup_xfer(chip, START, false, split);
           self.setup_nextfer(chip, START | STOP, true, read_len);
           self.on_deck.replace(
               (self.dma_pids.0, read_len as usize)
           );
           dma.start_xfer();
        });
    }

    fn enable_interrupts(&self) {
        unsafe {
            nvic::enable(self.nvic);
        }
    }

    fn disable_interrupts(&self) {
        let regs : &mut Registers = unsafe {mem::transmute(self.registers)};
        volatile_store(&mut regs.interrupt_disable, !0);
        unsafe {
            nvic::disable(self.nvic);
        }
    }
}

impl DMAClient for I2CDevice {
    fn xfer_done(&mut self, _pid: usize) {
        self.on_deck.take().map(|(dma_periph, len)| {
            self.dma.map(|dma| {
                let buf = dma.abort_xfer().unwrap();
                dma.prepare_xfer(dma_periph, buf, len);
                dma.start_xfer();
            });
        });
    }
}

impl hil::i2c::I2C for I2CDevice {

    /// This enables the entire I2C peripheral
    fn enable(&self) {
        // Enable the clock for the TWIM module
        unsafe {
            pm::enable_clock(self.clock);
        }

        let regs : &mut Registers = unsafe {mem::transmute(self.registers)};

        // enable, reset, disable
        volatile_store(&mut regs.control, 0x1 << 0);
        volatile_store(&mut regs.control, 0x1 << 7);
        volatile_store(&mut regs.control, 0x1 << 1);

        // Init the bus speed
        self.set_bus_speed();

        // slew
        volatile_store(&mut regs.slew_rate, (0x2 << 28) | (7<<16) | (7<<0));

        // clear interrupts
        volatile_store(&mut regs.status_clear, !0);

        self.enable_interrupts();
    }

    /// This disables the entire I2C peripheral
    fn disable (&self) {
        let regs : &mut Registers = unsafe {mem::transmute(self.registers)};
        volatile_store(&mut regs.control, 0x1 << 1);
        unsafe {
            pm::disable_clock(self.clock);
        }
        self.disable_interrupts();
    }

    fn write(&self, addr: u8, data: &'static mut [u8], len: u8) {
        I2CDevice::write(self, addr, START | STOP, data, len);
    }

    fn read(&self, addr: u8, data: &'static mut [u8], len: u8) {
        I2CDevice::read(self, addr, START | STOP, data, len);
    }
}

pub unsafe extern "C" fn twim2_interrupt() {
    use chip;
    use common::Queue;

    let dev = &I2C2;
    dev.disable_interrupts();
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(dev.nvic);
}

<commit_msg>I2C: Progress on repeated starts<commit_after>/*
 * I2C Support for the Atmel SAM4L.
 *
 * Uses the TWIM peripheral.
 */

use helpers::*;
use core::mem;

use common::take_cell::TakeCell;

use hil;
use pm;
use dma::{DMAChannel, DMAClient, DMAPeripheral};
use nvic;

// Listing of all registers related to the TWIM peripheral.
// Section 27.9 of the datasheet
#[repr(C, packed)]
#[allow(dead_code)]
struct Registers {
    control:                         usize,
    clock_waveform_generator:        usize,
    smbus_timing:                    usize,
    command:                         usize,
    next_command:                    usize,
    receive_holding:                 usize,
    transmit_holding:                usize,
    status:                          usize,
    interrupt_enable:                usize,
    interrupt_disable:               usize,
    interrupt_mask:                  usize,
    status_clear:                    usize,
    parameter:                       usize,
    version:                         usize,
    hsmode_clock_waveform_generator: usize,
    slew_rate:                       usize,
    hsmod_slew_rate:                 usize
}

// The addresses in memory (7.1 of manual) of the TWIM peripherals
const I2C_BASE_ADDRS: [*mut Registers; 4] =
    [ 0x40018000 as *mut Registers
    , 0x4001C000 as *mut Registers
    , 0x40078000 as *mut Registers
    , 0x4007C000 as *mut Registers];

// There are four TWIM (two wire master interface) peripherals on the SAM4L.
// These likely won't all be used for I2C, but we let the platform decide
// which one to use.
#[derive(Clone,Copy)]
pub enum Location {
    I2C00,  // TWIMS0
    I2C01,  // TWIMS1
    I2C02,  // TWIM2
    I2C03   // TWIM3
}

// Three main I2C speeds
#[derive(Clone,Copy)]
pub enum Speed {
    Standard100k,
    Fast400k,
    FastPlus1M
}

// This is instantiated when an I2C device is created by the device tree.
// This represents an abstraction of the peripheral hardware.
pub struct I2CDevice {
    registers: *mut Registers,  // Pointer to the I2C registers in memory
    clock: pm::Clock,
    dma: TakeCell<&'static DMAChannel>,
    dma_pids: (DMAPeripheral, DMAPeripheral),
    nvic: nvic::NvicIdx,
    client: TakeCell<&'static hil::i2c::I2CClient>,
    on_deck: TakeCell<(DMAPeripheral, usize)>,
}

pub static mut I2C0 : I2CDevice =
    I2CDevice::new(I2C_BASE_ADDRS[0], pm::PBAClock::TWIM0, nvic::NvicIdx::TWIM0,
                   DMAPeripheral::TWIM0_RX, DMAPeripheral::TWIM0_TX);
pub static mut I2C1 : I2CDevice =
    I2CDevice::new(I2C_BASE_ADDRS[1], pm::PBAClock::TWIM1, nvic::NvicIdx::TWIM1,
                   DMAPeripheral::TWIM1_RX, DMAPeripheral::TWIM1_TX);
pub static mut I2C2 : I2CDevice =
    I2CDevice::new(I2C_BASE_ADDRS[2], pm::PBAClock::TWIM2, nvic::NvicIdx::TWIM2,
                   DMAPeripheral::TWIM2_RX, DMAPeripheral::TWIM2_TX);
pub static mut I2C3 : I2CDevice =
    I2CDevice::new(I2C_BASE_ADDRS[3], pm::PBAClock::TWIM3, nvic::NvicIdx::TWIM3,
                   DMAPeripheral::TWIM3_RX, DMAPeripheral::TWIM3_TX);

pub const START : usize = 1 << 13;
pub const STOP : usize = 1 << 14;
pub const ACKLAST : usize = 1 << 24;

// Need to implement the `new` function on the I2C device as a constructor.
// This gets called from the device tree.
impl I2CDevice {
    const fn new(base_addr: *mut Registers, clock: pm::PBAClock,
                 nvic: nvic::NvicIdx,
                 dma_rx: DMAPeripheral, dma_tx: DMAPeripheral) -> I2CDevice {
        I2CDevice {
            registers: base_addr as *mut Registers,
            clock: pm::Clock::PBA(clock),
            dma: TakeCell::empty(),
            dma_pids: (dma_rx, dma_tx),
            nvic: nvic,
            client: TakeCell::empty(),
            on_deck: TakeCell::empty()
        }
    }

    /// Set the clock prescaler and the time widths of the I2C signals
    /// in the CWGR register to make the bus run at a particular I2C speed.
    fn set_bus_speed (&self) {

        // Set the clock speed parameters. This could be made smarter, but for
        // now we just use precomputed constants based on a 48MHz clock.
        // See line 320 in asf-2.31.0/sam/drivers/twim/twim.c for where I
        // got these values.
        // clock_speed / bus_speed / 2
        let (exp, data, stasto, high, low) = (7, 10, 200, 100, 100);

        let cwgr = ((exp & 0x7) << 28) |
                   ((data & 0xF) << 24) |
                   ((stasto & 0xFF) << 16) |
                   ((high & 0xFF) << 8) |
                   ((low & 0xFF) << 0);
        let regs : &mut Registers = unsafe {mem::transmute(self.registers)};
        volatile_store(&mut regs.clock_waveform_generator, cwgr);
    }

    pub fn set_dma(&self, dma: &'static DMAChannel) {
        self.dma.replace(dma);
    }

    pub fn set_client(&self, client: &'static hil::i2c::I2CClient) {
        self.client.replace(client);
    }

    pub fn handle_interrupt(&self) {
        use hil::i2c::Error;
        let regs : &mut Registers = unsafe {mem::transmute(self.registers)};

        let old_status = volatile_load(&regs.status);

        volatile_store(&mut regs.status_clear, !0);

        let err = match old_status {
            x if x & (1 <<  8) != 0 /*ANACK*/  => Some(Error::AddressNak),
            x if x & (1 <<  9) != 0 /*DNACK*/  => Some(Error::DataNak),
            x if x & (1 << 10) != 0 /*ARBLST*/ => Some(Error::ArbitrationLost),
            x if x & (1 <<  3) != 0 /*CCOMP*/   => Some(Error::CommandComplete),
            _ => None
        };

        match self.on_deck.take() {
            None => {
                volatile_store(&mut regs.command, 0);
                volatile_store(&mut regs.next_command, 0);

                err.map(|err| {
                    // enable, reset, disable
                    volatile_store(&mut regs.control, 0x1 << 0);
                    volatile_store(&mut regs.control, 0x1 << 7);
                    volatile_store(&mut regs.control, 0x1 << 1);

                    self.client.map(|client| {
                        let buf = match self.dma.take() {
                            Some(dma) => {
                                let b = dma.abort_xfer();
                                self.dma.replace(dma);
                                b
                            },
                            None => None
                        };
                        buf.map(|buf| {
                            client.command_complete(buf, err);
                        });
                    });
                });
            },
            Some((dma_periph, len)) => {
                self.dma.map(|dma| {
                    let buf = dma.abort_xfer().unwrap();
                    dma.prepare_xfer(dma_periph, buf, len + 1);
                    dma.start_xfer();
                    while dma.transfer_counter() > 1 {}
                    let ctr = dma.transfer_counter();
                    let old_status = volatile_load(&regs.status);
                    while old_status == volatile_load(&regs.status) {}
                    panic!("Changed! 0x{:x}", regs.status);
                    //let cmdr = volatile_load(&regs.command);
                    //let ncmdr = volatile_load(&regs.next_command);
                    //panic!("0x{:x} 0x{:x} 0x{:x} 0x{:x} {}", old_status, status, cmdr, ncmdr, ctr);
                    // EXPL(alevy): We seem to be able to get here in a repeated
                    // start. The DMA counter doesn't seem to like to get all
                    // the way down to 0, and even though the status eventually
                    // changes to have a CCOMP, it doesn't see to fire the
                    // interrupt (or at least call handle_interrupt).
                });
            }
        }
    }

    fn setup_xfer(&self, chip: u8, flags: usize, read: bool, len: u8) {
        let regs : &mut Registers = unsafe {mem::transmute(self.registers)};

        // disable before configuring
        volatile_store(&mut regs.control, 0x1 << 1);

        let read = if read { 1 } else { 0 };
        let command = ((chip as usize) << 1) // 7 bit address at offset 1 (8th
                                             // bit is ignored anyway)
                    | flags  // START, STOP & ACKLAST flags
                    | (1 << 15) // VALID
                    | (len as usize) << 16 // NBYTES (at most 255)
                    | read;
        volatile_store(&mut regs.command, command);
        volatile_store(&mut regs.next_command, 0);

        // Enable transaction error interrupts
        volatile_store(&mut regs.interrupt_enable,
                         (1 << 3)    // CCOMP   - Command completed
                       | (1 << 8)    // ANAK   - Address not ACKd
                       | (1 << 9)    // DNAK   - Data not ACKd
                       | (1 << 10)); // ARBLST - Abitration lost
    }

    fn setup_nextfer(&self, chip: u8, flags: usize, read: bool, len: u8) {
        let regs : &mut Registers = unsafe {mem::transmute(self.registers)};

        // disable before configuring
        volatile_store(&mut regs.control, 0x1 << 1);

        let read = if read { 1 } else { 0 };
        let command = ((chip as usize) << 1) // 7 bit address at offset 1 (8th
                                             // bit is ignored anyway)
                    | flags  // START, STOP & ACKLAST flags
                    | (1 << 15) // VALID
                    | (len as usize) << 16 // NBYTES (at most 255)
                    | read;
        volatile_store(&mut regs.next_command, command);

        // Enable
        volatile_store(&mut regs.control, 0x1 << 0);
    }

    fn master_enable(&self) {
        let regs : &mut Registers = unsafe {mem::transmute(self.registers)};

        // Enable to begin transfer
        volatile_store(&mut regs.control, 0x1 << 0);

    }

    pub fn write(&self, chip: u8, flags: usize, data: &'static mut [u8], len: u8) {
        self.dma.map(move |dma| {
            dma.enable();
            dma.prepare_xfer(self.dma_pids.1, data, len as usize);
            self.setup_xfer(chip, flags, false, len);
            self.master_enable();
            dma.start_xfer();
        });
    }

    pub fn read(&self, chip: u8, flags: usize, data: &'static mut [u8], len: u8) {
        self.dma.map(move |dma| {
            dma.enable();
            dma.prepare_xfer(self.dma_pids.0, data, len as usize);
            self.setup_xfer(chip, flags, true, len);
            self.master_enable();
            dma.start_xfer();
        });
    }

    pub fn write_read(&self, chip: u8, data: &'static mut [u8], split: u8, read_len: u8) {
        self.dma.map(move |dma| {
           dma.enable();
           dma.prepare_xfer(self.dma_pids.1, data, split as usize);
           self.setup_xfer(chip, START, false, split);
           self.setup_nextfer(chip, START | STOP, true, read_len);
           self.on_deck.replace(
               (self.dma_pids.0, read_len as usize)
           );
           dma.start_xfer();
        });
    }

    fn enable_interrupts(&self) {
        unsafe {
            nvic::enable(self.nvic);
        }
    }

    fn disable_interrupts(&self) {
        let regs : &mut Registers = unsafe {mem::transmute(self.registers)};
        volatile_store(&mut regs.interrupt_disable, !0);
        unsafe {
            nvic::disable(self.nvic);
        }
    }
}

impl DMAClient for I2CDevice {
    fn xfer_done(&mut self, _pid: usize) {
        self.on_deck.take().map(|(dma_periph, len)| {
            self.dma.map(|dma| {
                let buf = dma.abort_xfer().unwrap();
                dma.prepare_xfer(dma_periph, buf, len);
                dma.start_xfer();
            });
        });
    }
}

impl hil::i2c::I2C for I2CDevice {

    /// This enables the entire I2C peripheral
    fn enable(&self) {
        // Enable the clock for the TWIM module
        unsafe {
            pm::enable_clock(self.clock);
        }

        let regs : &mut Registers = unsafe {mem::transmute(self.registers)};

        // enable, reset, disable
        volatile_store(&mut regs.control, 0x1 << 0);
        volatile_store(&mut regs.control, 0x1 << 7);
        volatile_store(&mut regs.control, 0x1 << 1);

        // Init the bus speed
        self.set_bus_speed();

        // slew
        volatile_store(&mut regs.slew_rate, (0x2 << 28) | (7<<16) | (7<<0));

        // clear interrupts
        volatile_store(&mut regs.status_clear, !0);

        self.enable_interrupts();
    }

    /// This disables the entire I2C peripheral
    fn disable (&self) {
        let regs : &mut Registers = unsafe {mem::transmute(self.registers)};
        volatile_store(&mut regs.control, 0x1 << 1);
        unsafe {
            pm::disable_clock(self.clock);
        }
        self.disable_interrupts();
    }

    fn write(&self, addr: u8, data: &'static mut [u8], len: u8) {
        I2CDevice::write(self, addr, START | STOP, data, len);
    }

    fn read(&self, addr: u8, data: &'static mut [u8], len: u8) {
        I2CDevice::read(self, addr, START | STOP, data, len);
    }
}

pub unsafe extern "C" fn twim2_interrupt() {
    use chip;
    use common::Queue;

    let dev = &I2C2;
    dev.disable_interrupts();
    chip::INTERRUPT_QUEUE.as_mut().unwrap().enqueue(dev.nvic);
}

<|endoftext|>