<commit_before>use std::mem;

const HEADER_LEN: usize = 2;

#[derive(PartialEq, Debug)]
pub enum MqttType {
    //Reserved = 0,
    Connect = 1,
    // ConnAck = 2,
    Publish = 3,
    // PubAck = 4,
    // PubRec = 5,
    // PubRel = 6,
    // PubComp = 7,
    Subscribe = 8,
    SubAck = 9,
    // Unsubscribe = 0xa,
    // UnsubAck = 0xb,
    PingReq = 0xc,
    // PingResp = 0xd,
    Disconnect = 0xe,
}

pub fn message_type(bytes: &[u8]) -> MqttType {
    unsafe { mem::transmute((bytes[0] & 0xf0) >> 4) }
}

fn connect_bytes() -> Vec<u8> {
    vec!(
        0x10u8, 0x2a, // fixed header
        0x00, 0x06, 'M' as u8, 'Q' as u8, 'I' as u8, 's' as u8, 'd' as u8, 'p' as u8,
        0x03, // protocol version
        0xcc, // connection flags 1100111x user, pw, !wr, w(01), w, !c, x
        0x00, 0x0a, // keepalive of 100
        0x00, 0x03, 'c' as u8, 'i' as u8, 'd' as u8, // client ID
        0x00, 0x04, 'w' as u8, 'i' as u8, 'l' as u8, 'l' as u8, // will topic
        0x00, 0x04, 'w' as u8, 'm' as u8, 's' as u8, 'g' as u8, // will msg
        0x00, 0x07, 'g' as u8, 'l' as u8, 'i' as u8, 'f' as u8, 't' as u8, 'e' as u8, 'l' as u8, // username
        0x00, 0x02, 'p' as u8, 'w' as u8, // password
        )
}

#[test]
fn connect_type() {
    let connect_bytes = connect_bytes();
    assert_eq!(message_type(&connect_bytes), MqttType::Connect);
}

#[test]
fn ping_type() {
    let ping_bytes = &[0xc0u8, 0][0..];
    assert_eq!(message_type(ping_bytes), MqttType::PingReq);
}

#[test]
fn subscribe_type() {
    let subscribe_header = &[0x80, 0][0..];
    assert_eq!(message_type(subscribe_header), MqttType::Subscribe);
}

#[test]
fn suback_type() {
    let subscribe_header = &[0x90, 3, 0, 7, 1][0..];
    assert_eq!(message_type(subscribe_header), MqttType::SubAck);
}

pub fn remaining_length(bytes: &[u8]) -> usize {
    if bytes.len() < 2 {
        return 0;
    }

    let bytes = &bytes[1..]; //skip half of the fixed header

    //algorithm straight from the MQTT spec
    let mut multiplier: usize = 1;
    let mut value: usize = 0;
    let mut digit: usize = bytes[0] as usize;

    loop { // do-while would be cleaner...
        value += (digit & 127) * multiplier;
        multiplier *= 128;

        if (digit & 128) == 0 {
            break;
        }

        if bytes.len() > 1 {
            digit = bytes[1..][0] as usize;
        }
    }

    value
}

#[test]
fn connect_len() {
    assert_eq!(remaining_length(&connect_bytes()), 42);
}

#[test]
fn ping_len() {
    let ping_bytes = &[0xc0u8, 0][0..];
    assert_eq!(remaining_length(&ping_bytes), 0);
}

#[test]
fn msg_lens() {
    assert_eq!(remaining_length(&[]), 0);
    assert_eq!(remaining_length(&[0x15, 5]), 5);
    assert_eq!(remaining_length(&[0x27, 7]), 7);
    assert_eq!(remaining_length(&[0x12, 0xc1, 0x02]), 321);
    assert_eq!(remaining_length(&[0x12, 0x83, 0x02]), 259);
    //assert_eq!(remaining_length(&[0x12, 0x85, 0x80, 0x01]), 2097157);
}

pub fn subscribe_msg_id(bytes: &[u8]) -> u16 {
    bytes[3] as u16
}

#[test]
fn subscribe_msg_id_happy() {
    assert_eq!(subscribe_msg_id(&[0x8cu8, 3, 0, 33]), 33);
    assert_eq!(subscribe_msg_id(&[0x8cu8, 3, 0, 21]), 21);
}

pub fn publish_topic(bytes: &[u8]) -> String {
    let topic_len = ((bytes[2] as u16) << 8) + bytes[3] as u16;
    let topic_len = topic_len as usize;
    String::from_utf8(bytes[4 .. 4 + topic_len].to_vec())
        .expect("Could not convert publish topic to vec")
}

#[test]
fn test_get_topic_with_msg_id() {
    let pub_bytes = vec![
        0x3c, 0x0d, //fixed header
        0x00, 0x05, 'f' as u8, 'i' as u8, 'r' as u8, 's' as u8, 't' as u8,//topic name
        0x00, 0x21, //message ID
        'b' as u8, 'o' as u8, 'r' as u8, 'g' as u8, //payload
        ];
    assert_eq!(publish_topic(&pub_bytes[..]), "first");
}

pub fn publish_payload(bytes: &[u8]) -> &[u8] {
    let topic_len = publish_topic(bytes).len();
    let mut start = HEADER_LEN + topic_len + 2;
    if (bytes[0] & 0x06) != 0 {
        start += 2;
    }

    &bytes[start ..]
}

#[test]
fn test_get_payload_with_msg_id() {
    let pub_bytes = vec![
        0x3c, 0x0d, //fixed header
        0x00, 0x05, 'f' as u8, 'i' as u8, 'r' as u8, 's' as u8, 't' as u8,//topic name
        0x00, 0x21, //message ID
        1, 2, 3, 4, //payload
        ];
    assert_eq!(publish_payload(&pub_bytes[..]).to_vec(), vec![1, 2, 3, 4]);
}

#[test]
fn test_get_payload_no_msg_id() {
    let pub_bytes = vec![
        0x30, 0x0a, //fixed header
        0x00, 0x05, 'f' as u8, 'i' as u8, 'r' as u8, 's' as u8, 't' as u8,//topic name
        9, 8, 7, //payload
        ];
    assert_eq!(publish_payload(&pub_bytes[..]).to_vec(), vec![9, 8, 7]);
}

pub fn subscribe_topics(bytes: &[u8]) -> Vec<String> {
    let start = HEADER_LEN + 2; // final 2 for msg_id
    let mut res = vec![];
    let mut slice = &bytes[start .. ];
    while slice.len() > 0 {
        let topic_len = (((slice[0] as u16) << 8) + slice[1] as u16) as usize;
        let topic_slice = &slice[2 .. 2 + topic_len];
        res.push(String::from_utf8(topic_slice.to_vec())
                 .expect("Could not convert subscribe topic to vec"));
        //first 2 for topic len, last 1 for qos
        slice = &slice[2 + topic_len + 1 .. ];
    }
    res
}

#[test]
fn test_subscribe_topics1() {
    let sub_bytes = vec![
        0x8b, 0x13, //fixed header
        0x00, 0x21, //message ID
        0x00, 0x05, 'f' as u8, 'i' as u8, 'r' as u8, 's' as u8, 't' as u8,
        0x01, //qos
        0x00, 0x06, 's' as u8, 'e' as u8, 'c' as u8, 'o' as u8, 'n' as u8, 'd' as u8,
        0x02, //qos
        ];
    assert_eq!(subscribe_topics(&sub_bytes[..]), vec!["first".to_string(), "second".to_string()]);
}

#[test]
fn test_subscribe_topics2() {
    let sub_bytes = vec![
        0x8b, 0x12, //fixed header
        0x00, 0x21, //message ID
        0x00, 0x04, 'f' as u8, 'i' as u8, 'r' as u8, 's' as u8,
        0x01, //qos
        0x00, 0x06, 's' as u8, 'e' as u8, 'c' as u8, 'o' as u8, 'n' as u8, 'd' as u8,
        0x02, //qos
        ];
    assert_eq!(subscribe_topics(&sub_bytes[..]), vec!["firs".to_string(), "second".to_string()]);
}

pub fn total_length(bytes: &[u8]) -> usize {
    return remaining_length(bytes) + HEADER_LEN;
}
<commit_msg>Remove warnings from cargo test<commit_after>use std::mem;

const HEADER_LEN: usize = 2;

#[derive(PartialEq, Debug)]
pub enum MqttType {
    //Reserved = 0,
    Connect = 1,
    // ConnAck = 2,
    Publish = 3,
    // PubAck = 4,
    // PubRec = 5,
    // PubRel = 6,
    // PubComp = 7,
    Subscribe = 8,
    SubAck = 9,
    // Unsubscribe = 0xa,
    // UnsubAck = 0xb,
    PingReq = 0xc,
    // PingResp = 0xd,
    Disconnect = 0xe,
}

pub fn message_type(bytes: &[u8]) -> MqttType {
    unsafe { mem::transmute((bytes[0] & 0xf0) >> 4) }
}

fn connect_bytes() -> Vec<u8> {
    vec!(
        0x10u8, 0x2a, // fixed header
        0x00, 0x06, 'M' as u8, 'Q' as u8, 'I' as u8, 's' as u8, 'd' as u8, 'p' as u8,
        0x03, // protocol version
        0xcc, // connection flags 1100111x user, pw, !wr, w(01), w, !c, x
        0x00, 0x0a, // keepalive of 100
        0x00, 0x03, 'c' as u8, 'i' as u8, 'd' as u8, // client ID
        0x00, 0x04, 'w' as u8, 'i' as u8, 'l' as u8, 'l' as u8, // will topic
        0x00, 0x04, 'w' as u8, 'm' as u8, 's' as u8, 'g' as u8, // will msg
        0x00, 0x07, 'g' as u8, 'l' as u8, 'i' as u8, 'f' as u8, 't' as u8, 'e' as u8, 'l' as u8, // username
        0x00, 0x02, 'p' as u8, 'w' as u8, // password
        )
}

