<commit_before>use tf;
use libc::c_int;
use std::marker;
use std::ptr;
use super::Code;
use super::DataType;
use super::Graph;
use super::GraphTrait;
use super::Operation;
use super::OperationTrait;
use super::Result;
use super::SessionOptions;
use super::Status;
use super::Tensor;
use super::TensorType;

/// Manages a single graph and execution.
#[derive(Debug)]
pub struct Session {
    inner: *mut tf::TF_Session,
}

impl Session {
    /// Creates a session.
    pub fn new(options: &SessionOptions, graph: &Graph) -> Result<Self> {
        let mut status = Status::new();
        let inner = unsafe { tf::TF_NewSession(graph.inner(), options.inner, status.inner()) };
        if inner.is_null() {
            Err(status)
        } else {
            Ok(Session { inner: inner })
        }
    }

    /// Closes the session.
    pub fn close(&mut self) -> Result<()> {
        let mut status = Status::new();
        unsafe {
            tf::TF_CloseSession(self.inner, status.inner());
        }
        status.into_result()
    }

    /// Runs the graph, feeding the inputs and then fetching the outputs requested in the step.
    pub fn run(&mut self, step: &mut StepWithGraph) -> Result<()> {
        // Copy the input tensors because TF_Run consumes them.
        let mut input_tensors = Vec::with_capacity(step.input_tensors.len());
        for &input_tensor in &step.input_tensors {
            unsafe {
                let mut dims = Vec::with_capacity(tf::TF_NumDims(input_tensor) as usize);
                for i in 0..dims.capacity() {
                    dims.push(tf::TF_Dim(input_tensor, i as c_int));
                }
                input_tensors.push(tf::TF_NewTensor(tf::TF_TensorType(input_tensor),
                                                    dims.as_ptr(),
                                                    dims.len() as c_int,
                                                    tf::TF_TensorData(input_tensor),
                                                    tf::TF_TensorByteSize(input_tensor),
                                                    Some(super::noop_deallocator),
                                                    ptr::null_mut()));
            }
        }

        // In case we're running it a second time and not all outputs were taken out.
        step.drop_output_tensors();

        let mut status = Status::new();
        unsafe {
            tf::TF_SessionRun(self.inner,
                              ptr::null(),
                              step.input_ports.as_ptr(),
                              input_tensors.as_mut_ptr(),
                              input_tensors.len() as c_int,
                              step.output_ports.as_ptr(),
                              step.output_tensors.as_mut_ptr(),
                              step.output_tensors.len() as c_int,
                              step.target_operations.as_mut_ptr(),
                              step.target_operations.len() as c_int,
                              ptr::null_mut(),
                              status.inner());
        };
        status.into_result()
    }
}

impl Drop for Session {
    fn drop(&mut self) {
        let mut status = Status::new();
        unsafe {
            tf::TF_DeleteSession(self.inner, status.inner());
        }
        // TODO: What do we do with the status?
    }
}

////////////////////////

/// An opaque token for retrieving an output from a computation.
#[derive(Copy,Clone,Debug)]
pub struct OutputToken {
    index: usize,
}

/// Manages the inputs and outputs for a single execution of a graph.
///
/// Typical usage involves creating an instance of this struct,
/// adding some inputs to it, requesting some outputs, passing it to `Session::run`
/// and then taking the outputs out of it.
///
/// This will be renamed to Step once the old API goes away.
#[derive(Debug)]
pub struct StepWithGraph<'l> {
    input_ports: Vec<tf::TF_Output>,
    input_tensors: Vec<*mut tf::TF_Tensor>,

    output_ports: Vec<tf::TF_Output>,
    output_tensors: Vec<*mut tf::TF_Tensor>,

    target_operations: Vec<*const tf::TF_Operation>,

    phantom: marker::PhantomData<&'l ()>,
}

impl<'l> StepWithGraph<'l> {
    /// Creates a StepWithGraph.
    pub fn new() -> Self {
        StepWithGraph {
            input_ports: vec![],
            input_tensors: vec![],

            output_ports: vec![],
            output_tensors: vec![],

            target_operations: vec![],

            phantom: marker::PhantomData,
        }
    }

    /// Adds an input to be fed to the graph.
    pub fn add_input<T: TensorType>(&mut self,
                                    operation: &Operation,
                                    index: c_int,
                                    tensor: &'l Tensor<T>) {
        self.input_ports.push(tf::TF_Output {
            oper: operation.inner(),
            index: index,
        });
        self.input_tensors.push(tensor.inner);
    }

    /// Requests that an output is fetched from the graph after running this step.
    /// Returns an index that you can then use to fetch this output from the step after running it.
    pub fn request_output(&mut self, operation: &Operation, index: c_int) -> OutputToken {
        self.output_ports.push(tf::TF_Output {
            oper: operation.inner(),
            index: index,
        });
        self.output_tensors.push(ptr::null_mut());
        OutputToken { index: self.output_tensors.len() - 1 }
    }

    /// Extracts a tensor output given an index. A given index can only be extracted
    /// once per `Session::run`.
    /// Returns an error if output_idx is out of range, output is unavailable or the
    /// requested type does not match the type of the actual tensor.
    pub fn take_output<T: TensorType>(&mut self, token: OutputToken) -> Result<Tensor<T>> {
        let output_idx = token.index;
        if output_idx >= self.output_tensors.len() {
            return Err(Status::new_set(Code::OutOfRange,
                                       &format!("Requested output index is out of range: {} vs \
                                                 {}",
                                                output_idx,
                                                self.output_tensors.len()))
                .unwrap());
        }
        if self.output_tensors[output_idx].is_null() {
            return Err(Status::new_set(Code::Unavailable,
                                       "Output not available. Either it was already taken, or \
                                        this step has not been sucessfully run yet.")
                .unwrap());
        }
        let actual_data_type = self.output_data_type(output_idx).unwrap();
        if actual_data_type != T::data_type() {
            return Err(invalid_arg!("Requested tensor type does not match actual tensor type: \
                                     {} vs {}",
                                    actual_data_type,
                                    T::data_type()));
        }
        let tensor = unsafe { Tensor::from_tf_tensor(self.output_tensors[output_idx]).unwrap() };
        self.output_tensors[output_idx] = ptr::null_mut();
        Ok(tensor)
    }

    /// Adds a target operation to be executed when running the graph.
    pub fn add_target(&mut self, operation: &Operation) {
        self.target_operations.push(operation.inner());
    }

    /// Retuns the type of the tensor given an index.
    /// Returns `None` if the index is out of range or the output is not yet available.
    pub fn output_data_type(&self, output_idx: usize) -> Option<DataType> {
        if output_idx >= self.output_tensors.len() {
            return None;
        }
        if self.output_tensors[output_idx].is_null() {
            return None;
        }
        unsafe { Some(DataType::from_c(tf::TF_TensorType(self.output_tensors[output_idx]))) }
    }

    fn drop_output_tensors(&mut self) {
        for mut tensor in &mut self.output_tensors {
            // TODO: Is TF_DeleteTensor NULL safe?
            if !tensor.is_null() {
                unsafe {
                    tf::TF_DeleteTensor(*tensor);
                }
            }
            *tensor = ptr::null_mut();
        }
    }
}

impl<'l> Drop for StepWithGraph<'l> {
    fn drop(&mut self) {
        self.drop_output_tensors();
    }
}

////////////////////////

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::DataType;
    use super::super::Graph;
    use super::super::Operation;
    use super::super::Output;
    use super::super::SessionOptions;
    use super::super::Shape;
    use super::super::Tensor;

    fn create_session() -> (Session, Operation, Operation) {
        let mut g = Graph::new();
        let two = {
            let mut nd = g.new_operation("Const", "two").unwrap();
            nd.set_attr_type("dtype", DataType::Float).unwrap();
            let mut value = Tensor::new(&[1]);
            value[0] = 2.0f32;
            nd.set_attr_tensor("value", value).unwrap();
            nd.finish().unwrap()
        };
        let x = {
            let mut nd = g.new_operation("Placeholder", "x").unwrap();
            nd.set_attr_type("dtype", DataType::Float).unwrap();
            nd.set_attr_shape("shape", &Shape(Some(vec![]))).unwrap();
            nd.finish().unwrap()
        };
        let y = {
            let mut nd = g.new_operation("Mul", "y").unwrap();
            nd.add_input(Output {
                operation: &two,
                index: 0,
            });
            nd.add_input(Output {
                operation: &x,
                index: 0,
            });
            nd.finish().unwrap()
        };
        let options = SessionOptions::new();
        match Session::new(&options, &g) {
            Ok(session) => (session, x, y),
            Err(status) => panic!("Creating session failed with status: {}", status),
        }
    }

    #[test]
    fn smoke() {
        create_session();
    }

    #[test]
    fn test_close() {
        let (mut session, _, _) = create_session();
        let status = session.close();
        assert!(status.is_ok());
    }

    #[test]
    fn test_run() {
        let (mut session, x_operation, y_operation) = create_session();
        let mut x = <Tensor<f32>>::new(&[2]);
        x[0] = 2.0;
        x[1] = 3.0;
        let mut step = StepWithGraph::new();
        step.add_input(&x_operation, 0, &x);
        let output_token = step.request_output(&y_operation, 0);
        session.run(&mut step).unwrap();
        let output_tensor = step.take_output::<f32>(output_token).unwrap();
        let data = output_tensor.data();
        assert_eq!(data.len(), 2);
        assert_eq!(data[0], 4.0);
        assert_eq!(data[1], 6.0);
    }
}
<commit_msg>bindgen-generated `TF_SessionRun()` takes a `*const *const TF_Tensor`<commit_after>use tf;
use libc::c_int;
use std::marker;
use std::ptr;
use super::Code;
use super::DataType;
use super::Graph;
use super::GraphTrait;
use super::Operation;
use super::OperationTrait;
use super::Result;
use super::SessionOptions;
use super::Status;
use super::Tensor;
use super::TensorType;

/// Manages a single graph and execution.
#[derive(Debug)]
pub struct Session {
    inner: *mut tf::TF_Session,
}

impl Session {
    /// Creates a session.
    pub fn new(options: &SessionOptions, graph: &Graph) -> Result<Self> {
        let mut status = Status::new();
        let inner = unsafe { tf::TF_NewSession(graph.inner(), options.inner, status.inner()) };
        if inner.is_null() {
            Err(status)
        } else {
            Ok(Session { inner: inner })
        }
    }

    /// Closes the session.
    pub fn close(&mut self) -> Result<()> {
        let mut status = Status::new();
        unsafe {
            tf::TF_CloseSession(self.inner, status.inner());
        }
        status.into_result()
    }