#[test]
fn connect_type() {
    let connect_bytes = connect_bytes();
    assert_eq!(message_type(&connect_bytes), MqttType::Connect);
}

#[test]
fn ping_type() {
    let ping_bytes = &[0xc0u8, 0][0..];
    assert_eq!(message_type(ping_bytes), MqttType::PingReq);
}

#[test]
fn subscribe_type() {
    let subscribe_header = &[0x80, 0][0..];
    assert_eq!(message_type(subscribe_header), MqttType::Subscribe);
}

#[test]
fn suback_type() {
    let subscribe_header = &[0x90, 3, 0, 7, 1][0..];
    assert_eq!(message_type(subscribe_header), MqttType::SubAck);
}

#[test]
fn disconnect_type() {
    let bytes = &[224, 0][0..];
    assert_eq!(message_type(bytes), MqttType::Disconnect);

}

pub fn remaining_length(bytes: &[u8]) -> usize {
    if bytes.len() < 2 {
        return 0;
    }

    let bytes = &bytes[1..]; //skip half of the fixed header

    //algorithm straight from the MQTT spec
    let mut multiplier: usize = 1;
    let mut value: usize = 0;
    let mut digit: usize = bytes[0] as usize;

    loop { // do-while would be cleaner...
        value += (digit & 127) * multiplier;
        multiplier *= 128;

        if (digit & 128) == 0 {
            break;
        }

        if bytes.len() > 1 {
            digit = bytes[1..][0] as usize;
        }
    }

    value
}

#[test]
fn connect_len() {
    assert_eq!(remaining_length(&connect_bytes()), 42);
}

#[test]
fn ping_len() {
    let ping_bytes = &[0xc0u8, 0][0..];
    assert_eq!(remaining_length(&ping_bytes), 0);
}

#[test]
fn msg_lens() {
    assert_eq!(remaining_length(&[]), 0);
    assert_eq!(remaining_length(&[0x15, 5]), 5);
    assert_eq!(remaining_length(&[0x27, 7]), 7);
    assert_eq!(remaining_length(&[0x12, 0xc1, 0x02]), 321);
    assert_eq!(remaining_length(&[0x12, 0x83, 0x02]), 259);
    //assert_eq!(remaining_length(&[0x12, 0x85, 0x80, 0x01]), 2097157);
}

pub fn subscribe_msg_id(bytes: &[u8]) -> u16 {
    bytes[3] as u16
}

#[test]
fn subscribe_msg_id_happy() {
    assert_eq!(subscribe_msg_id(&[0x8cu8, 3, 0, 33]), 33);
    assert_eq!(subscribe_msg_id(&[0x8cu8, 3, 0, 21]), 21);
}

pub fn publish_topic(bytes: &[u8]) -> String {
    let topic_len = ((bytes[2] as u16) << 8) + bytes[3] as u16;
    let topic_len = topic_len as usize;
    String::from_utf8(bytes[4 .. 4 + topic_len].to_vec())
        .expect("Could not convert publish topic to vec")
}

#[test]
fn test_get_topic_with_msg_id() {
    let pub_bytes = vec![
        0x3c, 0x0d, //fixed header
        0x00, 0x05, 'f' as u8, 'i' as u8, 'r' as u8, 's' as u8, 't' as u8,//topic name
        0x00, 0x21, //message ID
        'b' as u8, 'o' as u8, 'r' as u8, 'g' as u8, //payload
        ];
    assert_eq!(publish_topic(&pub_bytes[..]), "first");
}

pub fn publish_payload(bytes: &[u8]) -> &[u8] {
    let topic_len = publish_topic(bytes).len();
    let mut start = HEADER_LEN + topic_len + 2;
    if (bytes[0] & 0x06) != 0 {
        start += 2;
    }

    &bytes[start ..]
}

#[test]
fn test_get_payload_with_msg_id() {
    let pub_bytes = vec![
        0x3c, 0x0d, //fixed header
        0x00, 0x05, 'f' as u8, 'i' as u8, 'r' as u8, 's' as u8, 't' as u8,//topic name
        0x00, 0x21, //message ID
        1, 2, 3, 4, //payload
        ];
    assert_eq!(publish_payload(&pub_bytes[..]).to_vec(), vec![1, 2, 3, 4]);
}

#[test]
fn test_get_payload_no_msg_id() {
    let pub_bytes = vec![
        0x30, 0x0a, //fixed header
        0x00, 0x05, 'f' as u8, 'i' as u8, 'r' as u8, 's' as u8, 't' as u8,//topic name
        9, 8, 7, //payload
        ];
    assert_eq!(publish_payload(&pub_bytes[..]).to_vec(), vec![9, 8, 7]);
}

pub fn subscribe_topics(bytes: &[u8]) -> Vec<String> {
    let start = HEADER_LEN + 2; // final 2 for msg_id
    let mut res = vec![];
    let mut slice = &bytes[start .. ];
    while slice.len() > 0 {
        let topic_len = (((slice[0] as u16) << 8) + slice[1] as u16) as usize;
        let topic_slice = &slice[2 .. 2 + topic_len];
        res.push(String::from_utf8(topic_slice.to_vec())
                 .expect("Could not convert subscribe topic to vec"));
        //first 2 for topic len, last 1 for qos
        slice = &slice[2 + topic_len + 1 .. ];
    }
    res
}

#[test]
fn test_subscribe_topics1() {
    let sub_bytes = vec![
        0x8b, 0x13, //fixed header
        0x00, 0x21, //message ID
        0x00, 0x05, 'f' as u8, 'i' as u8, 'r' as u8, 's' as u8, 't' as u8,
        0x01, //qos
        0x00, 0x06, 's' as u8, 'e' as u8, 'c' as u8, 'o' as u8, 'n' as u8, 'd' as u8,
        0x02, //qos
        ];
    assert_eq!(subscribe_topics(&sub_bytes[..]), vec!["first".to_string(), "second".to_string()]);
}

#[test]
fn test_subscribe_topics2() {
    let sub_bytes = vec![
        0x8b, 0x12, //fixed header
        0x00, 0x21, //message ID
        0x00, 0x04, 'f' as u8, 'i' as u8, 'r' as u8, 's' as u8,
        0x01, //qos
        0x00, 0x06, 's' as u8, 'e' as u8, 'c' as u8, 'o' as u8, 'n' as u8, 'd' as u8,
        0x02, //qos
        ];
    assert_eq!(subscribe_topics(&sub_bytes[..]), vec!["firs".to_string(), "second".to_string()]);
}

pub fn total_length(bytes: &[u8]) -> usize {
    return remaining_length(bytes) + HEADER_LEN;
}
<|endoftext|>


<commit_before>use parking_lot::RwLock;
use std::rc::Rc;

use crate::core::codec::text::u32_to_char;
use crate::core::view::ContentFilter;
use crate::core::view::FilterData;
use crate::core::view::FilterIo;
use crate::core::view::LayoutEnv;
use crate::core::view::View;
use crate::core::Editor;

pub struct TabFilter {
    prev_cp: char,
    column_count: u64,
    tab_color: (u8, u8, u8),
}

impl TabFilter {
    pub fn new() -> Self {
        TabFilter {
            prev_cp: '\u{0}',
            column_count: 0,
            // tab_color: (242, 71, 132), // pink-like
            // tab_color: (40, 23, 51) // purple-like
            // tab_color: (59, 34, 76)
            tab_color: (128, 75, 165),
        }
    }
}

impl ContentFilter<'_> for TabFilter {
    fn name(&self) -> &'static str {
        &"TabFilter"
    }

    fn setup(
        &mut self,
        _editor: &Editor<'static>,
        env: &mut LayoutEnv,
        _view: &Rc<RwLock<View>>,
        _parent_view: Option<&View<'static>>,
    ) {
        self.prev_cp = '\u{0}';
        self.column_count = 0;
        if env.graphic_display {
            // self.tab_color = (242, 71, 132); // purple-like
        } else {
            self.tab_color = (128, 0, 128); // magenta
        }
    }

    fn run(
        &mut self,
        _view: &View,
        _env: &mut LayoutEnv,
        filter_in: &[FilterIo],
        filter_out: &mut Vec<FilterIo>,
    ) {
        for io in filter_in.iter() {
            if let FilterIo {
                data: FilterData::TextInfo { real_cp, .. },
                ..
            } = &*io
            {
                let codepoint = u32_to_char(*real_cp);
                match codepoint {
                    '\t' => {
                        self.prev_cp = '\t';
                        // TODO(ceg): setup
                        let tab_size = 8;
                        let padding = tab_size - (self.column_count % tab_size);

                        //dbg_println!(" TAB column count = {}, padding = {}", self.column_count, padding);

                        for (idx, _) in (0..padding).enumerate() {
                            // \t -> ' '
                            let mut new_io = FilterIo::replace_displayed_codepoint(io, ' ');
                            new_io.style.color = self.tab_color;
                            new_io.size = if idx == 0 { io.size } else { 0 };
                            new_io.metadata = if idx == 0 { io.metadata } else { true };
                            filter_out.push(new_io);
                        }
                        self.column_count += padding;
                    }

                    _ => {
                        if codepoint == '\n' {
                            self.column_count = 0;
                        } else {
                            self.column_count += 1;
                        }
                        self.prev_cp = codepoint;
                        filter_out.push(io.clone());
                    }
                }
            } else {
                // not unicode
                // dbg_println!(" TAB EXP no unicode: {:?}", io);
                filter_out.push(io.clone());
            }
        }
    }
}
<commit_msg>tab expansion: improve tab display use 2 colors: 1st char use defaul color<commit_after>use parking_lot::RwLock;
use std::rc::Rc;

use crate::core::codec::text::u32_to_char;
use crate::core::codepointinfo::TextStyle;
use crate::core::view::{ContentFilter, FilterData, FilterIo, LayoutEnv, View};
use crate::core::Editor;

pub struct TabFilter {
    prev_cp: char,
    column_count: u64,
    tab_color: (u8, u8, u8),
}

impl TabFilter {
    pub fn new() -> Self {
        TabFilter {
            prev_cp: '\u{0}',
            column_count: 0,
            // tab_color: (242, 71, 132), // pink-like
            // tab_color: (40, 23, 51) // purple-like
            // tab_color: (59, 34, 76)
            tab_color: (128, 75, 165),
        }
    }
}

impl ContentFilter<'_> for TabFilter {
    fn name(&self) -> &'static str {
        &"TabFilter"
    }

    fn setup(
        &mut self,
        _editor: &Editor<'static>,
        env: &mut LayoutEnv,
        _view: &Rc<RwLock<View>>,
        _parent_view: Option<&View<'static>>,
    ) {
        self.prev_cp = '\u{0}';
        self.column_count = 0;
        if env.graphic_display {
            // self.tab_color = (242, 71, 132); // purple-like
        } else {
            self.tab_color = (128, 0, 128); // magenta
        }
    }

    fn run(
        &mut self,
        _view: &View,
        _env: &mut LayoutEnv,
        filter_in: &[FilterIo],
        filter_out: &mut Vec<FilterIo>,
    ) {
        for io in filter_in.iter() {
            if let FilterIo {
                data: FilterData::TextInfo { real_cp, .. },
                ..
            } = &*io
            {
                let codepoint = u32_to_char(*real_cp);
                match codepoint {
                    '\t' => {
                        self.prev_cp = '\t'; // TODO(ceg): user configuration/file hints
                        let tab_size = 8;
                        let padding = tab_size - (self.column_count % tab_size);

                        for (idx, _) in (0..padding).enumerate() {
                            // \t -> ' '
                            let mut new_io = FilterIo::replace_displayed_codepoint(io, ' ');

                            // display the tab expansion with 2 colors
                            // the 1st char uses a distinct color from the rest of the expansion
                            if idx == 0 {
                                new_io.metadata = io.metadata;
                                new_io.style.color = TextStyle::default_color();
                                new_io.size = io.size;
                            } else {
                                new_io.metadata = true;
                                new_io.style.color = self.tab_color;
                                new_io.size = 0;
                            };
                            filter_out.push(new_io);
                        }
                        self.column_count += padding;
                    }

                    _ => {
                        if codepoint == '\n' {
                            self.column_count = 0;
                        } else {
                            self.column_count += 1;
                        }
                        self.prev_cp = codepoint;
                        filter_out.push(io.clone());
                    }
                }
            } else {
                // not unicode
                // dbg_println!(" TAB EXP no unicode: {:?}", io);
                filter_out.push(io.clone());
            }
        }
    }
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::error::Error;
use std::io::Write;
use std::io::stderr;

use ansi_term::Colour::Red;

/// Print an Error type and its cause recursively
///
/// The error is printed with "Error NNNN :" as prefix, where "NNNN" is a number which increases
/// which each recursion into the errors cause. The error description is used to visualize what
/// failed and if there is a cause "-- caused by:" is appended, and the cause is printed on the next
/// line.
///
/// Example output:
///
/// ```ignore
/// Error    1 : Some error -- caused by:
/// Error    2 : Some other error -- caused by:
/// Error    3 : Yet another Error -- caused by:
/// ...
///
/// Error <NNNN> : <Error description>
/// ```
pub fn trace_error(e: &Error) {
    print_trace_maxdepth(count_error_causes(e), e, ::std::u64::MAX);
    write!(stderr(), "\n").ok();
}

/// Convenience function: calls `trace_error()` with `e` and afterwards `std::process::exit()`
/// with `code`
pub fn trace_error_exit(e: &Error, code: i32) -> ! {
    use std::process::exit;

    debug!("Tracing error...");
    trace_error(e);
    debug!("Calling exit()");
    exit(code);
}

/// Print an Error type and its cause recursively, but only `max` levels
///
/// Output is the same as for `trace_error()`, though there are only `max` levels printed.
pub fn trace_error_maxdepth(e: &Error, max: u64) {
    let n = count_error_causes(e);
    let msg = Red.blink().paint(format!("{}/{} Levels of errors will be printed\n",
                                        (if max > n { n } else { max }), n));
    write!(stderr(), "{}", msg).ok();
    print_trace_maxdepth(n, e, max);
    write!(stderr(), "").ok();
}

/// Print an Error type and its cause recursively with the debug!() macro
///
/// Output is the same as for `trace_error()`.
pub fn trace_error_dbg(e: &Error) {
    print_trace_dbg(0, e);
}

/// Helper function for `trace_error()` and `trace_error_maxdepth()`.
///
/// Returns the cause of the last processed error in the recursion, so `None` if all errors where
/// processed.
fn print_trace_maxdepth(idx: u64, e: &Error, max: u64) -> Option<&Error> {
    if e.cause().is_some() && idx > 0 {
        e.cause().map(|cause| {
            match print_trace_maxdepth(idx - 1, cause, max) {
                None    => write!(stderr(), "\n").ok(),
                Some(_) => write!(stderr(), " -- caused:\n").ok(),
            };
        });
    } else {
        write!(stderr(), "\n").ok();
    }
    write!(stderr(), "{}: {}", Red.paint(format!("ERROR[{:>4}]", idx)), e.description()).ok();
    e.cause()
}

/// Count errors in `Error::cause()` recursively
fn count_error_causes(e: &Error) -> u64 {
    1 + e.cause().map(|c| count_error_causes(c)).unwrap_or(0)
}

fn print_trace_dbg(idx: u64, e: &Error) {
    debug!("{}: {}", Red.blink().paint(format!("ERROR[{:>4}]", idx)), e.description());
    if e.cause().is_some() {
        e.cause().map(|c| print_trace_dbg(idx + 1, c));
    }
}

/// Helper functions for `Result<T, E>` types to reduce overhead in the following situations:
///
/// ```ignore
/// function().map_err(|e| { trace_error(&e); e })
/// ```
///
/// and variants
pub trait MapErrTrace {
    type Output;

    fn map_err_trace(self) -> Self;
    fn map_err_dbg_trace(self) -> Self;
    fn map_err_trace_exit(self, code: i32) -> Self;
    fn map_err_trace_exit_unwrap(self, code: i32) -> Self::Output;
    fn map_err_trace_maxdepth(self, max: u64) -> Self;
}

impl<U, E: Error> MapErrTrace for Result<U, E> {
    type Output = U;

    /// Simply call `trace_error()` on the Err (if there is one) and return the error.
    ///
    /// This does nothing besides the side effect of printing the error trace
    fn map_err_trace(self) -> Self {
        self.map_err(|e| { trace_error(&e); e })
    }

    /// Simply call `trace_error_dbg()` on the Err (if there is one) and return the error.
    ///
    /// This does nothing besides the side effect of printing the error trace
    fn map_err_dbg_trace(self) -> Self {
        self.map_err(|e| { trace_error_dbg(&e); e })
    }

    /// Simply call `trace_error_exit(code)` on the Err (if there is one).
    ///
    /// This does not return if there is an Err(e).
    fn map_err_trace_exit(self, code: i32) -> Self {
        self.map_err(|e| { trace_error_exit(&e, code) })
    }

    /// Helper for calling map_err_trace_exit(n).unwrap() in one call
    fn map_err_trace_exit_unwrap(self, code: i32) -> Self::Output {
        self.map_err_trace_exit(code).unwrap()
    }

    /// Simply call `trace_error_maxdepth(max)` on the Err (if there is one) and return the error.
    ///
    /// This does nothing besides the side effect of printing the error trace to a certain depth
    fn map_err_trace_maxdepth(self, max: u64) -> Self {
        self.map_err(|e| { trace_error_maxdepth(&e, max); e })
    }

}

<commit_msg>Do not call description() when displaying the error<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::error::Error;
use std::io::Write;
use std::io::stderr;

use ansi_term::Colour::Red;

/// Print an Error type and its cause recursively
///
/// The error is printed with "Error NNNN :" as prefix, where "NNNN" is a number which increases
/// which each recursion into the errors cause. The error description is used to visualize what
/// failed and if there is a cause "-- caused by:" is appended, and the cause is printed on the next
/// line.
///
/// Example output:
///
/// ```ignore
/// Error    1 : Some error -- caused by:
/// Error    2 : Some other error -- caused by:
/// Error    3 : Yet another Error -- caused by:
/// ...
///
/// Error <NNNN> : <Error description>
/// ```
pub fn trace_error(e: &Error) {
    print_trace_maxdepth(count_error_causes(e), e, ::std::u64::MAX);
    write!(stderr(), "\n").ok();
}

/// Convenience function: calls `trace_error()` with `e` and afterwards `std::process::exit()`
/// with `code`
pub fn trace_error_exit(e: &Error, code: i32) -> ! {
    use std::process::exit;

    debug!("Tracing error...");
    trace_error(e);
    debug!("Calling exit()");
    exit(code);
}

/// Print an Error type and its cause recursively, but only `max` levels
///
/// Output is the same as for `trace_error()`, though there are only `max` levels printed.
pub fn trace_error_maxdepth(e: &Error, max: u64) {
    let n = count_error_causes(e);
    let msg = Red.blink().paint(format!("{}/{} Levels of errors will be printed\n",
                                        (if max > n { n } else { max }), n));
    write!(stderr(), "{}", msg).ok();
    print_trace_maxdepth(n, e, max);
    write!(stderr(), "").ok();
}

/// Print an Error type and its cause recursively with the debug!() macro
///
/// Output is the same as for `trace_error()`.
pub fn trace_error_dbg(e: &Error) {
    print_trace_dbg(0, e);
}

/// Helper function for `trace_error()` and `trace_error_maxdepth()`.
///
/// Returns the cause of the last processed error in the recursion, so `None` if all errors where
/// processed.
fn print_trace_maxdepth(idx: u64, e: &Error, max: u64) -> Option<&Error> {
    if e.cause().is_some() && idx > 0 {
        e.cause().map(|cause| {
            match print_trace_maxdepth(idx - 1, cause, max) {
                None    => write!(stderr(), "\n").ok(),
                Some(_) => write!(stderr(), " -- caused:\n").ok(),
            };
        });
    } else {
        write!(stderr(), "\n").ok();
    }
    write!(stderr(), "{}: {}", Red.paint(format!("ERROR[{:>4}]", idx)), e).ok();
    e.cause()
}