    /// Runs the graph, feeding the inputs and then fetching the outputs requested in the step.
    pub fn run(&mut self, step: &mut StepWithGraph) -> Result<()> {
        // Copy the input tensors because TF_Run consumes them.
        let mut input_tensors = Vec::with_capacity(step.input_tensors.len());
        for &input_tensor in &step.input_tensors {
            unsafe {
                let mut dims = Vec::with_capacity(tf::TF_NumDims(input_tensor) as usize);
                for i in 0..dims.capacity() {
                    dims.push(tf::TF_Dim(input_tensor, i as c_int));
                }
                input_tensors.push(tf::TF_NewTensor(tf::TF_TensorType(input_tensor),
                                                    dims.as_ptr(),
                                                    dims.len() as c_int,
                                                    tf::TF_TensorData(input_tensor),
                                                    tf::TF_TensorByteSize(input_tensor),
                                                    Some(super::noop_deallocator),
                                                    ptr::null_mut()));
            }
        }

        // In case we're running it a second time and not all outputs were taken out.
        step.drop_output_tensors();

        let mut status = Status::new();
        unsafe {
            tf::TF_SessionRun(self.inner,
                              ptr::null(),
                              step.input_ports.as_ptr(),
                              input_tensors.as_ptr() as *const *const tf::TF_Tensor,
                              input_tensors.len() as c_int,
                              step.output_ports.as_ptr(),
                              step.output_tensors.as_mut_ptr(),
                              step.output_tensors.len() as c_int,
                              step.target_operations.as_mut_ptr(),
                              step.target_operations.len() as c_int,
                              ptr::null_mut(),
                              status.inner());
        };
        status.into_result()
    }
}

impl Drop for Session {
    fn drop(&mut self) {
        let mut status = Status::new();
        unsafe {
            tf::TF_DeleteSession(self.inner, status.inner());
        }
        // TODO: What do we do with the status?
    }
}

////////////////////////

/// An opaque token for retrieving an output from a computation.
#[derive(Copy,Clone,Debug)]
pub struct OutputToken {
    index: usize,
}

/// Manages the inputs and outputs for a single execution of a graph.
///
/// Typical usage involves creating an instance of this struct,
/// adding some inputs to it, requesting some outputs, passing it to `Session::run`
/// and then taking the outputs out of it.
///
/// This will be renamed to Step once the old API goes away.
#[derive(Debug)]
pub struct StepWithGraph<'l> {
    input_ports: Vec<tf::TF_Output>,
    input_tensors: Vec<*mut tf::TF_Tensor>,

    output_ports: Vec<tf::TF_Output>,
    output_tensors: Vec<*mut tf::TF_Tensor>,

    target_operations: Vec<*const tf::TF_Operation>,

    phantom: marker::PhantomData<&'l ()>,
}

impl<'l> StepWithGraph<'l> {
    /// Creates a StepWithGraph.
    pub fn new() -> Self {
        StepWithGraph {
            input_ports: vec![],
            input_tensors: vec![],

            output_ports: vec![],
            output_tensors: vec![],

            target_operations: vec![],

            phantom: marker::PhantomData,
        }
    }

    /// Adds an input to be fed to the graph.
    pub fn add_input<T: TensorType>(&mut self,
                                    operation: &Operation,
                                    index: c_int,
                                    tensor: &'l Tensor<T>) {
        self.input_ports.push(tf::TF_Output {
            oper: operation.inner(),
            index: index,
        });
        self.input_tensors.push(tensor.inner);
    }

    /// Requests that an output is fetched from the graph after running this step.
    /// Returns an index that you can then use to fetch this output from the step after running it.
    pub fn request_output(&mut self, operation: &Operation, index: c_int) -> OutputToken {
        self.output_ports.push(tf::TF_Output {
            oper: operation.inner(),
            index: index,
        });
        self.output_tensors.push(ptr::null_mut());
        OutputToken { index: self.output_tensors.len() - 1 }
    }

    /// Extracts a tensor output given an index. A given index can only be extracted
    /// once per `Session::run`.
    /// Returns an error if output_idx is out of range, output is unavailable or the
    /// requested type does not match the type of the actual tensor.
    pub fn take_output<T: TensorType>(&mut self, token: OutputToken) -> Result<Tensor<T>> {
        let output_idx = token.index;
        if output_idx >= self.output_tensors.len() {
            return Err(Status::new_set(Code::OutOfRange,
                                       &format!("Requested output index is out of range: {} vs \
                                                 {}",
                                                output_idx,
                                                self.output_tensors.len()))
                .unwrap());
        }
        if self.output_tensors[output_idx].is_null() {
            return Err(Status::new_set(Code::Unavailable,
                                       "Output not available. Either it was already taken, or \
                                        this step has not been sucessfully run yet.")
                .unwrap());
        }
        let actual_data_type = self.output_data_type(output_idx).unwrap();
        if actual_data_type != T::data_type() {
            return Err(invalid_arg!("Requested tensor type does not match actual tensor type: \
                                     {} vs {}",
                                    actual_data_type,
                                    T::data_type()));
        }
        let tensor = unsafe { Tensor::from_tf_tensor(self.output_tensors[output_idx]).unwrap() };
        self.output_tensors[output_idx] = ptr::null_mut();
        Ok(tensor)
    }

    /// Adds a target operation to be executed when running the graph.
    pub fn add_target(&mut self, operation: &Operation) {
        self.target_operations.push(operation.inner());
    }

    /// Retuns the type of the tensor given an index.
    /// Returns `None` if the index is out of range or the output is not yet available.
    pub fn output_data_type(&self, output_idx: usize) -> Option<DataType> {
        if output_idx >= self.output_tensors.len() {
            return None;
        }
        if self.output_tensors[output_idx].is_null() {
            return None;
        }
        unsafe { Some(DataType::from_c(tf::TF_TensorType(self.output_tensors[output_idx]))) }
    }

    fn drop_output_tensors(&mut self) {
        for mut tensor in &mut self.output_tensors {
            // TODO: Is TF_DeleteTensor NULL safe?
            if !tensor.is_null() {
                unsafe {
                    tf::TF_DeleteTensor(*tensor);
                }
            }
            *tensor = ptr::null_mut();
        }
    }
}

impl<'l> Drop for StepWithGraph<'l> {
    fn drop(&mut self) {
        self.drop_output_tensors();
    }
}

////////////////////////

#[cfg(test)]
mod tests {
    use super::*;
    use super::super::DataType;
    use super::super::Graph;
    use super::super::Operation;
    use super::super::Output;
    use super::super::SessionOptions;
    use super::super::Shape;
    use super::super::Tensor;

    fn create_session() -> (Session, Operation, Operation) {
        let mut g = Graph::new();
        let two = {
            let mut nd = g.new_operation("Const", "two").unwrap();
            nd.set_attr_type("dtype", DataType::Float).unwrap();
            let mut value = Tensor::new(&[1]);
            value[0] = 2.0f32;
            nd.set_attr_tensor("value", value).unwrap();
            nd.finish().unwrap()
        };
        let x = {
            let mut nd = g.new_operation("Placeholder", "x").unwrap();
            nd.set_attr_type("dtype", DataType::Float).unwrap();
            nd.set_attr_shape("shape", &Shape(Some(vec![]))).unwrap();
            nd.finish().unwrap()
        };
        let y = {
            let mut nd = g.new_operation("Mul", "y").unwrap();
            nd.add_input(Output {
                operation: &two,
                index: 0,
            });
            nd.add_input(Output {
                operation: &x,
                index: 0,
            });
            nd.finish().unwrap()
        };
        let options = SessionOptions::new();
        match Session::new(&options, &g) {
            Ok(session) => (session, x, y),
            Err(status) => panic!("Creating session failed with status: {}", status),
        }
    }

    #[test]
    fn smoke() {
        create_session();
    }

    #[test]
    fn test_close() {
        let (mut session, _, _) = create_session();
        let status = session.close();
        assert!(status.is_ok());
    }

    #[test]
    fn test_run() {
        let (mut session, x_operation, y_operation) = create_session();
        let mut x = <Tensor<f32>>::new(&[2]);
        x[0] = 2.0;
        x[1] = 3.0;
        let mut step = StepWithGraph::new();
        step.add_input(&x_operation, 0, &x);
        let output_token = step.request_output(&y_operation, 0);
        session.run(&mut step).unwrap();
        let output_tensor = step.take_output::<f32>(output_token).unwrap();
        let data = output_tensor.data();
        assert_eq!(data.len(), 2);
        assert_eq!(data[0], 4.0);
        assert_eq!(data[1], 6.0);
    }
}
<|endoftext|>


<commit_before>use std::cmp::{max, min};
use std::mem;

use rustbox::keyboard::Key;
use rustbox::{RustBox};

use trie::Trie;
use tui::style;
use tui::termbox;
use tui::widget::{WidgetRet, Widget};
use utils;

// TODO: Make these settings
const SCROLLOFF : i32 = 5;
const HIST_SIZE : usize = 30;

pub struct TextField {
    /// The message that's currently being edited (not yet sent)
    buffer : Vec<char>,

    /// Cursor in currently shown line
    cursor : i32,

    /// Horizontal scroll
    scroll : i32,

    /// Width of the widget
    width : i32,

    /// A history of sent messages/commands. Once added messages are never
    /// modified. A modification attempt should result in a new buffer with a
    /// copy of the vector in history. (old contents of the buffer will be lost)
    history : Vec<Vec<char>>,

    mode : Mode,
}

enum Mode {
    /// Editing the buffer
    Edit,

    /// Browsing history
    History(i32),

    /// Auto-completing a nick in channel
    Autocomplete {
        original_buffer    : Vec<char>,
        insertion_point    : usize,
        word_starts        : usize,
        completions        : Vec<String>,
        current_completion : usize,
    }
}

impl TextField {
    pub fn new(width : i32) -> TextField {
        TextField {
            buffer: Vec::with_capacity(512),
            cursor: 0,
            scroll: 0,
            width: width,
            history: Vec::with_capacity(HIST_SIZE),
            mode: Mode::Edit,
        }
    }

    pub fn resize_(&mut self, width : i32, _ : i32) {
        self.width = width;
        self.move_cursor_to_end();
    }

    pub fn draw_(&self, _ : &RustBox, pos_x : i32, pos_y : i32) {
        match self.mode {
            Mode::Edit => {
                draw_line(&self.buffer, pos_x, pos_y, self.scroll, self.width, self.cursor);
            },
            Mode::History(hist_curs) => {
                draw_line(&self.history[hist_curs as usize],
                          pos_x, pos_y, self.scroll, self.width, self.cursor);
            },
            Mode::Autocomplete {
                ref original_buffer, insertion_point, word_starts,
                ref completions, current_completion
            } => {
                // draw a placeholder for the cursor
                termbox::print_char(pos_x + self.cursor - self.scroll, pos_y,
                                    style::USER_MSG.fg, style::USER_MSG.bg,
                                    ' ');

                let completion : &str = &completions[current_completion];

                let mut orig_buf_iter = original_buffer.iter().cloned();
                let mut completion_iter = completion.chars();

                let iter : utils::InsertIterator<char> =
                    utils::insert_iter(&mut orig_buf_iter, &mut completion_iter, insertion_point);

                for (char_idx, char) in iter.enumerate() {
                    if char_idx >= ((self.scroll + self.width) as usize) {
                        break;
                    }

                    if char_idx >= self.scroll as usize {
                        if char_idx >= word_starts &&
                                char_idx < insertion_point + completion.len() {
                            termbox::print_char(pos_x + (char_idx as i32) - self.scroll, pos_y,
                                                style::COMPLETION.fg, style::COMPLETION.bg,
                                                char);
                        } else {
                            termbox::print_char(pos_x + (char_idx as i32) - self.scroll, pos_y,
                                                style::USER_MSG.fg, style::USER_MSG.bg,
                                                char);
                        }

                    }
                }

                termbox::set_cursor(pos_x + self.cursor - self.scroll, pos_y);
            },
        }
    }