/// Count errors in `Error::cause()` recursively
fn count_error_causes(e: &Error) -> u64 {
    1 + e.cause().map(|c| count_error_causes(c)).unwrap_or(0)
}

fn print_trace_dbg(idx: u64, e: &Error) {
    debug!("{}: {}", Red.blink().paint(format!("ERROR[{:>4}]", idx)), e);
    if e.cause().is_some() {
        e.cause().map(|c| print_trace_dbg(idx + 1, c));
    }
}

/// Helper functions for `Result<T, E>` types to reduce overhead in the following situations:
///
/// ```ignore
/// function().map_err(|e| { trace_error(&e); e })
/// ```
///
/// and variants
pub trait MapErrTrace {
    type Output;

    fn map_err_trace(self) -> Self;
    fn map_err_dbg_trace(self) -> Self;
    fn map_err_trace_exit(self, code: i32) -> Self;
    fn map_err_trace_exit_unwrap(self, code: i32) -> Self::Output;
    fn map_err_trace_maxdepth(self, max: u64) -> Self;
}

impl<U, E: Error> MapErrTrace for Result<U, E> {
    type Output = U;

    /// Simply call `trace_error()` on the Err (if there is one) and return the error.
    ///
    /// This does nothing besides the side effect of printing the error trace
    fn map_err_trace(self) -> Self {
        self.map_err(|e| { trace_error(&e); e })
    }

    /// Simply call `trace_error_dbg()` on the Err (if there is one) and return the error.
    ///
    /// This does nothing besides the side effect of printing the error trace
    fn map_err_dbg_trace(self) -> Self {
        self.map_err(|e| { trace_error_dbg(&e); e })
    }

    /// Simply call `trace_error_exit(code)` on the Err (if there is one).
    ///
    /// This does not return if there is an Err(e).
    fn map_err_trace_exit(self, code: i32) -> Self {
        self.map_err(|e| { trace_error_exit(&e, code) })
    }

    /// Helper for calling map_err_trace_exit(n).unwrap() in one call
    fn map_err_trace_exit_unwrap(self, code: i32) -> Self::Output {
        self.map_err_trace_exit(code).unwrap()
    }

    /// Simply call `trace_error_maxdepth(max)` on the Err (if there is one) and return the error.
    ///
    /// This does nothing besides the side effect of printing the error trace to a certain depth
    fn map_err_trace_maxdepth(self, max: u64) -> Self {
        self.map_err(|e| { trace_error_maxdepth(&e, max); e })
    }

}

<|endoftext|>


<commit_before>// task/args.rs
// AltOSRust
//
// Created by Daniel Seitz on 12/7/16

//! Arguments used in tasks.
//!
//! This module contains implementations for structs that help pass arguments into a task. The
//! `ArgsBuilder` struct provides an interface specifying what values the arguments to a task should
//! have. Begin by specifying how many arguments a task should take by creating a new `ArgsBuilder`
//! with that capacity, and use the `add_arg_box()` and `add_arg_num()` methods to give each
//! argument a value. Once you have added all the arguments required, call the `finalize()` method
//! to finish up the creation and return a usable `Args` object. For example:
//!
//! ```rust,no_run
//! use altos_core::args::{ArgsBuilder, Args};
//! use altos_core::Priority;
//! use altos_core::syscall::new_task;
//!
//! let mut args = ArgsBuilder::new(2);
//! args = args.add_arg_num(100).add_arg_num(500);
//!
//! new_task(test_task, args.finalize(), 512, Priority::Normal, "args");
//!
//! fn test_task(args: &mut Args) {
//!   let first = args.pop_num(); // first = 100
//!   let second = args.pop_num(); // second = 400
//!   loop {}
//! }
//! ```

use collections::Vec;
use alloc::boxed::Box;

type RawPtr = usize;

/// An Args Builder.
///
/// Use this to construct a new list of arguments to pass into a task. The arguments should be
/// either a pointer to an object or a word length integer.
pub struct ArgsBuilder {
  cap: usize,
  len: usize,
  vec: Vec<RawPtr>,
}

impl ArgsBuilder {
  /// Returns an empty `Args` object.
  ///
  /// Use this if the task you are creating should not take any arguments.
  pub fn empty() -> Args {
    Args::empty()
  }

  /// Creates a new builder with the specified capacity.
  ///
  /// The number of arguments for a task should be known before hand in order to avoid unnecessary
  /// reallocations. Attempting to exceed this capacity will panic the kernel.
  pub fn new(cap: usize) -> Self {
    ArgsBuilder {
      cap: cap,
      len: 0,
      vec: Vec::with_capacity(cap),
    }
  }

  /// Adds an object argument to the list of arguments.
  ///
  /// The argument is a box containing some object. When using the arguments within the task
  /// you must know the type and order of each argument and cast them manually to the correct
  /// object.
  ///
  /// # Examples
  ///
  /// ```rust,no_run
  /// use altos_core::args::ArgsBuilder;
  ///
  /// let mut args = ArgsBuilder::new(2);
  /// args = args.add_box(Box::new(400u16)).add_box(Box::new(100u32));
  /// ```
  ///
  /// # Panics
  ///
  /// This method will panic if you attempt to add more arguments than the capacity allocated.
  #[inline(never)]
  pub fn add_box<T>(mut self, arg: Box<T>) -> Self {
    if self.len >= self.cap {
      panic!("ArgsBuilder::add_arg - added too many arguments!");
    }
    unsafe {
      let cell = self.vec.get_unchecked_mut(self.len);
      *cell = Box::into_raw(arg) as usize;
    }
    self.len += 1;
    self
  }

  /// Adds an integer value to the list of arguments.
  ///
  /// The argument should be a `usize` value. When using the arguments within the task you must
  /// know the type and order of each argument and cast them manually to the correct type.
  ///
  /// # Examples
  ///
  /// ```rust,no_run
  /// use altos_core::args::ArgsBuilder;
  ///
  /// let mut args = ArgsBuilder::new(2);
  /// args = args.add_num(500).add_num(100);
  /// ```
  ///
  /// # Panics
  ///
  /// This method will panic if you attempt to add more arguments than the capacity allocated.
  pub fn add_num(mut self, arg: usize) -> Self {
    if self.len >= self.cap {
      panic!("ArgsBuilder::add_copy - added too many arguments!");
    }
    unsafe {
      let cell = self.vec.get_unchecked_mut(self.len);
      *cell = arg;
    }
    self.len += 1;
    self
  }

  /// Returns a finalized `Args` object.
  ///
  /// After adding all the arguments that are required for the task, call this method to finalize
  /// the construction of the object. The finalized object will be used in the creation of a new
  /// task.
  ///
  /// # Examples
  ///
  /// ```rust,no_run
  /// use altos_core::args::ArgsBuilder;
  ///
  /// let mut args = ArgsBuilder::new(2);
  /// args = args.add_arg_num(100).add_arg_num(500);
  /// let finalized_args = args.finalize();
  /// ```
  pub fn finalize(mut self) -> Args {
    unsafe { self.vec.set_len(self.len) };
    Args::new(self.vec)
  }
}

/// An object representing all of the arguments passed into a task.
///
/// This object contains a list of raw integer values that can be either interpreted as integer
/// values or raw pointer values that can be later casted into references. The task must know the
/// order and type of arguments passed into it in order to correctly interpret them. Unfortunately
/// we can not keep type safety across the task initialization barrier in order to keep tasks
/// uniform.
pub struct Args {
  args: Vec<RawPtr>,
}

impl Args {
  /// Returns an empty `Args` object.
  ///
  /// Use this when a task doesn't require any arguments.
  pub fn empty() -> Self {
    Args { args: Vec::with_capacity(0) }
  }

  /// Returns the next argument interpreted as a boxed object.
  ///
  /// This method unsafely casts the raw pointer value stored in the arguments list as a boxed
  /// value. If you cast it to the incorrect value you will be pointing at garbage or some unknown
  /// structure.
  ///
  /// # Examples
  ///
  /// ```rust,no_run
  /// use altos_core::args::ArgsBuilder;
  /// use altos_core::alloc::boxed::Box;
  ///
  /// struct Data(usize);
  ///
  /// let mut args = ArgsBuilder::new(1);
  ///
  /// args = args.add_arg_box(Box::new(Data(100)));
  ///
  /// let mut my_args = args.finalize();
  ///
  /// let my_data: Box<Data> = unsafe { my_args.pop_box::<Data>() };
  /// ```
  ///
  /// # Panics
  ///
  /// This method will panic if there are no more arguments to retrieve.
  pub unsafe fn pop_box<T>(&mut self) -> Box<T> {
    let ptr = self.args.pop().unwrap();
    Box::from_raw(ptr as *mut T)
  }

  /// Returns the next argument interpreted as a number.
  ///
  /// This method is safe because even if the argument is not the type you intended, you cannot
  /// unsafely dereference any arbitrary memory addresses.
  ///
  /// # Examples
  ///
  /// ```rust,no_run
  /// use altos_core::args::ArgsBuilder;
  ///
  /// let mut args = ArgsBuilder::new(1);
  ///
  /// args = args.add_arg_num(100);
  ///
  /// let mut my_args = args.finalize();
  ///
  /// let my_data: usize = my_args.pop_num();
  /// ```
  ///
  /// # Panics
  ///
  /// This method will panic if there are no more arguments to retrieve.
  pub fn pop_num(&mut self) -> usize {
    self.args.pop().unwrap()
  }

  fn new(args: Vec<RawPtr>) -> Self {
    Args { args: args }
  }
}
<commit_msg>fix doc tests<commit_after>// task/args.rs
// AltOSRust
//
// Created by Daniel Seitz on 12/7/16

//! Arguments used in tasks.
//!
//! This module contains implementations for structs that help pass arguments into a task. The
//! `ArgsBuilder` struct provides an interface specifying what values the arguments to a task should
//! have. Begin by specifying how many arguments a task should take by creating a new `ArgsBuilder`
//! with that capacity, and use the `add_box()` and `add_num()` methods to give each
//! argument a value. Once you have added all the arguments required, call the `finalize()` method
//! to finish up the creation and return a usable `Args` object. For example:
//!
//! ```rust,no_run
//! use altos_core::args::{ArgsBuilder, Args};
//! use altos_core::Priority;
//! use altos_core::syscall::new_task;
//!
//! let mut args = ArgsBuilder::new(2);
//! args = args.add_num(100).add_num(500);
//!
//! new_task(test_task, args.finalize(), 512, Priority::Normal, "args");
//!
//! fn test_task(args: &mut Args) {
//!   let first = args.pop_num(); // first = 100
//!   let second = args.pop_num(); // second = 400
//!   loop {}
//! }
//! ```

use collections::Vec;
use alloc::boxed::Box;

type RawPtr = usize;

/// An Args Builder.
///
/// Use this to construct a new list of arguments to pass into a task. The arguments should be
/// either a pointer to an object or a word length integer.
pub struct ArgsBuilder {
  cap: usize,
  len: usize,
  vec: Vec<RawPtr>,
}

impl ArgsBuilder {
  /// Returns an empty `Args` object.
  ///
  /// Use this if the task you are creating should not take any arguments.
  pub fn empty() -> Args {
    Args::empty()
  }

  /// Creates a new builder with the specified capacity.
  ///
  /// The number of arguments for a task should be known before hand in order to avoid unnecessary
  /// reallocations. Attempting to exceed this capacity will panic the kernel.
  pub fn new(cap: usize) -> Self {
    ArgsBuilder {
      cap: cap,
      len: 0,
      vec: Vec::with_capacity(cap),
    }
  }

  /// Adds an object argument to the list of arguments.
  ///
  /// The argument is a box containing some object. When using the arguments within the task
  /// you must know the type and order of each argument and cast them manually to the correct
  /// object.
  ///
  /// # Examples
  ///
  /// ```rust,no_run
  /// use altos_core::args::ArgsBuilder;
  ///
  /// let mut args = ArgsBuilder::new(2);
  /// args = args.add_box(Box::new(400u16)).add_box(Box::new(100u32));
  /// ```
  ///
  /// # Panics
  ///
  /// This method will panic if you attempt to add more arguments than the capacity allocated.
  #[inline(never)]
  pub fn add_box<T>(mut self, arg: Box<T>) -> Self {
    if self.len >= self.cap {
      panic!("ArgsBuilder::add_arg - added too many arguments!");
    }
    unsafe {
      let cell = self.vec.get_unchecked_mut(self.len);
      *cell = Box::into_raw(arg) as usize;
    }
    self.len += 1;
    self
  }

  /// Adds an integer value to the list of arguments.
  ///
  /// The argument should be a `usize` value. When using the arguments within the task you must
  /// know the type and order of each argument and cast them manually to the correct type.
  ///
  /// # Examples
  ///
  /// ```rust,no_run
  /// use altos_core::args::ArgsBuilder;
  ///
  /// let mut args = ArgsBuilder::new(2);
  /// args = args.add_num(500).add_num(100);
  /// ```
  ///
  /// # Panics
  ///
  /// This method will panic if you attempt to add more arguments than the capacity allocated.
  pub fn add_num(mut self, arg: usize) -> Self {
    if self.len >= self.cap {
      panic!("ArgsBuilder::add_copy - added too many arguments!");
    }
    unsafe {
      let cell = self.vec.get_unchecked_mut(self.len);
      *cell = arg;
    }
    self.len += 1;
    self
  }

  /// Returns a finalized `Args` object.
  ///
  /// After adding all the arguments that are required for the task, call this method to finalize
  /// the construction of the object. The finalized object will be used in the creation of a new
  /// task.
  ///
  /// # Examples
  ///
  /// ```rust,no_run
  /// use altos_core::args::ArgsBuilder;
  ///
  /// let mut args = ArgsBuilder::new(2);
  /// args = args.add_num(100).add_num(500);
  /// let finalized_args = args.finalize();
  /// ```
  pub fn finalize(mut self) -> Args {
    unsafe { self.vec.set_len(self.len) };
    Args::new(self.vec)
  }
}

/// An object representing all of the arguments passed into a task.
///
/// This object contains a list of raw integer values that can be either interpreted as integer
/// values or raw pointer values that can be later casted into references. The task must know the
/// order and type of arguments passed into it in order to correctly interpret them. Unfortunately
/// we can not keep type safety across the task initialization barrier in order to keep tasks
/// uniform.
pub struct Args {
  args: Vec<RawPtr>,
}

impl Args {
  /// Returns an empty `Args` object.
  ///
  /// Use this when a task doesn't require any arguments.
  pub fn empty() -> Self {
    Args { args: Vec::with_capacity(0) }
  }

  /// Returns the next argument interpreted as a boxed object.
  ///
  /// This method unsafely casts the raw pointer value stored in the arguments list as a boxed
  /// value. If you cast it to the incorrect value you will be pointing at garbage or some unknown
  /// structure.
  ///
  /// # Examples
  ///
  /// ```rust,no_run
  /// use altos_core::args::ArgsBuilder;
  /// use altos_core::alloc::boxed::Box;
  ///
  /// struct Data(usize);
  ///
  /// let mut args = ArgsBuilder::new(1);
  ///
  /// args = args.add_box(Box::new(Data(100)));
  ///
  /// let mut my_args = args.finalize();
  ///
  /// let my_data: Box<Data> = unsafe { my_args.pop_box::<Data>() };
  /// ```
  ///
  /// # Panics
  ///
  /// This method will panic if there are no more arguments to retrieve.
  pub unsafe fn pop_box<T>(&mut self) -> Box<T> {
    let ptr = self.args.pop().unwrap();
    Box::from_raw(ptr as *mut T)
  }

  /// Returns the next argument interpreted as a number.
  ///
  /// This method is safe because even if the argument is not the type you intended, you cannot
  /// unsafely dereference any arbitrary memory addresses.
  ///
  /// # Examples
  ///
  /// ```rust,no_run
  /// use altos_core::args::ArgsBuilder;
  ///
  /// let mut args = ArgsBuilder::new(1);
  ///
  /// args = args.add_num(100);
  ///
  /// let mut my_args = args.finalize();
  ///
  /// let my_data: usize = my_args.pop_num();
  /// ```
  ///
  /// # Panics
  ///
  /// This method will panic if there are no more arguments to retrieve.
  pub fn pop_num(&mut self) -> usize {
    self.args.pop().unwrap()
  }

  fn new(args: Vec<RawPtr>) -> Self {
    Args { args: args }
  }
}
<|endoftext|>


<commit_before>/*

  This struct essentially encapsulates the "instance variables"

*/
#[derive(Debug)]
pub struct SimpleHdrHistogram {
    pub leading_zeros_count_base: usize,
    pub sub_bucket_mask: u64,
    pub unit_magnitude: u32,
    pub sub_bucket_count: usize,
    pub sub_bucket_half_count: usize,
    pub sub_bucket_half_count_magnitude: u32,
    pub counts: Vec<u64>,
    pub counts_array_length: usize,
    pub normalizing_index_offset: usize,
}

/*

  Implementing this trait (Default) for our struct gives us a nice way to
  initialize an instance using default args instead of having to provide all of them

 */
impl Default for SimpleHdrHistogram {
    fn default () -> SimpleHdrHistogram {
        SimpleHdrHistogram {
            leading_zeros_count_base: 0,
            sub_bucket_mask: 0,
            unit_magnitude: 0,
            sub_bucket_count: 0,
            sub_bucket_half_count: 0,
            sub_bucket_half_count_magnitude: 0,
            counts: Vec::new(),
            counts_array_length: 0,
            normalizing_index_offset: 0,
        }
    }
}

pub trait HistogramBase {

    //FIXME this stuff could be mostly unsigned

    //TODO should be default impl of this trait
    fn record_single_value(&mut self, value: u64) -> Result<(), String>;

    //TODO should be default impl of this trait
    fn counts_array_index(&self, value: u64) -> Result<usize, String>;

    //TODO should be default impl of this trait
    fn counts_array_index_sub(&self, bucket_index: usize, sub_bucket_index: usize) -> usize;

    //TODO should be default impl of this trait
    fn get_bucket_index(&self, value: u64) -> usize;

    //TODO should be default impl of this trait
    fn get_sub_bucket_index(&self, value: u64, bucket_index: usize) -> usize;

    fn increment_count_at_index(&mut self, index: usize) -> Result<(), String>;
    fn normalize_index(&self, index: usize, normalizing_index_offset: usize, array_length: usize) ->
        Result<usize, String>;

}

impl HistogramBase for SimpleHdrHistogram {

    fn normalize_index(&self, index: usize, normalizing_index_offset: usize, array_length: usize) ->
Result<usize, String> {

        match normalizing_index_offset {
            0 => Ok(index),
            _ =>
                if ((index > array_length) || (index < 0)) {
                    Err(String::from("index out of covered range"))
                } else {
                    let mut normalized_index: usize = index - normalizing_index_offset;
                    if (normalized_index < 0) {
                        normalized_index += array_length;
                    } else if (normalized_index >= array_length) {
                        normalized_index -=array_length;
                    }
                    Ok(normalized_index)
                }
        }

    }

    fn increment_count_at_index(&mut self, index: usize) -> Result<(), String> {
        let normalized_index =
            self.normalize_index(index, self.normalizing_index_offset, self.counts_array_length);
        match normalized_index {
            Ok(the_index) => {
                self.counts[the_index] += 1;
                Ok(())
            }
            Err(err) =>
                Err(err)
        }
    }