    pub fn keypressed_(&mut self, key : Key) -> WidgetRet {
        match key {
            Key::Char(ch) => {
                self.modify();
                self.buffer.insert(self.cursor as usize, ch);
                self.inc_cursor();
                WidgetRet::KeyHandled
            },

            Key::Backspace => {
                if self.cursor > 0 {
                    self.modify();
                    self.buffer.remove(self.cursor as usize - 1);
                    self.dec_cursor();
                }
                WidgetRet::KeyHandled
            },

            Key::Ctrl(ch) => {
                if ch == 'a' {
                    self.move_cursor(0);
                    WidgetRet::KeyHandled
                }

                else if ch == 'e' {
                    self.move_cursor_to_end();
                    WidgetRet::KeyHandled
                }

                else if ch == 'k' {
                    if self.cursor != self.line_len() {
                        self.modify();
                        self.buffer.drain(self.cursor as usize ..);
                    }
                    WidgetRet::KeyHandled
                }

                else if ch == 'w' {
                    self.consume_word_before_curs();
                    WidgetRet::KeyHandled
                }

                else {
                    WidgetRet::KeyIgnored
                }
            },

            Key::Left => {
                self.dec_cursor();
                WidgetRet::KeyHandled
            },

            Key::Right => {
                self.inc_cursor();
                WidgetRet::KeyHandled
            },

            Key::Enter => {
                if self.line_len() > 0 {
                    self.modify();

                    let ret = mem::replace(&mut self.buffer, Vec::new());
                    if self.history.len() == HIST_SIZE {
                        let mut reuse = self.history.remove(0);
                        reuse.clear();
                        reuse.extend_from_slice(&ret);
                        self.history.push(reuse);
                    } else {
                        self.history.push(ret.clone());
                    }

                    self.move_cursor(0);

                    WidgetRet::Input(ret)
                } else {
                    WidgetRet::KeyHandled
                }
            },

            ////////////////////////////////////////////////////////////////////
            // Scrolling in history or autocompletion list

            Key::Up => {
                let mode = mem::replace(&mut self.mode, Mode::Edit);

                match mode {
                    Mode::Edit => {},
                    Mode::History(hist_curs) => {
                        if hist_curs != (self.history.len() - 1) as i32 {
                            self.mode = Mode::History(hist_curs + 1);
                        } else {
                            self.mode = Mode::Edit;
                        }
                        self.move_cursor_to_end();
                    },
                    Mode::Autocomplete {
                        original_buffer, insertion_point,
                        word_starts, completions, current_completion, ..
                    } => {
                        let current_completion =
                            if current_completion != completions.len() - 1 {
                                current_completion + 1
                            } else {
                                current_completion
                            };

                        let cursor = (insertion_point + completions[current_completion].len()) as i32;

                        self.mode = Mode::Autocomplete {
                            original_buffer: original_buffer,
                            insertion_point: insertion_point,
                            word_starts: word_starts,
                            completions: completions,
                            current_completion: current_completion,
                        };

                        self.move_cursor(cursor);
                    },
                }

                WidgetRet::KeyHandled
            },

            Key::Down => {
                let mode = mem::replace(&mut self.mode, Mode::Edit);

                match mode {
                    Mode::Edit => {
                        if !self.history.is_empty() {
                            self.mode = Mode::History((self.history.len() as i32) - 1);
                            self.move_cursor_to_end();
                        }
                    },
                    Mode::History(hist_curs) => {
                        self.mode = Mode::History(
                            if hist_curs > 0 { hist_curs - 1 } else { hist_curs });
                        self.move_cursor_to_end();
                    },
                    Mode::Autocomplete {
                        original_buffer, insertion_point,
                        word_starts, completions, current_completion, ..
                    } => {
                        let current_completion =
                            if current_completion > 0 {
                                current_completion - 1
                            } else {
                                current_completion
                            };

                        let cursor = (insertion_point + completions[current_completion].len()) as i32;

                        self.mode = Mode::Autocomplete {
                            original_buffer: original_buffer,
                            insertion_point: insertion_point,
                            word_starts: word_starts,
                            completions: completions,
                            current_completion: current_completion,
                        };

                        self.move_cursor(cursor);
                    },
                }

                WidgetRet::KeyHandled
            },

            ////////////////////////////////////////////////////////////////////

            _ => WidgetRet::KeyIgnored,
        }
    }

    fn consume_word_before_curs(&mut self) {
        // No modifications can happen if the scroll is at the beginning
        if self.cursor == 0 {
            return;
        }

        self.modify();

        let char = self.buffer[(self.cursor - 1) as usize];

        // Try to imitate vim's behaviour here.
        if char.is_whitespace() {
            self.consume_before(|c| c.is_whitespace());
        }

        else if char.is_alphanumeric() {
            self.consume_before(|c| c.is_alphanumeric());
        }

        else {
            self.consume_before(|c| !c.is_alphanumeric());
        }
    }

    fn consume_before<F>(&mut self, f : F) where F : Fn(char) -> bool {
        let end_range = self.cursor as usize;
        let mut begin_range = self.cursor - 1;
        while begin_range >= 0 && f(self.buffer[begin_range as usize]) {
            begin_range -= 1;
        }
        self.buffer.drain(((begin_range + 1) as usize) .. end_range);
        self.move_cursor(begin_range + 1);
    }

    // Ignoring auto-completions
    fn shown_line(&self) -> &Vec<char> {
        match self.mode {
            Mode::Edit | Mode::Autocomplete { .. } => &self.buffer,
            Mode::History(hist_curs) => &self.history[hist_curs as usize],
        }
    }

    fn line_len(&self) -> i32 {
        match self.mode {
            Mode::Edit => {
                self.buffer.len() as i32
            },
            Mode::History(hist_curs) => {
                self.history[hist_curs as usize].len() as i32
            },
            Mode::Autocomplete { ref original_buffer, ref completions, current_completion, .. } => {
                (original_buffer.len() + completions[current_completion].len()) as i32
            },
        }
    }

    ////////////////////////////////////////////////////////////////////////////

    fn in_autocomplete(&self) -> bool {
        match self.mode {
            Mode::Autocomplete { .. } => true,
            _ => false
        }
    }

    fn modify(&mut self) {
        match self.mode {
            Mode::Edit => {},
            Mode::History(hist_idx) => {
                self.buffer.clear();
                self.buffer.extend_from_slice(&self.history[hist_idx as usize]);
            },
            Mode::Autocomplete {
                ref mut original_buffer,
                mut insertion_point,
                ref mut completions,
                current_completion,
                ..
            } => {
                let mut buffer  : Vec<char>   = mem::replace(original_buffer, vec![]);
                let completions : Vec<String> = mem::replace(completions, vec![]);
                let word = &completions[current_completion];

                // FIXME: This is inefficient
                for char in word.chars() {
                    buffer.insert(insertion_point, char);
                    insertion_point += 1;
                }

                self.buffer = buffer;
            }
        }

        self.mode = Mode::Edit;
    }

    ////////////////////////////////////////////////////////////////////////////
    // Manipulating cursor

    fn inc_cursor(&mut self) {
        let cur = min(self.line_len(), self.cursor + 1);
        self.move_cursor(cur);
    }

    fn dec_cursor(&mut self) {
        let cur = max(0, self.cursor - 1);
        self.move_cursor(cur);
    }

    fn move_cursor_to_end(&mut self) {
        let cursor = self.line_len();
        self.move_cursor(cursor);
    }

    fn move_cursor(&mut self, cursor : i32) {
        assert!(cursor >= 0 && cursor <= self.line_len());
        self.cursor = cursor;

        if self.line_len() + 1 < self.width {
            self.scroll = 0;
        } else {
            let scrolloff = { if self.width < 2 * SCROLLOFF + 1 { 0 } else { SCROLLOFF } };

            let left_end  = self.scroll;
            let right_end = self.scroll + self.width;

            if cursor - scrolloff < left_end {
                self.scroll = max(0, cursor - scrolloff);
            } else if cursor + scrolloff >= right_end {
                self.scroll = min(// +1 because cursor should be visible, i.e.
                                  // right_end > cursor should hold after this
                                  max(0, cursor + 1 + scrolloff - self.width),
                                  // +1 because cursor goes one more character
                                  // after the buffer, to be able to add chars
                                  max(0, self.line_len() + 1 - self.width));
            }
        }
    }
}

fn draw_line(line : &[char], pos_x : i32, pos_y : i32, scroll : i32, width : i32, cursor : i32) {
    let slice : &[char] = &line[ scroll as usize .. min(line.len(), (scroll + width) as usize) ];

    termbox::print_chars(pos_x, pos_y, style::USER_MSG.fg, style::USER_MSG.bg, slice);

    // On my terminal the cursor is only shown when there's a character
    // under it.
    if cursor as usize >= line.len() {
        termbox::print_char(pos_x + cursor - scroll, pos_y,
                            style::USER_MSG.fg, style::USER_MSG.bg,
                            ' ');
    }
    termbox::set_cursor(pos_x + cursor - scroll, pos_y);
}

impl Widget for TextField {
    fn resize(&mut self, width : i32, height : i32) {
        self.resize_(width, height);
    }

    fn draw(&self, rustbox : &RustBox, pos_x : i32, pos_y : i32) {
        self.draw_(rustbox, pos_x, pos_y);
    }

    fn keypressed(&mut self, key : Key) -> WidgetRet {
        self.keypressed_(key)
    }

    fn autocomplete(&mut self, dict : &Trie) {
        if self.in_autocomplete() {
            // AWFUL CODE YO
            self.keypressed(Key::Up);
            return;
        }

        let cursor_right = self.cursor;
        let mut cursor_left = max(0, cursor_right - 1);

        let completions = {
            let line = self.shown_line();

            while cursor_left >= 0
                    && line.get(cursor_left as usize).map(|c| c.is_alphanumeric()).unwrap_or(false) {
                cursor_left -= 1;
            }

            let word = {
                if cursor_left == cursor_right {
                    &[]
                } else {
                    cursor_left += 1;
                    &line[ (cursor_left as usize) .. (cursor_right as usize) ]
                }
            };

            dict.drop_pfx(&mut word.iter().cloned())
        };

        if !completions.is_empty() {
            let completion_len = completions[0].len();
            self.mode = Mode::Autocomplete {
                original_buffer: self.shown_line().to_owned(),
                insertion_point: self.cursor as usize,
                word_starts: cursor_left as usize,
                completions: completions,
                current_completion: 0,
            };
            let cursor = self.cursor;
            self.move_cursor(cursor + completion_len as i32);
        }
    }
}
<commit_msg>fix up/down key orders<commit_after>use std::cmp::{max, min};
use std::mem;