    fn get_sub_bucket_index(&self, value: u64, bucket_index: usize) -> usize {
        let sum = bucket_index + self.unit_magnitude as usize;
        value.rotate_right(sum as u32) as usize
    }

    fn get_bucket_index(&self, value: u64) -> usize {
        let valueOrred = value | self.sub_bucket_mask;
        self.leading_zeros_count_base - (valueOrred.leading_zeros() as usize)
    }

    fn record_single_value(&mut self, value: u64) -> Result<(), String> {

        match self.counts_array_index(value) {
            Ok(counts_index) =>
                match self.increment_count_at_index(counts_index) {
                    Ok(_) =>
                        if true {
                            Ok(())
                        } else {
                            Err(String::from("Could not record single value"))
                        },
                    Err(err) => Err(String::from("Could not increment stuff"))
                },
            Err(err) => Err(String::from("Could not get index"))
        }

    }

    fn counts_array_index(&self, value: u64) -> Result<usize, String> {
        if value < 0 {
            Err(String::from("Histogram recorded values cannot be negative."))
        } else {
            let bucket_index = self.get_bucket_index(value);
            let sub_bucket_index = self.get_sub_bucket_index(value, bucket_index);
            let result = self.counts_array_index_sub(bucket_index, sub_bucket_index);
            Ok(result)
        }
    }

    fn counts_array_index_sub(&self, bucket_index: usize, sub_bucket_index: usize) -> usize {
        assert!(sub_bucket_index < self.sub_bucket_count);
        assert!(bucket_index == 0 || (sub_bucket_index >= self.sub_bucket_half_count));

        let bucket_base_index = (bucket_index + 1) << self.sub_bucket_half_count_magnitude;
        let offset_in_bucket = sub_bucket_index - self.sub_bucket_half_count;

        bucket_base_index + offset_in_bucket
    }
}

#[test]
fn can_record_single_value() {
    let mut the_hist = SimpleHdrHistogram { ..Default::default() };
    let result = the_hist.record_single_value(99);

    match result {
        Ok(_) => (),
        Err(err) => panic!(format!("could not add single record to histogram because error: {}", err))
    }
}

#[test]
fn can_compute_counts_array_index() {
    let mut the_hist = init_histo(1, 1000, 5);
    let result = the_hist.counts_array_index(99);

    match result {
        Ok(_) => (),
        Err(err) => panic!(format!("could not compute counts array index because error: {}", err))
    }
}

#[test]
fn can_get_bucket_index() {
    let mut the_hist = init_histo(1, 1000, 5);
    let result = the_hist.get_bucket_index(99);
    assert_eq!(result, 0)
}

#[test]
fn can_get_sub_bucket_index() {
    let mut the_hist = init_histo(1, 1000, 5);
    let result = the_hist.get_sub_bucket_index(99, 1);
    assert_eq!(result, 0)
}

/// lowest_discernible_value: must be >= 1
/// highest_trackable_value: must be >= 2 * lowest_discernible_value
/// num_significant_digits: must be <= 5
fn init_histo(lowest_discernible_value: u64, highest_trackable_value: u64, num_significant_digits: u32) -> SimpleHdrHistogram {

    assert!(lowest_discernible_value >= 1);
    assert!(highest_trackable_value >= 2 * lowest_discernible_value);
    assert!(num_significant_digits <= 5);

    let mut hist =  SimpleHdrHistogram { ..Default::default() };

    let largest_value_with_single_unit_resolution = 2_u64 * 10_u64.pow(num_significant_digits);

    let unit_magnitude = ((lowest_discernible_value as f64).ln() / 2_f64.ln()) as u32;
    let unit_magnitude_mask: u64  = 1_u64.rotate_left(unit_magnitude) - 1;

    // find nearest power of 2 to largest_value_with_single_unit_resolution
    let sub_bucket_count_magnitude: u32 =
        ((largest_value_with_single_unit_resolution as f64).ln() / 2_f64.ln()).ceil() as u32;

    // ugly looking... how should ternaries be done?
    let sub_bucket_half_count_magnitude: u32 = (if sub_bucket_count_magnitude > 1 { sub_bucket_count_magnitude } else { 1 }) - 1;
    let sub_bucket_count: usize = 2_usize.pow(sub_bucket_half_count_magnitude + 1);
    let sub_bucket_half_count: usize = sub_bucket_count / 2;
    // TODO is this cast OK?
    let sub_bucket_mask = (sub_bucket_count - 1).rotate_left(unit_magnitude) as u64;

    let counts_arr_len = counts_arr_len(highest_trackable_value, sub_bucket_count, unit_magnitude);
    let bucket_count = buckets_needed_for_value(highest_trackable_value, sub_bucket_count, unit_magnitude);

    let leading_zero_count_base: usize = (64_u32 - unit_magnitude - sub_bucket_half_count_magnitude - 1) as usize;

    hist.leading_zeros_count_base = leading_zero_count_base;
    hist.sub_bucket_mask = sub_bucket_mask;
    hist.unit_magnitude = unit_magnitude;
    hist.sub_bucket_count = sub_bucket_count;
    hist.sub_bucket_half_count = sub_bucket_half_count;
    hist.sub_bucket_half_count_magnitude = sub_bucket_half_count_magnitude;
    hist.counts = Vec::with_capacity(counts_arr_len);
    hist.counts_array_length = counts_arr_len;
    hist.normalizing_index_offset = 0_usize; // 0 for normal Histogram ctor in Java impl

    println!("hist: {:?}", hist);

    hist
}

fn buckets_needed_for_value(value: u64, sub_bucket_count: usize, unit_magnitude: u32) -> usize {

    // is this cast ok?
    let mut smallest_untrackable_value: u64 = sub_bucket_count.rotate_left(unit_magnitude) as u64;
    let mut buckets_needed: usize = 1;

    while smallest_untrackable_value <= value {
        if (smallest_untrackable_value > u64::max_value() / 2) {
            return buckets_needed + 1;
        }

        smallest_untrackable_value = smallest_untrackable_value.rotate_left(1);
        buckets_needed += 1;
    }

    return buckets_needed;
}

fn counts_arr_len_for_buckets(buckets: usize, sub_bucket_count: usize) -> usize {
    (buckets + 1) * (sub_bucket_count / 2)
}

fn counts_arr_len(value: u64, sub_bucket_count: usize, unit_magnitude: u32) -> usize {
    counts_arr_len_for_buckets(buckets_needed_for_value(value, sub_bucket_count, unit_magnitude), sub_bucket_count)
}<commit_msg>update min and max<commit_after>/*

  This struct essentially encapsulates the "instance variables"

*/
#[derive(Debug)]
pub struct SimpleHdrHistogram {
    pub leading_zeros_count_base: usize,
    pub sub_bucket_mask: u64,
    pub unit_magnitude: u32,
    pub sub_bucket_count: usize,
    pub sub_bucket_half_count: usize,
    pub sub_bucket_half_count_magnitude: u32,
    pub counts: Vec<u64>,
    pub counts_array_length: usize,
    pub normalizing_index_offset: usize,
    pub max_value: u64,
    pub min_non_zero_value: u64,
    pub unit_magnitude_mask: u64,
}

/*

  Implementing this trait (Default) for our struct gives us a nice way to
  initialize an instance using default args instead of having to provide all of them

 */
impl Default for SimpleHdrHistogram {
    fn default () -> SimpleHdrHistogram {
        SimpleHdrHistogram {
            leading_zeros_count_base: 0,
            sub_bucket_mask: 0,
            unit_magnitude: 0,
            sub_bucket_count: 0,
            sub_bucket_half_count: 0,
            sub_bucket_half_count_magnitude: 0,
            counts: Vec::new(),
            counts_array_length: 0,
            normalizing_index_offset: 0,
            max_value: 0,
            min_non_zero_value: u64::max_value(),
            unit_magnitude_mask: 0,
        }
    }
}

pub trait HistogramBase {

    //FIXME this stuff could be mostly unsigned

    //TODO this block should be default impl of this trait
    fn record_single_value(&mut self, value: u64) -> Result<(), String>;
    fn counts_array_index(&self, value: u64) -> Result<usize, String>;
    fn counts_array_index_sub(&self, bucket_index: usize, sub_bucket_index: usize) -> usize;
    fn get_bucket_index(&self, value: u64) -> usize;
    fn get_sub_bucket_index(&self, value: u64, bucket_index: usize) -> usize;
    fn update_min_and_max(&mut self, value: u64);
    fn update_max_value(&mut self, value: u64);
    fn update_min_non_zero_value(&mut self, value: u64);
    // end TODO

    fn increment_count_at_index(&mut self, index: usize) -> Result<(), String>;
    fn normalize_index(&self, index: usize, normalizing_index_offset: usize, array_length: usize) ->
        Result<usize, String>;

}

impl HistogramBase for SimpleHdrHistogram {

    fn update_max_value(&mut self, value: u64) {
        let mut internal_value = value | self.unit_magnitude_mask;
        self.max_value = internal_value;
    }

    fn update_min_non_zero_value(&mut self, value: u64) {
        if value <= self.unit_magnitude_mask {
            return
        }
        let internal_value = value & !self.unit_magnitude_mask;
        self.min_non_zero_value = internal_value;
    }

    fn update_min_and_max(&mut self, value: u64) {
        if value > self.max_value {
            self.update_max_value(value);
        }
        if ((value < self.min_non_zero_value) && (value != 0)) {
            self.update_min_non_zero_value(value);
        }
    }

    fn normalize_index(&self, index: usize, normalizing_index_offset: usize, array_length: usize) ->
Result<usize, String> {
        match normalizing_index_offset {
            0 => Ok(index),
            _ =>
                if ((index > array_length) || (index < 0)) {
                    Err(String::from("index out of covered range"))
                } else {
                    let mut normalized_index: usize = index - normalizing_index_offset;
                    if (normalized_index < 0) {
                        normalized_index += array_length;
                    } else if (normalized_index >= array_length) {
                        normalized_index -=array_length;
                    }
                    Ok(normalized_index)
                }
        }
    }

    fn increment_count_at_index(&mut self, index: usize) -> Result<(), String> {
        let normalized_index =
            self.normalize_index(index, self.normalizing_index_offset, self.counts_array_length);
        match normalized_index {
            Ok(the_index) => {
                self.counts[the_index] += 1;
                Ok(())
            }
            Err(err) =>
                Err(err)
        }
    }

    fn get_sub_bucket_index(&self, value: u64, bucket_index: usize) -> usize {
        let sum = bucket_index + self.unit_magnitude as usize;
        value.rotate_right(sum as u32) as usize
    }

    fn get_bucket_index(&self, value: u64) -> usize {
        let valueOrred = value | self.sub_bucket_mask;
        self.leading_zeros_count_base - (valueOrred.leading_zeros() as usize)
    }

    fn record_single_value(&mut self, value: u64) -> Result<(), String> {

        match self.counts_array_index(value) {
            Ok(counts_index) => {
                match self.increment_count_at_index(counts_index) {
                    Ok(_) => {
                        self.update_min_and_max(value);
                        //incrementTotalCount()

                        Err(String::from("Could not record single value"))
                    }
                    Err(err) => { Err(String::from("Could not increment stuff")) }
                }}
            Err(err) => Err(String::from("Could not get index"))
        }

    }

    fn counts_array_index(&self, value: u64) -> Result<usize, String> {
        if value < 0 {
            Err(String::from("Histogram recorded values cannot be negative."))
        } else {
            let bucket_index = self.get_bucket_index(value);
            let sub_bucket_index = self.get_sub_bucket_index(value, bucket_index);
            let result = self.counts_array_index_sub(bucket_index, sub_bucket_index);
            Ok(result)
        }
    }

    fn counts_array_index_sub(&self, bucket_index: usize, sub_bucket_index: usize) -> usize {
        assert!(sub_bucket_index < self.sub_bucket_count);
        assert!(bucket_index == 0 || (sub_bucket_index >= self.sub_bucket_half_count));

        let bucket_base_index = (bucket_index + 1) << self.sub_bucket_half_count_magnitude;
        let offset_in_bucket = sub_bucket_index - self.sub_bucket_half_count;

        bucket_base_index + offset_in_bucket
    }
}

#[test]
fn can_record_single_value() {
    let mut the_hist = SimpleHdrHistogram { ..Default::default() };
    let result = the_hist.record_single_value(99);

    match result {
        Ok(_) => (),
        Err(err) => panic!(format!("could not add single record to histogram because error: {}", err))
    }
}

#[test]
fn can_compute_counts_array_index() {
    let mut the_hist = init_histo(1, 1000, 5);
    let result = the_hist.counts_array_index(99);

    match result {
        Ok(_) => (),
        Err(err) => panic!(format!("could not compute counts array index because error: {}", err))
    }
}

#[test]
fn can_get_bucket_index() {
    let mut the_hist = init_histo(1, 1000, 5);
    let result = the_hist.get_bucket_index(99);
    assert_eq!(result, 0)
}

#[test]
fn can_get_sub_bucket_index() {
    let mut the_hist = init_histo(1, 1000, 5);
    let result = the_hist.get_sub_bucket_index(99, 1);
    assert_eq!(result, 0)
}

/// lowest_discernible_value: must be >= 1
/// highest_trackable_value: must be >= 2 * lowest_discernible_value
/// num_significant_digits: must be <= 5
fn init_histo(lowest_discernible_value: u64, highest_trackable_value: u64, num_significant_digits: u32) -> SimpleHdrHistogram {

    assert!(lowest_discernible_value >= 1);
    assert!(highest_trackable_value >= 2 * lowest_discernible_value);
    assert!(num_significant_digits <= 5);

    let mut hist =  SimpleHdrHistogram { ..Default::default() };

    let largest_value_with_single_unit_resolution = 2_u64 * 10_u64.pow(num_significant_digits);

    let unit_magnitude = ((lowest_discernible_value as f64).ln() / 2_f64.ln()) as u32;
    let unit_magnitude_mask: u64  = 1_u64.rotate_left(unit_magnitude) - 1;

    // find nearest power of 2 to largest_value_with_single_unit_resolution
    let sub_bucket_count_magnitude: u32 =
        ((largest_value_with_single_unit_resolution as f64).ln() / 2_f64.ln()).ceil() as u32;

    // ugly looking... how should ternaries be done?
    let sub_bucket_half_count_magnitude: u32 = (if sub_bucket_count_magnitude > 1 { sub_bucket_count_magnitude } else { 1 }) - 1;
    let sub_bucket_count: usize = 2_usize.pow(sub_bucket_half_count_magnitude + 1);
    let sub_bucket_half_count: usize = sub_bucket_count / 2;
    // TODO is this cast OK?
    let sub_bucket_mask = (sub_bucket_count - 1).rotate_left(unit_magnitude) as u64;

    let counts_arr_len = counts_arr_len(highest_trackable_value, sub_bucket_count, unit_magnitude);
    let bucket_count = buckets_needed_for_value(highest_trackable_value, sub_bucket_count, unit_magnitude);

    let leading_zero_count_base: usize = (64_u32 - unit_magnitude - sub_bucket_half_count_magnitude - 1) as usize;

    hist.leading_zeros_count_base = leading_zero_count_base;
    hist.sub_bucket_mask = sub_bucket_mask;
    hist.unit_magnitude = unit_magnitude;
    hist.sub_bucket_count = sub_bucket_count;
    hist.sub_bucket_half_count = sub_bucket_half_count;
    hist.sub_bucket_half_count_magnitude = sub_bucket_half_count_magnitude;
    hist.counts = Vec::with_capacity(counts_arr_len);
    hist.counts_array_length = counts_arr_len;
    hist.normalizing_index_offset = 0_usize; // 0 for normal Histogram ctor in Java impl

    println!("hist: {:?}", hist);

    hist
}

fn buckets_needed_for_value(value: u64, sub_bucket_count: usize, unit_magnitude: u32) -> usize {

    // is this cast ok?
    let mut smallest_untrackable_value: u64 = sub_bucket_count.rotate_left(unit_magnitude) as u64;
    let mut buckets_needed: usize = 1;

    while smallest_untrackable_value <= value {
        if (smallest_untrackable_value > u64::max_value() / 2) {
            return buckets_needed + 1;
        }

        smallest_untrackable_value = smallest_untrackable_value.rotate_left(1);
        buckets_needed += 1;
    }

    return buckets_needed;
}

fn counts_arr_len_for_buckets(buckets: usize, sub_bucket_count: usize) -> usize {
    (buckets + 1) * (sub_bucket_count / 2)
}

fn counts_arr_len(value: u64, sub_bucket_count: usize, unit_magnitude: u32) -> usize {
    counts_arr_len_for_buckets(buckets_needed_for_value(value, sub_bucket_count, unit_magnitude), sub_bucket_count)
}<|endoftext|>


<commit_before>use dotenv::dotenv;
use teloxide::prelude::*;
use tokio;

mod bot;
mod db;
mod web;

#[actix_rt::main]
async fn main() {
    dotenv().expect("please create an .env file");
    run().await;
}

async fn run() {
    teloxide::enable_logging!();

    let bot_instance = Bot::from_env();

    tokio::select! {
        _ = bot::run(bot_instance) => {},
        _ = web::run() => {}
    }
}
<commit_msg>dont panic when .env is missing<commit_after>use dotenv::dotenv;
use teloxide::prelude::*;
use tokio;

mod bot;
mod db;
mod web;

#[actix_rt::main]
async fn main() {
    dotenv();
    run().await;
}

async fn run() {
    teloxide::enable_logging!();

    let bot_instance = Bot::from_env();

    tokio::select! {
        _ = bot::run(bot_instance) => {},
        _ = web::run() => {}
    }
}
<|endoftext|>


<commit_before>//
// Copyright 2019 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

//! A logger that sends output to an Oak logging channel, for use with
//! the [log facade].
//!
//! [log facade]: https://crates.io/crates/log

extern crate log;
extern crate oak;
#[cfg(test)]
extern crate serial_test;
#[cfg(test)]
#[macro_use]
extern crate serial_test_derive;

#[cfg(test)]
mod tests;

use log::{Level, Log, Metadata, Record, SetLoggerError};
use std::io::Write;

struct OakChannelLogger {
    channel: oak::io::Channel,
}

impl Log for OakChannelLogger {
    fn enabled(&self, metadata: &Metadata) -> bool {
        metadata.level() <= log::max_level()
    }
    fn log(&self, record: &Record) {
        if !self.enabled(record.metadata()) {
            return;
        }
        // Only flush logging channel on newlines.
        let mut channel = std::io::LineWriter::new(self.channel);
        writeln!(
            &mut channel,
            "{}  {} : {} : {}",
            record.level(),
            record.file().unwrap_or_default(),
            record.line().unwrap_or_default(),
            record.args()
        )
        .unwrap();
    }
    fn flush(&self) {}
}

/// Initialize Node-wide default logging.
///
/// Uses the default level (`Debug`) and the default pre-defined port name
/// (`"log"`) for the logging channel from the current Node.
///
/// # Panics
///
/// Panics if a logger has already been set.
pub fn init_default() {
    init(
        Level::Debug,
        oak::WriteHandle {
            handle: oak::channel_find("log"),
        },
    )
    .unwrap();
}

/// Initialize Node-wide logging via a channel.
///
/// Initialize logging at the given level, using the send channel half
/// identified by the given port name.
///
/// # Errors
///
/// An error is returned if a logger has already been set.
pub fn init(level: Level, channel_handle: oak::WriteHandle) -> Result<(), SetLoggerError> {
    log::set_boxed_logger(Box::new(OakChannelLogger {
        channel: oak::io::Channel::new(channel_handle),
    }))?;
    log::set_max_level(level.to_level_filter());
    Ok(())
}
<commit_msg>oak_log: add constants for port names<commit_after>//
// Copyright 2019 The Project Oak Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