use rustbox::keyboard::Key;
use rustbox::{RustBox};

use trie::Trie;
use tui::style;
use tui::termbox;
use tui::widget::{WidgetRet, Widget};
use utils;

// TODO: Make these settings
const SCROLLOFF : i32 = 5;
const HIST_SIZE : usize = 30;

pub struct TextField {
    /// The message that's currently being edited (not yet sent)
    buffer : Vec<char>,

    /// Cursor in currently shown line
    cursor : i32,

    /// Horizontal scroll
    scroll : i32,

    /// Width of the widget
    width : i32,

    /// A history of sent messages/commands. Once added messages are never
    /// modified. A modification attempt should result in a new buffer with a
    /// copy of the vector in history. (old contents of the buffer will be lost)
    history : Vec<Vec<char>>,

    mode : Mode,
}

enum Mode {
    /// Editing the buffer
    Edit,

    /// Browsing history
    History(i32),

    /// Auto-completing a nick in channel
    Autocomplete {
        original_buffer    : Vec<char>,
        insertion_point    : usize,
        word_starts        : usize,
        completions        : Vec<String>,
        current_completion : usize,
    }
}

impl TextField {
    pub fn new(width : i32) -> TextField {
        TextField {
            buffer: Vec::with_capacity(512),
            cursor: 0,
            scroll: 0,
            width: width,
            history: Vec::with_capacity(HIST_SIZE),
            mode: Mode::Edit,
        }
    }

    pub fn resize_(&mut self, width : i32, _ : i32) {
        self.width = width;
        self.move_cursor_to_end();
    }

    pub fn draw_(&self, _ : &RustBox, pos_x : i32, pos_y : i32) {
        match self.mode {
            Mode::Edit => {
                draw_line(&self.buffer, pos_x, pos_y, self.scroll, self.width, self.cursor);
            },
            Mode::History(hist_curs) => {
                draw_line(&self.history[hist_curs as usize],
                          pos_x, pos_y, self.scroll, self.width, self.cursor);
            },
            Mode::Autocomplete {
                ref original_buffer, insertion_point, word_starts,
                ref completions, current_completion
            } => {
                // draw a placeholder for the cursor
                termbox::print_char(pos_x + self.cursor - self.scroll, pos_y,
                                    style::USER_MSG.fg, style::USER_MSG.bg,
                                    ' ');

                let completion : &str = &completions[current_completion];

                let mut orig_buf_iter = original_buffer.iter().cloned();
                let mut completion_iter = completion.chars();

                let iter : utils::InsertIterator<char> =
                    utils::insert_iter(&mut orig_buf_iter, &mut completion_iter, insertion_point);

                for (char_idx, char) in iter.enumerate() {
                    if char_idx >= ((self.scroll + self.width) as usize) {
                        break;
                    }

                    if char_idx >= self.scroll as usize {
                        if char_idx >= word_starts &&
                                char_idx < insertion_point + completion.len() {
                            termbox::print_char(pos_x + (char_idx as i32) - self.scroll, pos_y,
                                                style::COMPLETION.fg, style::COMPLETION.bg,
                                                char);
                        } else {
                            termbox::print_char(pos_x + (char_idx as i32) - self.scroll, pos_y,
                                                style::USER_MSG.fg, style::USER_MSG.bg,
                                                char);
                        }

                    }
                }

                termbox::set_cursor(pos_x + self.cursor - self.scroll, pos_y);
            },
        }
    }

    pub fn keypressed_(&mut self, key : Key) -> WidgetRet {
        match key {
            Key::Char(ch) => {
                self.modify();
                self.buffer.insert(self.cursor as usize, ch);
                self.inc_cursor();
                WidgetRet::KeyHandled
            },

            Key::Backspace => {
                if self.cursor > 0 {
                    self.modify();
                    self.buffer.remove(self.cursor as usize - 1);
                    self.dec_cursor();
                }
                WidgetRet::KeyHandled
            },

            Key::Ctrl(ch) => {
                if ch == 'a' {
                    self.move_cursor(0);
                    WidgetRet::KeyHandled
                }

                else if ch == 'e' {
                    self.move_cursor_to_end();
                    WidgetRet::KeyHandled
                }

                else if ch == 'k' {
                    if self.cursor != self.line_len() {
                        self.modify();
                        self.buffer.drain(self.cursor as usize ..);
                    }
                    WidgetRet::KeyHandled
                }

                else if ch == 'w' {
                    self.consume_word_before_curs();
                    WidgetRet::KeyHandled
                }

                else {
                    WidgetRet::KeyIgnored
                }
            },

            Key::Left => {
                self.dec_cursor();
                WidgetRet::KeyHandled
            },

            Key::Right => {
                self.inc_cursor();
                WidgetRet::KeyHandled
            },

            Key::Enter => {
                if self.line_len() > 0 {
                    self.modify();

                    let ret = mem::replace(&mut self.buffer, Vec::new());
                    if self.history.len() == HIST_SIZE {
                        let mut reuse = self.history.remove(0);
                        reuse.clear();
                        reuse.extend_from_slice(&ret);
                        self.history.push(reuse);
                    } else {
                        self.history.push(ret.clone());
                    }

                    self.move_cursor(0);

                    WidgetRet::Input(ret)
                } else {
                    WidgetRet::KeyHandled
                }
            },

            ////////////////////////////////////////////////////////////////////
            // Scrolling in history or autocompletion list

            Key::Up => {
                let mode = mem::replace(&mut self.mode, Mode::Edit);

                match mode {
                    Mode::Edit => {
                        if !self.history.is_empty() {
                            self.mode = Mode::History((self.history.len() as i32) - 1);
                            self.move_cursor_to_end();
                        }
                    },
                    Mode::History(hist_curs) => {
                        self.mode = Mode::History(
                            if hist_curs > 0 { hist_curs - 1 } else { hist_curs });
                        self.move_cursor_to_end();
                    },
                    Mode::Autocomplete {
                        original_buffer, insertion_point,
                        word_starts, completions, current_completion, ..
                    } => {
                        let current_completion =
                            if current_completion != completions.len() - 1 {
                                current_completion + 1
                            } else {
                                current_completion
                            };

                        let cursor = (insertion_point + completions[current_completion].len()) as i32;

                        self.mode = Mode::Autocomplete {
                            original_buffer: original_buffer,
                            insertion_point: insertion_point,
                            word_starts: word_starts,
                            completions: completions,
                            current_completion: current_completion,
                        };

                        self.move_cursor(cursor);
                    },
                }

                WidgetRet::KeyHandled
            },

            Key::Down => {
                let mode = mem::replace(&mut self.mode, Mode::Edit);

                match mode {
                    Mode::Edit => {},
                    Mode::History(hist_curs) => {
                        if hist_curs != (self.history.len() - 1) as i32 {
                            self.mode = Mode::History(hist_curs + 1);
                        } else {
                            self.mode = Mode::Edit;
                        }
                        self.move_cursor_to_end();
                    },
                    Mode::Autocomplete {
                        original_buffer, insertion_point,
                        word_starts, completions, current_completion, ..
                    } => {
                        let current_completion =
                            if current_completion > 0 {
                                current_completion - 1
                            } else {
                                current_completion
                            };

                        let cursor = (insertion_point + completions[current_completion].len()) as i32;

                        self.mode = Mode::Autocomplete {
                            original_buffer: original_buffer,
                            insertion_point: insertion_point,
                            word_starts: word_starts,
                            completions: completions,
                            current_completion: current_completion,
                        };

                        self.move_cursor(cursor);
                    },
                }

                WidgetRet::KeyHandled
            },

            ////////////////////////////////////////////////////////////////////

            _ => WidgetRet::KeyIgnored,
        }
    }

    fn consume_word_before_curs(&mut self) {
        // No modifications can happen if the scroll is at the beginning
        if self.cursor == 0 {
            return;
        }

        self.modify();

        let char = self.buffer[(self.cursor - 1) as usize];

        // Try to imitate vim's behaviour here.
        if char.is_whitespace() {
            self.consume_before(|c| c.is_whitespace());
        }

        else if char.is_alphanumeric() {
            self.consume_before(|c| c.is_alphanumeric());
        }

        else {
            self.consume_before(|c| !c.is_alphanumeric());
        }
    }

    fn consume_before<F>(&mut self, f : F) where F : Fn(char) -> bool {
        let end_range = self.cursor as usize;
        let mut begin_range = self.cursor - 1;
        while begin_range >= 0 && f(self.buffer[begin_range as usize]) {
            begin_range -= 1;
        }
        self.buffer.drain(((begin_range + 1) as usize) .. end_range);
        self.move_cursor(begin_range + 1);
    }

    // Ignoring auto-completions
    fn shown_line(&self) -> &Vec<char> {
        match self.mode {
            Mode::Edit | Mode::Autocomplete { .. } => &self.buffer,
            Mode::History(hist_curs) => &self.history[hist_curs as usize],
        }
    }

    fn line_len(&self) -> i32 {
        match self.mode {
            Mode::Edit => {
                self.buffer.len() as i32
            },
            Mode::History(hist_curs) => {
                self.history[hist_curs as usize].len() as i32
            },
            Mode::Autocomplete { ref original_buffer, ref completions, current_completion, .. } => {
                (original_buffer.len() + completions[current_completion].len()) as i32
            },
        }
    }

    ////////////////////////////////////////////////////////////////////////////

    fn in_autocomplete(&self) -> bool {
        match self.mode {
            Mode::Autocomplete { .. } => true,
            _ => false
        }
    }

    fn modify(&mut self) {
        match self.mode {
            Mode::Edit => {},
            Mode::History(hist_idx) => {
                self.buffer.clear();
                self.buffer.extend_from_slice(&self.history[hist_idx as usize]);
            },
            Mode::Autocomplete {
                ref mut original_buffer,
                mut insertion_point,
                ref mut completions,
                current_completion,
                ..
            } => {
                let mut buffer  : Vec<char>   = mem::replace(original_buffer, vec![]);
                let completions : Vec<String> = mem::replace(completions, vec![]);
                let word = &completions[current_completion];

                // FIXME: This is inefficient
                for char in word.chars() {
                    buffer.insert(insertion_point, char);
                    insertion_point += 1;
                }

                self.buffer = buffer;
            }
        }

        self.mode = Mode::Edit;
    }

    ////////////////////////////////////////////////////////////////////////////
    // Manipulating cursor

    fn inc_cursor(&mut self) {
        let cur = min(self.line_len(), self.cursor + 1);
        self.move_cursor(cur);
    }

    fn dec_cursor(&mut self) {
        let cur = max(0, self.cursor - 1);
        self.move_cursor(cur);
    }

    fn move_cursor_to_end(&mut self) {
        let cursor = self.line_len();
        self.move_cursor(cursor);
    }