//! A logger that sends output to an Oak logging channel, for use with
//! the [log facade].
//!
//! [log facade]: https://crates.io/crates/log

extern crate log;
extern crate oak;
#[cfg(test)]
extern crate serial_test;
#[cfg(test)]
#[macro_use]
extern crate serial_test_derive;

#[cfg(test)]
mod tests;

use log::{Level, Log, Metadata, Record, SetLoggerError};
use std::io::Write;

struct OakChannelLogger {
    channel: oak::io::Channel,
}

impl Log for OakChannelLogger {
    fn enabled(&self, metadata: &Metadata) -> bool {
        metadata.level() <= log::max_level()
    }
    fn log(&self, record: &Record) {
        if !self.enabled(record.metadata()) {
            return;
        }
        // Only flush logging channel on newlines.
        let mut channel = std::io::LineWriter::new(self.channel);
        writeln!(
            &mut channel,
            "{}  {} : {} : {}",
            record.level(),
            record.file().unwrap_or_default(),
            record.line().unwrap_or_default(),
            record.args()
        )
        .unwrap();
    }
    fn flush(&self) {}
}

/// Default port name for the write half of a channel that connects to the
/// logging pseudo-Node.
pub const DEFAULT_PORT_NAME: &str = "log";

/// Implicit port name for the read half of a channel that arrives at the
/// logging pseudo-Node.
pub const IN_PORT_NAME: &str = "in";

/// Initialize Node-wide default logging.
///
/// Uses the default level (`Debug`) and the default pre-defined port name
/// (`"log"`) for the logging channel from the current Node.
///
/// # Panics
///
/// Panics if a logger has already been set.
pub fn init_default() {
    init(
        Level::Debug,
        oak::WriteHandle {
            handle: oak::channel_find(DEFAULT_PORT_NAME),
        },
    )
    .unwrap();
}

/// Initialize Node-wide logging via a channel.
///
/// Initialize logging at the given level, using the send channel half
/// identified by the given port name.
///
/// # Errors
///
/// An error is returned if a logger has already been set.
pub fn init(level: Level, channel_handle: oak::WriteHandle) -> Result<(), SetLoggerError> {
    log::set_boxed_logger(Box::new(OakChannelLogger {
        channel: oak::io::Channel::new(channel_handle),
    }))?;
    log::set_max_level(level.to_level_filter());
    Ok(())
}
<|endoftext|>


<commit_before>// Note, in actual code use this instead https://doc.rust-lang.org/std/collections/struct.LinkedList.html
// Also refer to https://rust-unofficial.github.io/too-many-lists/

pub struct LinkedList<T> {
    head: Option<Box<Node<T>>>,
    size: usize,
}

pub struct Node<T> {
    data: T,
    next: Option<Box<Node<T>>>,
}

impl<T> LinkedList<T> {
    pub fn new() -> Self {
        LinkedList {
            head: None,
            size: 0,
        }
    }

    /// Adds a new node containing the specified value at the start of the LinkedList
    pub fn push(&mut self, e: T) {
        let node = Node {
            data: e,
            next: self.head.take(),
        };
        self.head = Some(Box::new(node));
        self.size += 1;
    }

    /// Removes the node at the beginning of the LinkedList
    pub fn pop(&mut self) -> Option<T> {
        self.head.take().map(|node| {
            self.head = node.next;
            self.size -= 1;
            node.data
        })
    }

    pub fn peek(&self) -> Option<&T> {
        self.head.as_ref().map(|node| {
            &node.data
        })
    }

    pub fn peek_mut(&mut self) -> Option<&mut T> {
        self.head.as_mut().map(|node| {
            &mut node.data
        })
    }
}

impl<T> Drop for LinkedList<T> {
    fn drop(&mut self) {
        let mut cur_link = self.head.take();
        while let Some(mut boxed_node) = cur_link {
            cur_link = boxed_node.next.take();
        }
        self.size = 0;
    }
}

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

    #[test]
    fn an_empty_list_has_size_zero() {
        let list: LinkedList<u32> = LinkedList::new();
        assert_eq!(list.size, 0);
    }

    #[test]
    fn adding_an_element_increases_size() {
        let mut list = LinkedList::new();
        list.push(10);
        assert_eq!(list.size, 1);
    }

    #[test]
    fn adding_and_removing_elements() {
        let mut list = LinkedList::new();
        list.push(22);
        list.push(11);
        let value = list.pop();
        assert_eq!(list.size, 1);
        assert_eq!(value.unwrap(), 11);

        list.push(33);
        list.push(44);
        assert_eq!(list.size, 3);

        let value = list.pop();
        assert_eq!(list.size, 2);
        assert_eq!(value.unwrap(), 44);
    }

    #[test]
    fn peek() {
        let mut list = LinkedList::new();
        assert_eq!(list.peek(), None);
        assert_eq!(list.peek_mut(), None);
        list.push(1); list.push(2); list.push(3);

        assert_eq!(list.peek(), Some(&3));
        assert_eq!(list.peek_mut(), Some(&mut 3));

        list.peek_mut().map(|value| {
            *value = 42
        });

        assert_eq!(list.peek(), Some(&42));
        assert_eq!(list.pop(), Some(42));
    }
}
<commit_msg>linked list<commit_after>// See https://rust-unofficial.github.io/too-many-lists/
// Note, in actual code use this instead https://doc.rust-lang.org/std/collections/struct.LinkedList.html

#[derive(Default)]
pub struct List<T> {
    head: Link<T>,
}

type Link<T> = Option<Box<Node<T>>>;

struct Node<T> {
    elem: T,
    next: Link<T>,
}

impl<T> List<T> {
    pub fn new() -> Self {
        List { head: None }
    }

    pub fn push(&mut self, elem: T) {
        let new_node = Box::new(Node {
            elem,
            next: self.head.take(),
        });

        self.head = Some(new_node);
    }

    pub fn pop(&mut self) -> Option<T> {
        self.head.take().map(|node| {
            self.head = node.next;
            node.elem
        })
    }

    pub fn peek(&self) -> Option<&T> {
        self.head.as_ref().map(|node| &node.elem)
    }

    pub fn peek_mut(&mut self) -> Option<&mut T> {
        self.head.as_mut().map(|node| &mut node.elem)
    }

    #[allow(clippy::should_implement_trait)]
    pub fn into_iter(self) -> IntoIter<T> {
        IntoIter(self)
    }

    pub fn iter(&self) -> Iter<'_, T> {
        Iter {
            next: self.head.as_ref().map(|node| &**node),
        }
    }

    pub fn iter_mut(&mut self) -> IterMut<'_, T> {
        IterMut {
            next: self.head.as_mut().map(|node| &mut **node),
        }
    }
}

impl<T> Drop for List<T> {
    fn drop(&mut self) {
        let mut cur_link = self.head.take();
        while let Some(mut boxed_node) = cur_link {
            cur_link = boxed_node.next.take();
        }
    }
}

pub struct IntoIter<T>(List<T>);

impl<T> Iterator for IntoIter<T> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        // access fields of a tuple struct numerically
        self.0.pop()
    }
}

pub struct Iter<'a, T> {
    next: Option<&'a Node<T>>,
}

impl<'a, T> Iterator for Iter<'a, T> {
    type Item = &'a T;
    fn next(&mut self) -> Option<Self::Item> {
        self.next.map(|node| {
            self.next = node.next.as_ref().map(|node| &**node);
            &node.elem
        })
    }
}

pub struct IterMut<'a, T> {
    next: Option<&'a mut Node<T>>,
}

impl<'a, T> Iterator for IterMut<'a, T> {
    type Item = &'a mut T;

    fn next(&mut self) -> Option<Self::Item> {
        self.next.take().map(|node| {
            self.next = node.next.as_mut().map(|node| &mut **node);
            &mut node.elem
        })
    }
}

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

    #[test]
    fn basics() {
        let mut list = List::new();

        // Check empty list behaves right
        assert_eq!(list.pop(), None);

        // Populate list
        list.push(1);
        list.push(2);
        list.push(3);

        // Check normal removal
        assert_eq!(list.pop(), Some(3));
        assert_eq!(list.pop(), Some(2));

        // Push some more just to make sure nothing's corrupted
        list.push(4);
        list.push(5);

        // Check normal removal
        assert_eq!(list.pop(), Some(5));
        assert_eq!(list.pop(), Some(4));

        // Check exhaustion
        assert_eq!(list.pop(), Some(1));
        assert_eq!(list.pop(), None);
    }

    #[test]
    fn peek() {
        let mut list = List::new();
        assert_eq!(list.peek(), None);
        assert_eq!(list.peek_mut(), None);
        list.push(1);
        list.push(2);
        list.push(3);

        assert_eq!(list.peek(), Some(&3));
        assert_eq!(list.peek_mut(), Some(&mut 3));

        list.peek_mut().map(|value| *value = 42);

        assert_eq!(list.peek(), Some(&42));
        assert_eq!(list.pop(), Some(42));
    }

    #[test]
    fn into_iter() {
        let mut list = List::new();
        list.push(1);
        list.push(2);
        list.push(3);

        let mut iter = list.into_iter();
        assert_eq!(iter.next(), Some(3));
        assert_eq!(iter.next(), Some(2));
        assert_eq!(iter.next(), Some(1));
        assert_eq!(iter.next(), None);
    }

    #[test]
    fn iter() {
        let mut list = List::new();
        list.push(1);
        list.push(2);
        list.push(3);

        let mut iter = list.iter();
        assert_eq!(iter.next(), Some(&3));
        assert_eq!(iter.next(), Some(&2));
        assert_eq!(iter.next(), Some(&1));
    }

    #[test]
    fn iter_mut() {
        let mut list = List::new();
        list.push(1);
        list.push(2);
        list.push(3);

        let mut iter = list.iter_mut();
        assert_eq!(iter.next(), Some(&mut 3));
        assert_eq!(iter.next(), Some(&mut 2));
        assert_eq!(iter.next(), Some(&mut 1));
    }
}
<|endoftext|>