    fn move_cursor(&mut self, cursor : i32) {
        assert!(cursor >= 0 && cursor <= self.line_len());
        self.cursor = cursor;

        if self.line_len() + 1 < self.width {
            self.scroll = 0;
        } else {
            let scrolloff = { if self.width < 2 * SCROLLOFF + 1 { 0 } else { SCROLLOFF } };

            let left_end  = self.scroll;
            let right_end = self.scroll + self.width;

            if cursor - scrolloff < left_end {
                self.scroll = max(0, cursor - scrolloff);
            } else if cursor + scrolloff >= right_end {
                self.scroll = min(// +1 because cursor should be visible, i.e.
                                  // right_end > cursor should hold after this
                                  max(0, cursor + 1 + scrolloff - self.width),
                                  // +1 because cursor goes one more character
                                  // after the buffer, to be able to add chars
                                  max(0, self.line_len() + 1 - self.width));
            }
        }
    }
}

fn draw_line(line : &[char], pos_x : i32, pos_y : i32, scroll : i32, width : i32, cursor : i32) {
    let slice : &[char] = &line[ scroll as usize .. min(line.len(), (scroll + width) as usize) ];

    termbox::print_chars(pos_x, pos_y, style::USER_MSG.fg, style::USER_MSG.bg, slice);

    // On my terminal the cursor is only shown when there's a character
    // under it.
    if cursor as usize >= line.len() {
        termbox::print_char(pos_x + cursor - scroll, pos_y,
                            style::USER_MSG.fg, style::USER_MSG.bg,
                            ' ');
    }
    termbox::set_cursor(pos_x + cursor - scroll, pos_y);
}

impl Widget for TextField {
    fn resize(&mut self, width : i32, height : i32) {
        self.resize_(width, height);
    }

    fn draw(&self, rustbox : &RustBox, pos_x : i32, pos_y : i32) {
        self.draw_(rustbox, pos_x, pos_y);
    }

    fn keypressed(&mut self, key : Key) -> WidgetRet {
        self.keypressed_(key)
    }

    fn autocomplete(&mut self, dict : &Trie) {
        if self.in_autocomplete() {
            // AWFUL CODE YO
            self.keypressed(Key::Up);
            return;
        }

        let cursor_right = self.cursor;
        let mut cursor_left = max(0, cursor_right - 1);

        let completions = {
            let line = self.shown_line();

            while cursor_left >= 0
                    && line.get(cursor_left as usize).map(|c| c.is_alphanumeric()).unwrap_or(false) {
                cursor_left -= 1;
            }

            let word = {
                if cursor_left == cursor_right {
                    &[]
                } else {
                    cursor_left += 1;
                    &line[ (cursor_left as usize) .. (cursor_right as usize) ]
                }
            };

            dict.drop_pfx(&mut word.iter().cloned())
        };

        if !completions.is_empty() {
            let completion_len = completions[0].len();
            self.mode = Mode::Autocomplete {
                original_buffer: self.shown_line().to_owned(),
                insertion_point: self.cursor as usize,
                word_starts: cursor_left as usize,
                completions: completions,
                current_completion: 0,
            };
            let cursor = self.cursor;
            self.move_cursor(cursor + completion_len as i32);
        }
    }
}
<|endoftext|>


<commit_before>use crate::utils::{
    in_macro_or_desugar, match_def_path,
    paths::{BEGIN_PANIC, BEGIN_PANIC_FMT},
    resolve_node, snippet_opt, span_lint_and_then,
};
use if_chain::if_chain;
use rustc::{
    declare_lint_pass, declare_tool_lint,
    hir::{intravisit::FnKind, Body, Expr, ExprKind, FnDecl, HirId, MatchSource, StmtKind},
    lint::{LateContext, LateLintPass, LintArray, LintPass},
};
use rustc_errors::Applicability;
use syntax::source_map::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for missing return statements at the end of a block.
    ///
    /// **Why is this bad?** Actually omitting the return keyword is idiomatic Rust code. Programmers
    /// coming from other languages might prefer the expressiveness of `return`. It's possible to miss
    /// the last returning statement because the only difference is a missing `;`. Especially in bigger
    /// code with multiple return paths having a `return` keyword makes it easier to find the
    /// corresponding statements.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// fn foo(x: usize) -> usize {
    ///     x
    /// }
    /// ```
    /// add return
    /// ```rust
    /// fn foo(x: usize) -> usize {
    ///     return x;
    /// }
    /// ```
    pub IMPLICIT_RETURN,
    restriction,
    "use a return statement like `return expr` instead of an expression"
}

declare_lint_pass!(ImplicitReturn => [IMPLICIT_RETURN]);

static LINT_BREAK: &str = "change `break` to `return` as shown";
static LINT_RETURN: &str = "add `return` as shown";

fn lint(cx: &LateContext<'_, '_>, outer_span: Span, inner_span: Span, msg: &str) {
    let outer_span = span_to_outer_expn(outer_span);
    let inner_span = span_to_outer_expn(inner_span);

    span_lint_and_then(cx, IMPLICIT_RETURN, outer_span, "missing return statement", |db| {
        if let Some(snippet) = snippet_opt(cx, inner_span) {
            db.span_suggestion(
                outer_span,
                msg,
                format!("return {}", snippet),
                Applicability::MachineApplicable,
            );
        }
    });
}

fn span_to_outer_expn(span: Span) -> Span {
    if let Some(expr) = span.ctxt().outer_expn_info() {
        span_to_outer_expn(expr.call_site)
    } else {
        span
    }
}

fn expr_match(cx: &LateContext<'_, '_>, expr: &Expr) {
    match &expr.node {
        // loops could be using `break` instead of `return`
        ExprKind::Block(block, ..) | ExprKind::Loop(block, ..) => {
            if let Some(expr) = &block.expr {
                expr_match(cx, expr);
            }
            // only needed in the case of `break` with `;` at the end
            else if let Some(stmt) = block.stmts.last() {
                if_chain! {
                    if let StmtKind::Semi(expr, ..) = &stmt.node;
                    // make sure it's a break, otherwise we want to skip
                    if let ExprKind::Break(.., break_expr) = &expr.node;
                    if let Some(break_expr) = break_expr;
                    then {
                            lint(cx, expr.span, break_expr.span, LINT_BREAK);
                    }
                }
            }
        },
        // use `return` instead of `break`
        ExprKind::Break(.., break_expr) => {
            if let Some(break_expr) = break_expr {
                lint(cx, expr.span, break_expr.span, LINT_BREAK);
            }
        },
        ExprKind::Match(.., arms, source) => {
            let check_all_arms = match source {
                MatchSource::IfLetDesugar {
                    contains_else_clause: has_else,
                } => *has_else,
                _ => true,
            };

            if check_all_arms {
                for arm in arms {
                    expr_match(cx, &arm.body);
                }
            } else {
                expr_match(cx, &arms.first().expect("if let doesn't have a single arm").body);
            }
        },
        // skip if it already has a return statement
        ExprKind::Ret(..) => (),
        // make sure it's not a call that panics
        ExprKind::Call(expr, ..) => {
            if_chain! {
                if let ExprKind::Path(qpath) = &expr.node;
                if let Some(path_def_id) = resolve_node(cx, qpath, expr.hir_id).opt_def_id();
                if match_def_path(cx, path_def_id, &BEGIN_PANIC) ||
                    match_def_path(cx, path_def_id, &BEGIN_PANIC_FMT);
                then { }
                else {
                    lint(cx, expr.span, expr.span, LINT_RETURN)
                }
            }
        },
        // everything else is missing `return`
        _ => lint(cx, expr.span, expr.span, LINT_RETURN),
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImplicitReturn {
    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        _: FnKind<'tcx>,
        _: &'tcx FnDecl,
        body: &'tcx Body,
        span: Span,
        _: HirId,
    ) {
        let def_id = cx.tcx.hir().body_owner_def_id(body.id());
        let mir = cx.tcx.optimized_mir(def_id);

        // checking return type through MIR, HIR is not able to determine inferred closure return types
        // make sure it's not a macro
        if !mir.return_ty().is_unit() && !in_macro_or_desugar(span) {
            expr_match(cx, &body.value);
        }
    }
}
<commit_msg>Use source_callsite() instead of recursive outer_expn_info()<commit_after>use crate::utils::{
    in_macro_or_desugar, match_def_path,
    paths::{BEGIN_PANIC, BEGIN_PANIC_FMT},
    resolve_node, snippet_opt, span_lint_and_then,
};
use if_chain::if_chain;
use rustc::{
    declare_lint_pass, declare_tool_lint,
    hir::{intravisit::FnKind, Body, Expr, ExprKind, FnDecl, HirId, MatchSource, StmtKind},
    lint::{LateContext, LateLintPass, LintArray, LintPass},
};
use rustc_errors::Applicability;
use syntax::source_map::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for missing return statements at the end of a block.
    ///
    /// **Why is this bad?** Actually omitting the return keyword is idiomatic Rust code. Programmers
    /// coming from other languages might prefer the expressiveness of `return`. It's possible to miss
    /// the last returning statement because the only difference is a missing `;`. Especially in bigger
    /// code with multiple return paths having a `return` keyword makes it easier to find the
    /// corresponding statements.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    /// ```rust
    /// fn foo(x: usize) -> usize {
    ///     x
    /// }
    /// ```
    /// add return
    /// ```rust
    /// fn foo(x: usize) -> usize {
    ///     return x;
    /// }
    /// ```
    pub IMPLICIT_RETURN,
    restriction,
    "use a return statement like `return expr` instead of an expression"
}

declare_lint_pass!(ImplicitReturn => [IMPLICIT_RETURN]);

static LINT_BREAK: &str = "change `break` to `return` as shown";
static LINT_RETURN: &str = "add `return` as shown";

fn lint(cx: &LateContext<'_, '_>, outer_span: Span, inner_span: Span, msg: &str) {
    let outer_span = outer_span.source_callsite();
    let inner_span = inner_span.source_callsite();

    span_lint_and_then(cx, IMPLICIT_RETURN, outer_span, "missing return statement", |db| {
        if let Some(snippet) = snippet_opt(cx, inner_span) {
            db.span_suggestion(
                outer_span,
                msg,
                format!("return {}", snippet),
                Applicability::MachineApplicable,
            );
        }
    });
}

fn expr_match(cx: &LateContext<'_, '_>, expr: &Expr) {
    match &expr.node {
        // loops could be using `break` instead of `return`
        ExprKind::Block(block, ..) | ExprKind::Loop(block, ..) => {
            if let Some(expr) = &block.expr {
                expr_match(cx, expr);
            }
            // only needed in the case of `break` with `;` at the end
            else if let Some(stmt) = block.stmts.last() {
                if_chain! {
                    if let StmtKind::Semi(expr, ..) = &stmt.node;
                    // make sure it's a break, otherwise we want to skip
                    if let ExprKind::Break(.., break_expr) = &expr.node;
                    if let Some(break_expr) = break_expr;
                    then {
                            lint(cx, expr.span, break_expr.span, LINT_BREAK);
                    }
                }
            }
        },
        // use `return` instead of `break`
        ExprKind::Break(.., break_expr) => {
            if let Some(break_expr) = break_expr {
                lint(cx, expr.span, break_expr.span, LINT_BREAK);
            }
        },
        ExprKind::Match(.., arms, source) => {
            let check_all_arms = match source {
                MatchSource::IfLetDesugar {
                    contains_else_clause: has_else,
                } => *has_else,
                _ => true,
            };

            if check_all_arms {
                for arm in arms {
                    expr_match(cx, &arm.body);
                }
            } else {
                expr_match(cx, &arms.first().expect("if let doesn't have a single arm").body);
            }
        },
        // skip if it already has a return statement
        ExprKind::Ret(..) => (),
        // make sure it's not a call that panics
        ExprKind::Call(expr, ..) => {
            if_chain! {
                if let ExprKind::Path(qpath) = &expr.node;
                if let Some(path_def_id) = resolve_node(cx, qpath, expr.hir_id).opt_def_id();
                if match_def_path(cx, path_def_id, &BEGIN_PANIC) ||
                    match_def_path(cx, path_def_id, &BEGIN_PANIC_FMT);
                then { }
                else {
                    lint(cx, expr.span, expr.span, LINT_RETURN)
                }
            }
        },
        // everything else is missing `return`
        _ => lint(cx, expr.span, expr.span, LINT_RETURN),
    }
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for ImplicitReturn {
    fn check_fn(
        &mut self,
        cx: &LateContext<'a, 'tcx>,
        _: FnKind<'tcx>,
        _: &'tcx FnDecl,
        body: &'tcx Body,
        span: Span,
        _: HirId,
    ) {
        let def_id = cx.tcx.hir().body_owner_def_id(body.id());
        let mir = cx.tcx.optimized_mir(def_id);

        // checking return type through MIR, HIR is not able to determine inferred closure return types
        // make sure it's not a macro
        if !mir.return_ty().is_unit() && !in_macro_or_desugar(span) {
            expr_match(cx, &body.value);
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code, unused_imports, unused_variables)]
fn main() {
  use std::io;
  use std::num;

  // We derive `Debug` because all types should probably derive `Debug`.
  // This gives us a reasonable human readable description of `CliError` values.
  #[derive(Debug)]
  enum CliError {
      Io(io::Error),
      Parse(num::ParseIntError),
  }

  use std::error;
  use std::fmt;

  impl fmt::Display for CliError {
      fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
          match *self {
              // Both underlying errors already impl `Display`, so we defer to
              // their implementations.
              CliError::Io(ref err) => write!(f, "IO error: {}", err),
              CliError::Parse(ref err) => write!(f, "Parse error: {}", err),
          }
      }
  }

  impl error::Error for CliError {
      fn description(&self) -> &str {
          // This method returns a borrowed string with a lifetime attached to
          // the error value. This means we cannot heap allocate a new string
          // in this method using safe code, so we are forced to keep the
          // description short and sweet.
          match *self {
              CliError::Io(_) => "IO error",
              CliError::Parse(_) => "error converting string to number",
          }
      }

      fn cause(&self) -> Option<&error::Error> {
          match *self {
              // N.B. Both of these implicitly cast `err` from their concrete
              // types (either `&io::Error` or `&num::ParseIntError`)
              // to a trait object `&Error`. This works because both error types
              // implement `Error`.
              CliError::Io(ref err) => Some(err),
              CliError::Parse(ref err) => Some(err),
          }
      }
  }
}
<commit_msg>Make error impl better.<commit_after>#![allow(dead_code, unused_imports, unused_variables)]
fn main() {
  use std::io;
  use std::num;

  // We derive `Debug` because all types should probably derive `Debug`.
  // This gives us a reasonable human readable description of `CliError` values.
  #[derive(Debug)]
  enum CliError {
      Io(io::Error),
      Parse(num::ParseIntError),
  }

  use std::error;
  use std::fmt;

  impl fmt::Display for CliError {
      fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
          match *self {
              // Both underlying errors already impl `Display`, so we defer to
              // their implementations.
              CliError::Io(ref err) => write!(f, "IO error: {}", err),
              CliError::Parse(ref err) => write!(f, "Parse error: {}", err),
          }
      }
  }

  impl error::Error for CliError {
      fn description(&self) -> &str {
          // Both underlying errors already impl `Error`, so we defer to their
          // implementations.
          match *self {
              CliError::Io(ref err) => err.description(),
              // Normally we can just write `err.description()`, but the error
              // type has a concrete method called `description`, which conflicts
              // with the trait method. For now, we must explicitly call
              // `description` through the `Error` trait.
              CliError::Parse(ref err) => error::Error::description(err),
          }
      }

      fn cause(&self) -> Option<&error::Error> {
          match *self {
              // N.B. Both of these implicitly cast `err` from their concrete
              // types (either `&io::Error` or `&num::ParseIntError`)
              // to a trait object `&Error`. This works because both error types
              // implement `Error`.
              CliError::Io(ref err) => Some(err),
              CliError::Parse(ref err) => Some(err),
          }
      }
  }
}
<|endoftext|>


<commit_before>extern crate hyper;
use std::io::Read;
use self::hyper::Client;
use self::hyper::header::Connection;

use std::collections::HashMap;
use std::io::{Error, ErrorKind};
use std::cell::Cell;
use std::sync::Arc;
use std::cell::RefCell;
use std::cell::UnsafeCell;
use std::ops::FnMut;

// pub fn download() -> String
// {
//         // Create a client.
//         let client = Client::new();
//
//         // Creating an outgoing request.
//         let mut res = client.get("http://forum1.hkgolden.com/topics.aspx?type=BW")
//             // set a header
//             .header(Connection::close())
//             // let 'er go!
//             .send().unwrap();
//
//         // Read the Response.
//         let mut body = String::new();
//         res.read_to_string(&mut body).unwrap();
//
//     return body;
// }

pub struct WebResource {
     pub pages: HashMap<String, String>,
     pub client: Client
}

impl WebResource {

    pub fn new() -> Self {
        WebResource {
            pages: HashMap::new(),
            client: Client::new()
        }
    }

    // let fetch_page = move |url: &str| -> String {
    //     download_map.entry(String::from(url))
    //                 .or_insert_with(move || {
    //                     match download_page(&client, &String::from(url)) {
    //                         Ok(s) => s,
    //                         Err(e) => format!("{:?}", e),
    //                     }
    //                 })
    //                 .clone()
    // };
    //

    pub fn download_page(&mut self, url: &String) -> Result<String, Error> {
        match self.client.get(url).send() {
            Ok(mut resp) => {
                let mut s = String::new();
                match resp.read_to_string(&mut s) {
                    Ok(size) => Ok(s),
                    Err(e) => Err(e),
                }
            }
            Err(e) => Err(Error::new(ErrorKind::InvalidData, e)),
        }
    }

    pub fn save(&mut self, url: &str) {
        if !self.pages.contains_key(url) {
            let res = match self.download_page(&String::from(url)) {
                Ok(s) => s,
                Err(e) => format!("{:?}", e),
            };
            self.pages.insert(String::from(url), res);
        }
    }

    pub fn get(&mut self, url: &str) -> String {
        match self.pages.get(url) {
            Some(page) => page.clone(),
            None => { String::from("None") }
        }
    }

    pub fn fetch(&mut self, url: &str) -> String {
        self.save(url);
        self.get(url)
    }
}
<commit_msg>Webresource - methods rename<commit_after>extern crate hyper;
use std::io::Read;
use self::hyper::Client;
use self::hyper::header::Connection;

use std::collections::HashMap;
use std::io::{Error, ErrorKind};
use std::cell::Cell;
use std::sync::Arc;
use std::cell::RefCell;
use std::cell::UnsafeCell;
use std::ops::FnMut;

// pub fn download() -> String
// {
//         // Create a client.
//         let client = Client::new();
//
//         // Creating an outgoing request.
//         let mut res = client.get("http://forum1.hkgolden.com/topics.aspx?type=BW")
//             // set a header
//             .header(Connection::close())
//             // let 'er go!
//             .send().unwrap();
//
//         // Read the Response.
//         let mut body = String::new();
//         res.read_to_string(&mut body).unwrap();
//
//     return body;
// }

pub struct WebResource {
     pub pages: HashMap<String, String>,
     client: Client,
}

impl WebResource {

    pub fn new() -> Self {
        WebResource {
            pages: HashMap::new(),
            client: Client::new(),
        }
    }

    // let fetch_page = move |url: &str| -> String {
    //     download_map.entry(String::from(url))
    //                 .or_insert_with(move || {
    //                     match download_page(&client, &String::from(url)) {
    //                         Ok(s) => s,
    //                         Err(e) => format!("{:?}", e),
    //                     }
    //                 })
    //                 .clone()
    // };
    //

    pub fn fetch(&mut self, url: &String) -> Result<String, Error> {
        match self.client.get(url).send() {
            Ok(mut resp) => {
                let mut s = String::new();
                match resp.read_to_string(&mut s) {
                    Ok(size) => Ok(s),
                    Err(e) => Err(e),
                }
            }
            Err(e) => Err(Error::new(ErrorKind::InvalidData, e)),
        }
    }

    pub fn fetch_safe(&mut self, url: &str) -> String {
        match self.fetch(&String::from(url)) {
            Ok(s) => s,
            Err(e) => format!("{:?}", e),
        }
    }

    pub fn find(&mut self, url: &str) -> String {
        match self.pages.get(url) {
            Some(page) => page.clone(),
            None => { String::from("None") }
        }
    }

    pub fn get(&mut self, url: &str) -> String {
        if !self.pages.contains_key(url) {
            let res = self.fetch_safe(url);
            self.pages.insert(String::from(url), res);
        }
        self.find(url)
    }
}
<|endoftext|>


<commit_before>#![no_std]
#![feature(asm)]

#[macro_use]
extern crate libtww;

use libtww::prelude::*;
use libtww::system;
use libtww::link;
use libtww::Link;
use libtww::link::inventory::Inventory;
use libtww::link::item;
use libtww::game::Console;
use libtww::game::controller;
use libtww::game::flag;
use libtww::warping::Entrance;
use libtww::warping::Warp;
use libtww::warping::stage;

#[no_mangle]
#[inline(never)]
pub extern "C" fn init() {
    // Call overriden instruction
    system::cdyl_init_async();

    Console::get().setup();
}

#[no_mangle]
#[inline(never)]
pub extern "C" fn game_loop() {
    let link = Link::get();
    let console = Console::get();
    let inventory = Inventory::get();
    let mut lines = &mut console.lines;

    let exit = Warp::last_exit();

    if exit.entrance.stage_name() == stage::sea::SEA && Link::stage() == stage::other::NAME_SELECT && !flag::HAS_SEEN_INTRO.is_active()
    {
        system::memory::write(0x803B81BC, 0x01000000); //hero's sword
        let warp = Warp::new(stage::earth_temple::TEMPLE, 1, 1, exit.layer_override, exit.fadeout, exit.enabled);
        warp.execute();
    }
    if Link::stage() == stage::earth_temple::TEMPLE && exit.entrance.room == Entrance::last_entrance().room
    {
        let _ = write!(lines[0].begin(), "Puzzle 1: Backwards is Forwards");

        if Link::room() == 0 && exit.entrance.room == Entrance::last_entrance().room
        {
            system::memory::write(0x803B81BC, 0x00000000); //hero's sword off
            let warp = Warp::new(stage::earth_temple::TEMPLE, 1, 1, exit.layer_override, exit.fadeout, true);
            warp.execute();
        }
        else if Link::room() == 1
        {
            let warp = Warp::new(stage::earth_temple::TEMPLE, exit.entrance.entrance, exit.entrance.room, exit.layer_override, exit.fadeout, false);
            warp.execute();
        }
    }

    if Link::stage() == stage::forsaken_fortress::FF1_INTERIOR
    {

        if !flag::GRABBED_FIRST_ROPE_IN_FF1.is_active()
        {
            let _ = write!(lines[0].begin(), "Puzzle 2: On the Ropes Without That Button");
            Link::set_collision(link::CollisionType::DoorCancel);
        }
        else
        {
            let _ = write!(lines[0].begin(), "Puzzle 3: No Pain, No Gain");
            if link.heart_quarters < 12
            {
                Link::set_collision(link::CollisionType::ChestStorage);
            }
            else
            {
                Link::set_collision(link::CollisionType::Default);
            }
        }
    }

}

#[no_mangle]
#[inline(never)]
pub extern "C" fn set_controller() {
    if Link::stage() == stage::forsaken_fortress::FF1_INTERIOR
    {
        controller::mask_all_buttons(!controller::A);
    }
}

#[no_mangle]
pub extern "C" fn start() {
    game_loop();
    init();
    set_controller();
}
<commit_msg>Make save and death warps take you to empty room<commit_after>#![no_std]
#![feature(asm)]

#[macro_use]
extern crate libtww;

use libtww::prelude::*;
use libtww::system;
use libtww::link;
use libtww::Link;
use libtww::link::inventory::Inventory;
use libtww::link::item;
use libtww::game::Console;
use libtww::game::controller;
use libtww::game::flag;
use libtww::warping::Entrance;
use libtww::warping::Warp;
use libtww::warping::stage;
use libtww::warping::warp;
use libtww::warping::fadeout::FadeOut;

#[no_mangle]
#[inline(never)]
pub extern "C" fn init() {
    // Call overriden instruction
    system::cdyl_init_async();

    Console::get().setup();
}

#[no_mangle]
#[inline(never)]
pub extern "C" fn game_loop() {
    let link = Link::get();
    let console = Console::get();
    let inventory = Inventory::get();
    let mut lines = &mut console.lines;

    let exit = Warp::last_exit();

    if exit.entrance.stage_name() == stage::sea::SEA && Entrance::last_entrance().stage_name() == stage::other::NAME_SELECT && !flag::HAS_SEEN_INTRO.is_active()
    {
        system::memory::write(0x803B81BC, 0x01000000); //hero's sword
        let warp = Warp::new(stage::earth_temple::TEMPLE, 1, 1, exit.layer_override, exit.fadeout, exit.enabled);
        warp.execute();
    }
    else if exit.entrance.stage_name() == stage::sea::SEA && exit.entrance.room == 44 //game over or save warp
    {
        let _ = write!(lines[0].begin(), "you tried... :^)");
        let warp = Warp::new(stage::dev::LARGE_EMPTY_ROOM, 0, 0, exit.layer_override, exit.fadeout, true);
        warp.execute();
    }
    else if Entrance::last_entrance().stage_name() == stage::earth_temple::TEMPLE && exit.entrance.room == Entrance::last_entrance().room
    {
        flag::HAS_SEEN_INTRO.activate();
        let _ = write!(lines[0].begin(), "Puzzle 1: Backwards is Forwards");
        if Link::room() == 0 && exit.entrance.room == Entrance::last_entrance().room
        {
            system::memory::write(0x803B81BC, 0x00000000); //hero's sword off
            let warp = Warp::new(stage::earth_temple::TEMPLE, 1, 1, exit.layer_override, exit.fadeout, true);
            warp.execute();
        }
        else if Link::room() == 1
        {
            let warp = Warp::new(stage::earth_temple::TEMPLE, exit.entrance.entrance, exit.entrance.room, exit.layer_override, exit.fadeout, false);
            warp.execute();
        }
    }
    else if Entrance::last_entrance().stage_name() == stage::forsaken_fortress::FF1_INTERIOR
    {
        if !flag::GRABBED_FIRST_ROPE_IN_FF1.is_active()
        {
            let _ = write!(lines[0].begin(), "Puzzle 2: On the Ropes Without That Button");
            Link::set_collision(link::CollisionType::DoorCancel);
        }
        else
        {
            let _ = write!(lines[0].begin(), "Puzzle 3: No Pain, No Gain");
            if link.heart_quarters < 12
            {
                Link::set_collision(link::CollisionType::ChestStorage);
            }
            else
            {
                Link::set_collision(link::CollisionType::Default);
            }
        }
    }
    else
    {
        lines[0].clear();
    }
}

#[no_mangle]
#[inline(never)]
pub extern "C" fn set_controller() {
    if Entrance::last_entrance().stage_name() == stage::forsaken_fortress::FF1_INTERIOR
    {
        controller::mask_all_buttons(!controller::A);
    }
}

#[no_mangle]
pub extern "C" fn start() {
    game_loop();
    init();
    set_controller();
}
<|endoftext|>


<commit_before>use compression::{NUM_DOCS_PER_BLOCK, BlockDecoder, VIntDecoder};
use DocId;
use postings::{Postings, FreqHandler, DocSet, HasLen, SkipResult};
use std::num::Wrapping;
use fastfield::DeleteBitSet;

const EMPTY_DATA: [u8; 0] = [0u8; 0];

/// `SegmentPostings` represents the inverted list or postings associated to
/// a term in a `Segment`.
///
/// As we iterate through the `SegmentPostings`, the frequencies are optionally decoded.
/// Positions on the other hand, are optionally entirely decoded upfront.
pub struct SegmentPostings<'a> {
    len: usize,
    block_len: usize,
    doc_offset: u32,
    block_decoder: BlockDecoder,
    freq_handler: FreqHandler,
    remaining_data: &'a [u8],
    cur: Wrapping<usize>,
    delete_bitset: DeleteBitSet,
}

impl<'a> SegmentPostings<'a> {
    fn load_next_block(&mut self) {
        let num_remaining_docs = self.len - self.cur.0;
        if num_remaining_docs >= NUM_DOCS_PER_BLOCK {
            self.remaining_data =
                self.block_decoder
                    .uncompress_block_sorted(self.remaining_data, self.doc_offset);
            self.remaining_data = self.freq_handler.read_freq_block(self.remaining_data);
            self.doc_offset = self.block_decoder.output(NUM_DOCS_PER_BLOCK - 1);
            self.block_len = NUM_DOCS_PER_BLOCK;
        } else {
            self.remaining_data =
                self.block_decoder
                    .uncompress_vint_sorted(self.remaining_data,
                                            self.doc_offset,
                                            num_remaining_docs);
            self.freq_handler
                .read_freq_vint(self.remaining_data, num_remaining_docs);
            self.block_len = num_remaining_docs;
        }
    }

    /// Reads a Segment postings from an &[u8]
    ///
    /// * `len` - number of document in the posting lists.
    /// * `data` - data array. The complete data is not necessarily used.
    /// * `freq_handler` - the freq handler is in charge of decoding
    ///   frequencies and/or positions
    pub fn from_data(len: u32,
                     data: &'a [u8],
                     delete_bitset: &'a DeleteBitSet,
                     freq_handler: FreqHandler)
                     -> SegmentPostings<'a> {
        SegmentPostings {
            len: len as usize,
            block_len: len as usize,
            doc_offset: 0,
            block_decoder: BlockDecoder::new(),
            freq_handler: freq_handler,
            remaining_data: data,
            cur: Wrapping(usize::max_value()),
            delete_bitset: delete_bitset.clone(),
        }
    }

    /// Returns an empty segment postings object
    pub fn empty() -> SegmentPostings<'static> {
        SegmentPostings {
            len: 0,
            block_len: 0,
            doc_offset: 0,
            block_decoder: BlockDecoder::new(),
            freq_handler: FreqHandler::new_without_freq(),
            remaining_data: &EMPTY_DATA,
            delete_bitset: DeleteBitSet::empty(),
            cur: Wrapping(usize::max_value()),
        }
    }

    /// Index within a block is used as an address when
    /// interacting with the `FreqHandler`
    fn index_within_block(&self) -> usize {
        self.cur.0 % NUM_DOCS_PER_BLOCK
    }

    /// Sets the current position to a location relative
    /// to the current block
    #[inline]
    fn set_within_block(&mut self, inner_pos: usize) {
        self.cur = Wrapping(self.cur.0 & !(NUM_DOCS_PER_BLOCK - 1)) + Wrapping(inner_pos)
    }
}

impl<'a> DocSet for SegmentPostings<'a> {
    // goes to the next element.
    // next needs to be called a first time to point to the correct element.
    #[inline]
    fn advance(&mut self) -> bool {
        loop {
            self.cur += Wrapping(1);
            if self.cur.0 >= self.len {
                return false;
            }
            if self.index_within_block() == 0 {
                self.load_next_block();
            }
            if !self.delete_bitset.is_deleted(self.doc()) {
                return true;
            }
        }
    }

    fn skip_next(&mut self, target: DocId) -> SkipResult {
        if !self.advance() {
            return SkipResult::End;
        }

        let mut pos = self.index_within_block();
        // skip blocks until one that might contain the target
        loop {
            // check if we need to go to the next block
            if target > self.block_decoder.output(self.block_len - 1) {
                self.cur += Wrapping(self.block_len - pos);
                self.load_next_block();
                pos = 0;

                // there was no more data
                if self.cur.0 == self.len {
                    return SkipResult::End;
                }
            } else if target < self.block_decoder.output(pos) {
                // We've overpassed the target after the first `advance` call
                // or we're at the beginning of a block.
                // Either way, we're on the first `DocId` greater than `target`
                return SkipResult::OverStep;
            } else {
                break;
            }
        }

        debug_assert!(target >= self.block_decoder.output(pos));
        debug_assert!(target <= self.block_decoder.output(self.block_len - 1));

        // we're in the right block, do a binary search
        let mut start = pos;
        let mut count = self.block_len - start;
        while count > 0 {
            let step = count / 2;
            let mid = start + step;
            let doc = self.block_decoder.output(mid);
            if doc < target {
                start = mid + 1;
                count -= step + 1;
            } else if doc > target {
                count = step;
            } else {
                self.set_within_block(mid);

                if !self.delete_bitset.is_deleted(doc) {
                    return SkipResult::Reached;
                }

                if self.advance() {
                    return SkipResult::OverStep;
                }
                return SkipResult::End;
            }
        }

        // `doc` is now >= `target`
        let doc = self.block_decoder.output(start);
        self.set_within_block(start);

        if !self.delete_bitset.is_deleted(doc) {
            if doc == target {
                return SkipResult::Reached;
            } else {
                return SkipResult::OverStep;
            }
        }

        if self.advance() {
            return SkipResult::OverStep;
        }
        return SkipResult::End;
    }

    #[inline]
    fn doc(&self) -> DocId {
        self.block_decoder.output(self.index_within_block())
    }
}

impl<'a> HasLen for SegmentPostings<'a> {
    fn len(&self) -> usize {
        self.len
    }
}

impl<'a> Postings for SegmentPostings<'a> {
    fn term_freq(&self) -> u32 {
        self.freq_handler.freq(self.index_within_block())
    }

    fn positions(&self) -> &[u32] {
        self.freq_handler.positions(self.index_within_block())
    }
}
<commit_msg>Disable early exit<commit_after>use compression::{NUM_DOCS_PER_BLOCK, BlockDecoder, VIntDecoder};
use DocId;
use postings::{Postings, FreqHandler, DocSet, HasLen, SkipResult};
use std::num::Wrapping;
use fastfield::DeleteBitSet;

const EMPTY_DATA: [u8; 0] = [0u8; 0];

/// `SegmentPostings` represents the inverted list or postings associated to
/// a term in a `Segment`.
///
/// As we iterate through the `SegmentPostings`, the frequencies are optionally decoded.
/// Positions on the other hand, are optionally entirely decoded upfront.
pub struct SegmentPostings<'a> {
    len: usize,
    block_len: usize,
    doc_offset: u32,
    block_decoder: BlockDecoder,
    freq_handler: FreqHandler,
    remaining_data: &'a [u8],
    cur: Wrapping<usize>,
    delete_bitset: DeleteBitSet,
}

impl<'a> SegmentPostings<'a> {
    fn load_next_block(&mut self) {
        let num_remaining_docs = self.len - self.cur.0;
        if num_remaining_docs >= NUM_DOCS_PER_BLOCK {
            self.remaining_data =
                self.block_decoder
                    .uncompress_block_sorted(self.remaining_data, self.doc_offset);
            self.remaining_data = self.freq_handler.read_freq_block(self.remaining_data);
            self.doc_offset = self.block_decoder.output(NUM_DOCS_PER_BLOCK - 1);
            self.block_len = NUM_DOCS_PER_BLOCK;
        } else {
            self.remaining_data =
                self.block_decoder
                    .uncompress_vint_sorted(self.remaining_data,
                                            self.doc_offset,
                                            num_remaining_docs);
            self.freq_handler
                .read_freq_vint(self.remaining_data, num_remaining_docs);
            self.block_len = num_remaining_docs;
        }
    }

    /// Reads a Segment postings from an &[u8]
    ///
    /// * `len` - number of document in the posting lists.
    /// * `data` - data array. The complete data is not necessarily used.
    /// * `freq_handler` - the freq handler is in charge of decoding
    ///   frequencies and/or positions
    pub fn from_data(len: u32,
                     data: &'a [u8],
                     delete_bitset: &'a DeleteBitSet,
                     freq_handler: FreqHandler)
                     -> SegmentPostings<'a> {
        SegmentPostings {
            len: len as usize,
            block_len: len as usize,
            doc_offset: 0,
            block_decoder: BlockDecoder::new(),
            freq_handler: freq_handler,
            remaining_data: data,
            cur: Wrapping(usize::max_value()),
            delete_bitset: delete_bitset.clone(),
        }
    }

    /// Returns an empty segment postings object
    pub fn empty() -> SegmentPostings<'static> {
        SegmentPostings {
            len: 0,
            block_len: 0,
            doc_offset: 0,
            block_decoder: BlockDecoder::new(),
            freq_handler: FreqHandler::new_without_freq(),
            remaining_data: &EMPTY_DATA,
            delete_bitset: DeleteBitSet::empty(),
            cur: Wrapping(usize::max_value()),
        }
    }

    /// Index within a block is used as an address when
    /// interacting with the `FreqHandler`
    fn index_within_block(&self) -> usize {
        self.cur.0 % NUM_DOCS_PER_BLOCK
    }

    /// Sets the current position to a location relative
    /// to the current block
    #[inline]
    fn set_within_block(&mut self, inner_pos: usize) {
        self.cur = Wrapping(self.cur.0 & !(NUM_DOCS_PER_BLOCK - 1)) + Wrapping(inner_pos)
    }
}

impl<'a> DocSet for SegmentPostings<'a> {
    // goes to the next element.
    // next needs to be called a first time to point to the correct element.
    #[inline]
    fn advance(&mut self) -> bool {
        loop {
            self.cur += Wrapping(1);
            if self.cur.0 >= self.len {
                return false;
            }
            if self.index_within_block() == 0 {
                self.load_next_block();
            }
            if !self.delete_bitset.is_deleted(self.doc()) {
                return true;
            }
        }
    }

    fn skip_next(&mut self, target: DocId) -> SkipResult {
        if !self.advance() {
            return SkipResult::End;
        }

        let mut pos = self.index_within_block();
        // skip blocks until one that might contain the target
        loop {
            // check if we need to go to the next block
            if target > self.block_decoder.output(self.block_len - 1) {
                self.cur += Wrapping(self.block_len - pos);
                self.load_next_block();
                pos = 0;

                // there was no more data
                if self.cur.0 == self.len {
                    return SkipResult::End;
                }
            } else if target < self.block_decoder.output(pos) {
                // We've overpassed the target after the first `advance` call
                // or we're at the beginning of a block.
                // Either way, we're on the first `DocId` greater than `target`
                return SkipResult::OverStep;
            } else {
                break;
            }
        }

        debug_assert!(target >= self.block_decoder.output(pos));
        debug_assert!(target <= self.block_decoder.output(self.block_len - 1));

        // we're in the right block, do a binary search
        let mut start = pos;
        let mut count = self.block_len - start;
        while count > 0 {
            let step = count / 2;
            let mid = start + step;
            let doc = self.block_decoder.output(mid);
            if doc < target {
                start = mid + 1;
                count -= step + 1;
            } else {
                count = step;
            }
        }

        // `doc` is now >= `target`
        let doc = self.block_decoder.output(start);
        self.set_within_block(start);

        if !self.delete_bitset.is_deleted(doc) {
            if doc == target {
                return SkipResult::Reached;
            } else {
                return SkipResult::OverStep;
            }
        }

        if self.advance() {
            return SkipResult::OverStep;
        }
        return SkipResult::End;
    }

    #[inline]
    fn doc(&self) -> DocId {
        self.block_decoder.output(self.index_within_block())
    }
}

impl<'a> HasLen for SegmentPostings<'a> {
    fn len(&self) -> usize {
        self.len
    }
}

impl<'a> Postings for SegmentPostings<'a> {
    fn term_freq(&self) -> u32 {
        self.freq_handler.freq(self.index_within_block())
    }

    fn positions(&self) -> &[u32] {
        self.freq_handler.positions(self.index_within_block())
    }
}
<|endoftext|>


<commit_before>use lexer::Lexer;
use parser::{Context, ParsingResult, TeXToken, ParsingInterpreter, InterpreterOutput,
             InterpretersLauncher};

use parser::comment::CommentInterpreter;
use parser::text::TextInterpreter;
use parser::command::CommandInterpreter;

pub struct Parser<'a> {
    lexer: Lexer<'a>,
    ctx: Context,
}

impl<'a> Parser<'a> {
    pub fn new(input: &'a str) -> Self {
        Parser {
            lexer: Lexer::new(input),
            ctx: Context::new(),
        }
    }

    pub fn parse(&mut self) -> ParsingResult<Vec<TeXToken>> {
        let handler = TopParserInterpreter::default();
        let mut out = vec![];

        match handler.launch_interpreters(
            &mut out,
            &mut self.lexer,
            &mut self.ctx,
        )? {
            Some(InterpreterOutput::Stop) => (),
            _ => {
                // TODO: return error.
            }
        }
        Ok(out)
    }
}

pub struct TopParserInterpreter {
    interpreters: Vec<Box<ParsingInterpreter>>,
}

impl TopParserInterpreter {
    pub fn new() -> Self {
        TopParserInterpreter { interpreters: vec![] }
    }
}

impl InterpretersLauncher for TopParserInterpreter {
    fn get_interpreters(&self) -> &Vec<Box<ParsingInterpreter>> {
        &self.interpreters
    }
}

impl Default for TopParserInterpreter {
    fn default() -> Self {
        TopParserInterpreter {
            interpreters: vec![
                Box::new(CommentInterpreter::new()),
                Box::new(CommandInterpreter::default()),
                Box::new(TextInterpreter::new()),
            ],
        }
    }
}
<commit_msg>update rustfmt to 0.1.5<commit_after>use lexer::Lexer;
use parser::{Context, ParsingResult, TeXToken, ParsingInterpreter, InterpreterOutput,
             InterpretersLauncher};

use parser::comment::CommentInterpreter;
use parser::text::TextInterpreter;
use parser::command::CommandInterpreter;

pub struct Parser<'a> {
    lexer: Lexer<'a>,
    ctx: Context,
}

impl<'a> Parser<'a> {
    pub fn new(input: &'a str) -> Self {
        Parser {
            lexer: Lexer::new(input),
            ctx: Context::new(),
        }
    }

    pub fn parse(&mut self) -> ParsingResult<Vec<TeXToken>> {
        let handler = TopParserInterpreter::default();
        let mut out = vec![];

        match handler
            .launch_interpreters(&mut out, &mut self.lexer, &mut self.ctx)? {
            Some(InterpreterOutput::Stop) => (),
            _ => {
                // TODO: return error.
            }
        }
        Ok(out)
    }
}

pub struct TopParserInterpreter {
    interpreters: Vec<Box<ParsingInterpreter>>,
}

impl TopParserInterpreter {
    pub fn new() -> Self {
        TopParserInterpreter { interpreters: vec![] }
    }
}

impl InterpretersLauncher for TopParserInterpreter {
    fn get_interpreters(&self) -> &Vec<Box<ParsingInterpreter>> {
        &self.interpreters
    }
}

impl Default for TopParserInterpreter {
    fn default() -> Self {
        TopParserInterpreter {
            interpreters: vec![
                Box::new(CommentInterpreter::new()),
                Box::new(CommandInterpreter::default()),
                Box::new(TextInterpreter::new()),
            ],
        }
    }
}
<|endoftext|>


<commit_before>// This tests that exports can have visible dependencies on things
// that are not exported, allowing for a sort of poor-man's ADT

mod foo {
  export f;
  export g;

  // not exported
  tag t {
    t1;
  }

  fn f() -> t {
    ret t1;
  }

  fn g(t v) {
    check (v == t1);
  }
}

fn main() {
  foo.g(foo.f());
}<commit_msg>Revert "Use check instead of assert in export-unexported-dep"<commit_after>// This tests that exports can have visible dependencies on things
// that are not exported, allowing for a sort of poor-man's ADT

mod foo {
  export f;
  export g;

  // not exported
  tag t {
    t1;
  }

  fn f() -> t {
    ret t1;
  }

  fn g(t v) {
    assert v == t1;
  }
}

fn main() {
  foo.g(foo.f());
}<|endoftext|>