<commit_before>//! limit defines a struct to enforce limits.

#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]

use std::sync::atomic::AtomicUsize;

/// Represents a struct used to enforce a numerical limit.
pub struct Limit {
    upper_bound: usize,
    #[allow(unused)]
    max: AtomicUsize,
}

impl Limit {
    /// Creates a new limit.
    #[inline]
    pub const fn new(upper_bound: usize) -> Self {
        Self { upper_bound, max: AtomicUsize::new(0) }
    }

    /// Creates a new limit.
    #[inline]
    #[cfg(feature = "tracking")]
    pub const fn new_tracking(upper_bound: usize) -> Self {
        Self { upper_bound, max: AtomicUsize::new(1) }
    }

    /// Gets the underlying numeric limit.
    #[inline]
    pub const fn inner(&self) -> usize {
        self.upper_bound
    }

    /// Checks whether the given value is below the limit.
    /// Returns `Ok` when `other` is below `self`, and `Err` otherwise.
    #[inline]
    pub fn check(&self, other: usize) -> Result<(), ()> {
        if other > self.upper_bound {
            Err(())
        } else {
            #[cfg(feature = "tracking")]
            loop {
                use std::sync::atomic::Ordering;
                let old_max = self.max.load(Ordering::Relaxed);
                if other <= old_max || old_max == 0 {
                    break;
                }
                if self
                    .max
                    .compare_exchange_weak(old_max, other, Ordering::Relaxed, Ordering::Relaxed)
                    .is_ok()
                {
                    eprintln!("new max: {}", other);
                }
            }

            Ok(())
        }
    }
}
<commit_msg>Properly cfg the `max` field of Limit<commit_after>//! limit defines a struct to enforce limits.

#![warn(rust_2018_idioms, unused_lifetimes, semicolon_in_expressions_from_macros)]

#[cfg(feature = "tracking")]
use std::sync::atomic::AtomicUsize;

/// Represents a struct used to enforce a numerical limit.
pub struct Limit {
    upper_bound: usize,
    #[cfg(feature = "tracking")]
    max: AtomicUsize,
}

impl Limit {
    /// Creates a new limit.
    #[inline]
    pub const fn new(upper_bound: usize) -> Self {
        Self {
            upper_bound,
            #[cfg(feature = "tracking")]
            max: AtomicUsize::new(0),
        }
    }

    /// Creates a new limit.
    #[inline]
    #[cfg(feature = "tracking")]
    pub const fn new_tracking(upper_bound: usize) -> Self {
        Self {
            upper_bound,
            #[cfg(feature = "tracking")]
            max: AtomicUsize::new(1),
        }
    }

    /// Gets the underlying numeric limit.
    #[inline]
    pub const fn inner(&self) -> usize {
        self.upper_bound
    }

    /// Checks whether the given value is below the limit.
    /// Returns `Ok` when `other` is below `self`, and `Err` otherwise.
    #[inline]
    pub fn check(&self, other: usize) -> Result<(), ()> {
        if other > self.upper_bound {
            Err(())
        } else {
            #[cfg(feature = "tracking")]
            loop {
                use std::sync::atomic::Ordering;
                let old_max = self.max.load(Ordering::Relaxed);
                if other <= old_max || old_max == 0 {
                    break;
                }
                if self
                    .max
                    .compare_exchange_weak(old_max, other, Ordering::Relaxed, Ordering::Relaxed)
                    .is_ok()
                {
                    eprintln!("new max: {}", other);
                }
            }

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


<commit_before>use std::fmt::Write;

/* For branch name dedup */
use std::collections::HashSet;

use util::*;

use std::process;

use timesheet::traits::HasHTML;

#[derive(PartialEq, PartialOrd, Serialize, Deserialize, Debug)]
pub enum EventType {
    Pause,
    Resume,
    Note,
    Commit { hash: String },
}

#[derive(Serialize, Deserialize, Debug)]
struct Event {
    timestamp : u64,
    note      : Option<String>,
    ev_ty     : EventType
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Session {
    pub start    : u64,
    pub end      : u64,
    running  : bool,
    branches : HashSet<String>,
    events   : Vec<Event>,
}

impl Session {
    pub fn new(timestamp: Option<u64>) -> Session {
        let timestamp = match timestamp {
            Some(timestamp) => timestamp,
            None => get_seconds(),
        };
        Session {
            start    : timestamp,
            end      : timestamp + 1,
            running  : true,
            branches : HashSet::<String>::new(),
            events   : Vec::<Event>::new(),
        }
    }

    pub fn is_running(&self) -> bool {
        self.running
    }

    /* TODO: test this! Equality derivation for EventType */
    pub fn is_paused(&self) -> bool {
        self.events.last().map_or(false, |ev| ev.ev_ty == EventType::Pause)
    }

    pub fn update_end(&mut self) {
        self.end = match self.events.len() {
            0 => self.end,
            n => &self.events[n - 1].timestamp + 1,
        }
    }

    pub fn finalize(&mut self, timestamp: Option<u64>) {
        let timestamp = match timestamp {
            None => get_seconds(),
            Some(timestamp) => {
                let is_valid_ts = match self.events.len() {
                    0 => timestamp > self.start,
                    n => {
                        let last_ev = &self.events[n - 1];
                        timestamp > last_ev.timestamp
                    }
                };
                if is_valid_ts {
                    timestamp
                } else {
                    println!("That is not a valid timestamp!");
                    process::exit(0);
                }
            }
        };
        if self.is_running() {
            if self.is_paused() {
                self.push_event(Some(timestamp), None, EventType::Resume);
            }
            self.running = false;
            self.end = timestamp + 1;
        }
    }

    pub fn push_event(&mut self,
                  timestamp : Option<u64>,
                  note      : Option<String>,
                  type_of_event : EventType)
                  -> bool {
        /* Cannot push if session is already finalized. */
        if !self.is_running() {
            println!("Already finalized, cannot push event.");
            return false;
        }

        let timestamp = match timestamp {
            None => {
                let now = get_seconds();
                self.end = now;
                now
            }
            Some(timestamp) => {
                let is_valid_ts = match self.events.len() {
                    0 => timestamp > self.start,
                    n => timestamp > self.events[n - 1].timestamp,
                };
                if is_valid_ts {
                    self.end = timestamp + 1;
                    timestamp
                } else {
                    println!("That timestamp is before the last event.");
                    return false;
                }
            }
        };
        /* TODO: improve logic */
        match type_of_event {
            // TODO: fix this, so both note and ago work...
            EventType::Pause => {
                if self.is_paused() {
                    println!("Already paused.");
                    false
                } else {
                    self.events
                        .push(Event {
                                  timestamp : timestamp,
                                  note      : note,
                                  ev_ty   : EventType::Pause,
                              });
                    true
                }
            }
            EventType::Resume => {
                if !self.is_paused() {
                    println!("Currently not paused.");
                    false
                } else {
                    self.events
                        .push(Event {
                                  timestamp : timestamp,
                                  note      : note,
                                  ev_ty     : EventType::Resume,
                              });
                    true
                }
            }
            EventType::Note => {
                if self.is_paused() {
                    /* Add note to previous pause (last of events vec) */
                    /* If self.is_paused(), then self.len() is always at least 1 */
                    let len = self.events.len();
                    let pause = &mut self.events[len - 1];
                    match pause.note {
                        Some(ref mut already) => {
                            // TODO: handle long strings (also in other types)
                            // TODO: there must be another way other than

                            already.push_str("
");
                            already.push_str(&note.unwrap());
                        }
                        None => pause.note = note,
                    }
                } else {
                    self.events
                        .push(Event {
                                  timestamp : timestamp,
                                  note      : note,
                                  ev_ty     : EventType::Note,
                              })
                };
                true
            }
            /* Commit adding possible only in present */
            EventType::Commit { hash } => {
                if self.is_paused() {
                    self.push_event(None, None, EventType::Resume);
                }
                /* Commit message must be provided */
                if note.is_none() {
                    println!("No commit message found for commit {}.", hash);
                }
                self.events
                    .push(Event {
                              timestamp : get_seconds(),
                              note      : note,
                              ev_ty     : EventType::Commit { hash },
                          });
                true
            }
        }
    }

    pub fn pause_time(&self) -> u64 {
        let mut pause_time = 0;
        let mut last_pause_ts = 0;
        for event in &self.events {
            match event.ev_ty {
                EventType::Pause => last_pause_ts = event.timestamp,
                EventType::Resume => pause_time += event.timestamp - last_pause_ts,
                _ => {}
            }
        }
        pause_time
    }

    pub fn working_time(&self) -> u64 {
        let pause_time = self.pause_time();
        self.end - self.start - pause_time
    }

    pub fn add_branch(&mut self, name: String) {
        if self.is_running() {
            self.branches.insert(name);
        }
    }

    pub fn status(&self) -> String {
        let mut status = String::new();
        write!(&mut status, "Session running since {}.\n",
               sec_to_hms_string(get_seconds() - self.start))
                .unwrap();
        if self.is_paused() {
            write!(&mut status, "    Paused since {}.\n",
                   sec_to_hms_string(get_seconds() - self.events[self.events.len() - 1].timestamp))
                    .unwrap();
        } else {
            match self.events.len() {
                0 => write!(&mut status, "    No events in this session yet!\n").unwrap(),
                n => {
                    write!(&mut status,
                           "    Last event: {:?}, {} ago.\n",
                           &self.events[n - 1].ev_ty,
                           sec_to_hms_string(get_seconds() - self.events[n - 1].timestamp))
                            .unwrap()
                }
            }
        }
        let branch_str = match self.branches.len() {
            0 => String::new(),
            n => {
                self.branches.iter().fold(
                    format!("Worked on {} branches: ", n),
                    |res, s| res + s + " "
                )
            }
        };
        status.push_str(&branch_str);
        status
    }
}

impl HasHTML for Event {
    fn to_html(&self) -> String {
        match self.ev_ty {
            EventType::Pause => {
                match self.note {
                    Some(ref info) => {
                        format!(r#"
{}: Started a pause

{}

"#,
                                ts_to_date(self.timestamp),
                                info.clone())
                    }
                    None => {
                        format!(r#"
{}: Started a pause

"#,
                                ts_to_date(self.timestamp))
                    }
                }
            }
            EventType::Resume => {
                format!(r#"
{}: Resumed work

"#,
                        ts_to_date(self.timestamp))
            }
            /* An EventType::Note note is a Some because it's
             * 'constructor' function takes a String
             * (and not Option<String>)
             */
            EventType::Note => {
                match self.note {
                    Some(ref text) => {
                        format!(r#"
{}: Note: {
}

"#,
                                ts_to_date(self.timestamp),
                                text)
                    }
                    None => unreachable!(),
                }
            }
            /* It is safe to unwrap an EventType::Commit note because if
             * a commit has no message something went really wrong
             * (like parsing the output of `git log` in git_commit_message()
             */
            EventType::Commit { ref hash } => {
                match self.note {
                    Some(ref text) => {
                        format!(r#"
{}: Commit id: {}

message: {}

"#,
                                ts_to_date(self.timestamp),
                                hash,
                                text)
                    }
                    None => unreachable!(),
                }
            }
        }
    }
}

impl HasHTML for Session {
    fn to_html(&self) -> String {
        let mut html = format!(r#"

Session on {}
"#,
                               ts_to_date(self.start));

        for event in &self.events {
            html.push_str(&event.to_html());
        }

        write!(&mut html,
               r#"
Ended on {}
"#,
               ts_to_date(self.end))
                .unwrap();

        let mut branch_str = String::new();
        match self.branches.len() {
            0 => {}
            n => {
                write!(&mut branch_str, "Worked on {} branches: ", n).unwrap();
                for branch in &self.branches {
                    write!(&mut branch_str, "{} ", branch).unwrap();
                }
            }
        };

        write!(&mut html,
               r#"

{}

Worked for {}

Paused for {}

"#,
               branch_str,
               sec_to_hms_string(self.working_time()),
               sec_to_hms_string(self.pause_time()))
                .unwrap();

        write!(&mut html, "
").unwrap();
        html
    }
}<commit_msg>simplify is_paused()<commit_after>use std::fmt::Write;

/* For branch name dedup */
use std::collections::HashSet;

use util::*;

use std::process;

use timesheet::traits::HasHTML;

#[derive(PartialEq, PartialOrd, Serialize, Deserialize, Debug)]
pub enum EventType {
    Pause,
    Resume,
    Note,
    Commit { hash: String },
}

#[derive(Serialize, Deserialize, Debug)]
struct Event {
    timestamp : u64,
    note      : Option<String>,
    ev_ty     : EventType
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Session {
    pub start    : u64,
    pub end      : u64,
    running  : bool,
    branches : HashSet<String>,
    events   : Vec<Event>,
}

impl Session {
    pub fn new(timestamp: Option<u64>) -> Session {
        let timestamp = match timestamp {
            Some(timestamp) => timestamp,
            None => get_seconds(),
        };
        Session {
            start    : timestamp,
            end      : timestamp + 1,
            running  : true,
            branches : HashSet::<String>::new(),
            events   : Vec::<Event>::new(),
        }
    }

    pub fn is_running(&self) -> bool {
        self.running
    }

    pub fn is_paused(&self) -> bool {
        self.events.last().map_or(false, |ev| {
            println!("{:?} is pause: {}", ev.ev_ty,
            ev.ev_ty == EventType::Pause);
            true
        });
        self.events.last().map_or(false, |ev| ev.ev_ty == EventType::Pause)
    }

    pub fn update_end(&mut self) {
        self.end = match self.events.len() {
            0 => self.end,
            n => &self.events[n - 1].timestamp + 1,
        }
    }

    pub fn finalize(&mut self, timestamp: Option<u64>) {
        let timestamp = match timestamp {
            None => get_seconds(),
            Some(timestamp) => {
                let is_valid_ts = match self.events.len() {
                    0 => timestamp > self.start,
                    n => {
                        let last_ev = &self.events[n - 1];
                        timestamp > last_ev.timestamp
                    }
                };
                if is_valid_ts {
                    timestamp
                } else {
                    println!("That is not a valid timestamp!");
                    process::exit(0);
                }
            }
        };
        if self.is_running() {
            if self.is_paused() {
                self.push_event(Some(timestamp), None, EventType::Resume);
            }
            self.running = false;
            self.end = timestamp + 1;
        }
    }

    pub fn push_event(&mut self,
                  timestamp : Option<u64>,
                  note      : Option<String>,
                  type_of_event : EventType)
                  -> bool {
        /* Cannot push if session is already finalized. */
        if !self.is_running() {
            println!("Already finalized, cannot push event.");
            return false;
        }

        let timestamp = match timestamp {
            None => {
                let now = get_seconds();
                self.end = now;
                now
            }
            Some(timestamp) => {
                let is_valid_ts = match self.events.len() {
                    0 => timestamp > self.start,
                    n => timestamp > self.events[n - 1].timestamp,
                };
                if is_valid_ts {
                    self.end = timestamp + 1;
                    timestamp
                } else {
                    println!("That timestamp is before the last event.");
                    return false;
                }
            }
        };
        /* TODO: improve logic */
        match type_of_event {
            // TODO: fix this, so both note and ago work...
            EventType::Pause => {
                if self.is_paused() {
                    println!("Already paused.");
                    false
                } else {
                    self.events
                        .push(Event {
                                  timestamp : timestamp,
                                  note      : note,
                                  ev_ty   : EventType::Pause,
                              });
                    true
                }
            }
            EventType::Resume => {
                if !self.is_paused() {
                    println!("Currently not paused.");
                    false
                } else {
                    self.events
                        .push(Event {
                                  timestamp : timestamp,
                                  note      : note,
                                  ev_ty     : EventType::Resume,
                              });
                    true
                }
            }
            EventType::Note => {
                if self.is_paused() {
                    /* Add note to previous pause (last of events vec) */
                    /* If self.is_paused(), then self.len() is always at least 1 */
                    let len = self.events.len();
                    let pause = &mut self.events[len - 1];
                    match pause.note {
                        Some(ref mut already) => {
                            // TODO: handle long strings (also in other types)
                            // TODO: there must be another way other than

                            already.push_str("
");
                            already.push_str(&note.unwrap());
                        }
                        None => pause.note = note,
                    }
                } else {
                    self.events
                        .push(Event {
                                  timestamp : timestamp,
                                  note      : note,
                                  ev_ty     : EventType::Note,
                              })
                };
                true
            }
            /* Commit adding possible only in present */
            EventType::Commit { hash } => {
                if self.is_paused() {
                    self.push_event(None, None, EventType::Resume);
                }
                /* Commit message must be provided */
                if note.is_none() {
                    println!("No commit message found for commit {}.", hash);
                }
                self.events
                    .push(Event {
                              timestamp : get_seconds(),
                              note      : note,
                              ev_ty     : EventType::Commit { hash },
                          });
                true
            }
        }
    }

    pub fn pause_time(&self) -> u64 {
        let mut pause_time = 0;
        let mut last_pause_ts = 0;
        for event in &self.events {
            match event.ev_ty {
                EventType::Pause => last_pause_ts = event.timestamp,
                EventType::Resume => pause_time += event.timestamp - last_pause_ts,
                _ => {}
            }
        }
        pause_time
    }

    pub fn working_time(&self) -> u64 {
        let pause_time = self.pause_time();
        self.end - self.start - pause_time
    }

    pub fn add_branch(&mut self, name: String) {
        if self.is_running() {
            self.branches.insert(name);
        }
    }

    pub fn status(&self) -> String {
        let mut status = String::new();
        write!(&mut status, "Session running since {}.\n",
               sec_to_hms_string(get_seconds() - self.start))
                .unwrap();
        if self.is_paused() {
            write!(&mut status, "    Paused since {}.\n",
                   sec_to_hms_string(get_seconds() - self.events[self.events.len() - 1].timestamp))
                    .unwrap();
        } else {
            match self.events.len() {
                0 => write!(&mut status, "    No events in this session yet!\n").unwrap(),
                n => {
                    write!(&mut status,
                           "    Last event: {:?}, {} ago.\n",
                           &self.events[n - 1].ev_ty,
                           sec_to_hms_string(get_seconds() - self.events[n - 1].timestamp))
                            .unwrap()
                }
            }
        }
        let branch_str = match self.branches.len() {
            0 => String::new(),
            n => {
                self.branches.iter().fold(
                    format!("Worked on {} branches: ", n),
                    |res, s| res + s + " "
                )
            }
        };
        status.push_str(&branch_str);
        status
    }
}

impl HasHTML for Event {
    fn to_html(&self) -> String {
        match self.ev_ty {
            EventType::Pause => {
                match self.note {
                    Some(ref info) => {
                        format!(r#"
{}: Started a pause

{}

"#,
                                ts_to_date(self.timestamp),
                                info.clone())
                    }
                    None => {
                        format!(r#"
{}: Started a pause

"#,
                                ts_to_date(self.timestamp))
                    }
                }
            }
            EventType::Resume => {
                format!(r#"
{}: Resumed work

"#,
                        ts_to_date(self.timestamp))
            }
            /* An EventType::Note note is a Some because it's
             * 'constructor' function takes a String
             * (and not Option<String>)
             */
            EventType::Note => {
                match self.note {
                    Some(ref text) => {
                        format!(r#"
{}: Note: {
}

"#,
                                ts_to_date(self.timestamp),
                                text)
                    }
                    None => unreachable!(),
                }
            }
            /* It is safe to unwrap an EventType::Commit note because if
             * a commit has no message something went really wrong
             * (like parsing the output of `git log` in git_commit_message()
             */
            EventType::Commit { ref hash } => {
                match self.note {
                    Some(ref text) => {
                        format!(r#"
{}: Commit id: {}

message: {}

"#,
                                ts_to_date(self.timestamp),
                                hash,
                                text)
                    }
                    None => unreachable!(),
                }
            }
        }
    }
}

impl HasHTML for Session {
    fn to_html(&self) -> String {
        let mut html = format!(r#"

Session on {}
"#,
                               ts_to_date(self.start));

        for event in &self.events {
            html.push_str(&event.to_html());
        }

        write!(&mut html,
               r#"
Ended on {}
"#,
               ts_to_date(self.end))
                .unwrap();

        let mut branch_str = String::new();
        match self.branches.len() {
            0 => {}
            n => {
                write!(&mut branch_str, "Worked on {} branches: ", n).unwrap();
                for branch in &self.branches {
                    write!(&mut branch_str, "{} ", branch).unwrap();
                }
            }
        };

        write!(&mut html,
               r#"

{}

Worked for {}

Paused for {}

"#,
               branch_str,
               sec_to_hms_string(self.working_time()),
               sec_to_hms_string(self.pause_time()))
                .unwrap();

        write!(&mut html, "
").unwrap();
        html
    }
}
<|endoftext|>


<commit_before>// From Varnish source code:
/*
 * Shared memory log format
 *
 * The log member points to an array of 32bit unsigned integers containing
 * log records.
 *
 * Each logrecord consist of:
 *    [n]               = ((type & 0xff) << 24) | (length & 0xffff)
 *    [n + 1]           = ((marker & 0x03) << 30) | (identifier & 0x3fffffff)
 *    [n + 2] ... [m]   = content (NUL-terminated)
 *
 * Logrecords are NUL-terminated so that string functions can be run
 * directly on the shmlog data.
 *
 * Notice that the constants in these macros cannot be changed without
 * changing corresponding magic numbers in varnishd/cache/cache_shmlog.c
 *
 * VSL_CLIENT(ptr)
 *   Non-zero if this is a client transaction
 *
 * VSL_BACKEND(ptr)
 *   Non-zero if this is a backend transaction
 */

use std::mem;

use nom::{self, le_u32};

use super::{
    VslRecord,
    VslRecordHeader,
    Marker,
    VslRecordTag,
};

const VSL_LENOFFSET: u32 = 24;
const VSL_LENMASK: u32 = 0xffff;
const VSL_IDENTOFFSET: u8 = 30;
const VSL_IDENTMASK: u32 = !(0b0000_0011 << VSL_IDENTOFFSET);

named!(pub binary_vsl_tag<&[u8], Option<&[u8]> >, opt!(complete!(tag!(b"VSL\0"))));

fn vsl_record_header(input: &[u8]) -> nom::IResult<&[u8], VslRecordHeader, u32> {
    chain!(
        input, r1: le_u32 ~ r2: le_u32,
        || VslRecordHeader {
            tag: (r1 >> VSL_LENOFFSET) as u8,
            len: (r1 & VSL_LENMASK) as u16,
            marker: Marker::from_bits_truncate(((r2 & !VSL_IDENTMASK) >> VSL_IDENTOFFSET) as u8),
            ident: r2 & VSL_IDENTMASK,
        })
}

fn to_vsl_record_tag(num: u8) -> VslRecordTag {
    let num = num as u32;

    // Warning: we need to make sure that num is an existing VslRecordTag variant or program will crash!
    // TODO: there needs to be a better way than this!
    if num > VslRecordTag::SLT_HitMiss as u32 && num < VslRecordTag::SLT__Reserved as u32 {
        return VslRecordTag::SLT__Bogus
    }

    unsafe { mem::transmute(num as u32) }
}

pub fn vsl_record_v4(input: &[u8]) -> nom::IResult<&[u8], VslRecord, u32> {
    chain!(
        input,
        header: vsl_record_header ~
        data: take!(header.len - 1) ~ take!(1) ~ take!((4 - header.len % 4) % 4),
        || VslRecord {
            tag: to_vsl_record_tag(header.tag),
            marker: header.marker,
            ident: header.ident,
            data: data
        })
}
<commit_msg>include new tags<commit_after>// From Varnish source code:
/*
 * Shared memory log format
 *
 * The log member points to an array of 32bit unsigned integers containing
 * log records.
 *
 * Each logrecord consist of:
 *    [n]               = ((type & 0xff) << 24) | (length & 0xffff)
 *    [n + 1]           = ((marker & 0x03) << 30) | (identifier & 0x3fffffff)
 *    [n + 2] ... [m]   = content (NUL-terminated)
 *
 * Logrecords are NUL-terminated so that string functions can be run
 * directly on the shmlog data.
 *
 * Notice that the constants in these macros cannot be changed without
 * changing corresponding magic numbers in varnishd/cache/cache_shmlog.c
 *
 * VSL_CLIENT(ptr)
 *   Non-zero if this is a client transaction
 *
 * VSL_BACKEND(ptr)
 *   Non-zero if this is a backend transaction
 */

use std::mem;

use nom::{self, le_u32};

use super::{
    VslRecord,
    VslRecordHeader,
    Marker,
    VslRecordTag,
};

const VSL_LENOFFSET: u32 = 24;
const VSL_LENMASK: u32 = 0xffff;
const VSL_IDENTOFFSET: u8 = 30;
const VSL_IDENTMASK: u32 = !(0b0000_0011 << VSL_IDENTOFFSET);

named!(pub binary_vsl_tag<&[u8], Option<&[u8]> >, opt!(complete!(tag!(b"VSL\0"))));

fn vsl_record_header(input: &[u8]) -> nom::IResult<&[u8], VslRecordHeader, u32> {
    chain!(
        input, r1: le_u32 ~ r2: le_u32,
        || VslRecordHeader {
            tag: (r1 >> VSL_LENOFFSET) as u8,
            len: (r1 & VSL_LENMASK) as u16,
            marker: Marker::from_bits_truncate(((r2 & !VSL_IDENTMASK) >> VSL_IDENTOFFSET) as u8),
            ident: r2 & VSL_IDENTMASK,
        })
}

fn to_vsl_record_tag(num: u8) -> VslRecordTag {
    let num = num as u32;

    // Warning: we need to make sure that num is an existing VslRecordTag variant or program will crash!
    // TODO: there needs to be a better way than this!
    if num > VslRecordTag::SLT_SessError as u32 && num < VslRecordTag::SLT__Reserved as u32 {
        return VslRecordTag::SLT__Bogus
    }

    unsafe { mem::transmute(num as u32) }
}

pub fn vsl_record_v4(input: &[u8]) -> nom::IResult<&[u8], VslRecord, u32> {
    chain!(
        input,
        header: vsl_record_header ~
        data: take!(header.len - 1) ~ take!(1) ~ take!((4 - header.len % 4) % 4),
        || VslRecord {
            tag: to_vsl_record_tag(header.tag),
            marker: header.marker,
            ident: header.ident,
            data: data
        })
}
<|endoftext|>


<commit_before>//! Support types for generated encoding tables.
//!
//! This module contains types and functions for working with the encoding tables generated by
//! `lib/cretonne/meta/gen_encoding.py`.

use constant_hash::{Table, probe};
use ir::{Type, Opcode, DataFlowGraph, InstructionData};
use isa::{Encoding, Legalize};
use settings::PredicateView;
use std::ops::Range;

/// A recipe predicate.
///
/// This is a predicate function capable of testing ISA and instruction predicates simultaneously.
///
/// A None predicate is always satisfied.
pub type RecipePredicate = Option<fn(PredicateView, &InstructionData) -> bool>;

/// An instruction predicate.
///
/// This is a predicate function that needs to be tested in addition to the recipe predicate. It
/// can't depend on ISA settings.
pub type InstPredicate = fn(&DataFlowGraph, &InstructionData) -> bool;

/// Legalization action to perform when no encoding can be found for an instruction.
///
/// This is an index into an ISA-specific table of legalization actions.
pub type LegalizeCode = u8;

/// Level 1 hash table entry.
///
/// One level 1 hash table is generated per CPU mode. This table is keyed by the controlling type
/// variable, using `VOID` for non-polymorphic instructions.
///
/// The hash table values are references to level 2 hash tables, encoded as an offset in `LEVEL2`
/// where the table begins, and the binary logarithm of its length. All the level 2 hash tables
/// have a power-of-two size.
///
/// Entries are generic over the offset type. It will typically be `u32` or `u16`, depending on the
/// size of the `LEVEL2` table.
///
/// Empty entries are encoded with a `!0` value for `log2len` which will always be out of range.
/// Entries that have a `legalize` value but no level 2 table have an `offset` field that is out f
/// bounds.
pub struct Level1Entry<OffT: Into<u32> + Copy> {
    pub ty: Type,
    pub log2len: u8,
    pub legalize: LegalizeCode,
    pub offset: OffT,
}

impl<OffT: Into<u32> + Copy> Level1Entry<OffT> {
    /// Get the level 2 table range indicated by this entry.
    fn range(&self) -> Range<usize> {
        let b = self.offset.into() as usize;
        b..b + (1 << self.log2len)
    }
}

impl<OffT: Into<u32> + Copy> Table<Type> for [Level1Entry<OffT>] {
    fn len(&self) -> usize {
        self.len()
    }

    fn key(&self, idx: usize) -> Option<Type> {
        if self[idx].log2len != !0 {
            Some(self[idx].ty)
        } else {
            None
        }
    }
}

/// Level 2 hash table entry.
///
/// The second level hash tables are keyed by `Opcode`, and contain an offset into the `ENCLISTS`
/// table where the encoding recipes for the instruction are stored.
///
/// Entries are generic over the offset type which depends on the size of `ENCLISTS`. A `u16`
/// offset allows the entries to be only 32 bits each. There is no benefit to dropping down to `u8`
/// for tiny ISAs. The entries won't shrink below 32 bits since the opcode is expected to be 16
/// bits.
///
/// Empty entries are encoded with a `NotAnOpcode` `opcode` field.
pub struct Level2Entry<OffT: Into<u32> + Copy> {
    pub opcode: Option<Opcode>,
    pub offset: OffT,
}

impl<OffT: Into<u32> + Copy> Table<Opcode> for [Level2Entry<OffT>] {
    fn len(&self) -> usize {
        self.len()
    }

    fn key(&self, idx: usize) -> Option<Opcode> {
        self[idx].opcode
    }
}

/// Two-level hash table lookup and iterator construction.
///
/// Given the controlling type variable and instruction opcode, find the corresponding encoding
/// list.
///
/// Returns an iterator that produces legal encodings for `inst`.
pub fn lookup_enclist<'a, OffT1, OffT2>(
    ctrl_typevar: Type,
    inst: &'a InstructionData,
    dfg: &'a DataFlowGraph,
    level1_table: &'static [Level1Entry<OffT1>],
    level2_table: &'static [Level2Entry<OffT2>],
    enclist: &'static [EncListEntry],
    legalize_actions: &'static [Legalize],
    recipe_preds: &'static [RecipePredicate],
    inst_preds: &'static [InstPredicate],
    isa_preds: PredicateView<'a>,
) -> Encodings<'a>
where
    OffT1: Into<u32> + Copy,
    OffT2: Into<u32> + Copy,
{
    let (offset, legalize) = match probe(level1_table, ctrl_typevar, ctrl_typevar.index()) {
        Err(l1idx) => {
            // No level 1 entry found for the type.
            // We have a sentinel entry with the default legalization code.
            (!0, level1_table[l1idx].legalize)
        }
        Ok(l1idx) => {
            // We have a valid level 1 entry for this type.
            let l1ent = &level1_table[l1idx];
            let offset = match level2_table.get(l1ent.range()) {
                Some(l2tab) => {
                    let opcode = inst.opcode();
                    match probe(l2tab, opcode, opcode as usize) {
                        Ok(l2idx) => l2tab[l2idx].offset.into() as usize,
                        Err(_) => !0,
                    }
                }
                // The l1ent range is invalid. This means that we just have a customized
                // legalization code for this type. The level 2 table is empty.
                None => !0,
            };
            (offset, l1ent.legalize)
        }
    };

    // Now we have an offset into `enclist` that is `!0` when no encoding list could be found.
    // The default legalization code is always valid.
    Encodings::new(
        offset,
        legalize,
        inst,
        dfg,
        enclist,
        legalize_actions,
        recipe_preds,
        inst_preds,
        isa_preds,
    )
}

/// Encoding list entry.
///
/// Encoding lists are represented as sequences of u16 words.
pub type EncListEntry = u16;

/// Number of bits used to represent a predicate. c.f. `meta/gen_encoding.py`.
const PRED_BITS: u8 = 12;
const PRED_MASK: usize = (1 << PRED_BITS) - 1;
/// First code word representing a predicate check. c.f. `meta/gen_encoding.py`.
const PRED_START: usize = 0x1000;

/// An iterator over legal encodings for the instruction.
pub struct Encodings<'a> {
    // Current offset into `enclist`, or out of bounds after we've reached the end.
    offset: usize,
    // Legalization code to use of no encoding is found.
    legalize: LegalizeCode,
    inst: &'a InstructionData,
    dfg: &'a DataFlowGraph,
    enclist: &'static [EncListEntry],
    legalize_actions: &'static [Legalize],
    recipe_preds: &'static [RecipePredicate],
    inst_preds: &'static [InstPredicate],
    isa_preds: PredicateView<'a>,
}

impl<'a> Encodings<'a> {
    /// Creates a new instance of `Encodings`.
    ///
    /// This iterator provides search for encodings that applies to the given instruction. The
    /// encoding lists are laid out such that first call to `next` returns valid entry in the list
    /// or `None`.
    pub fn new(
        offset: usize,
        legalize: LegalizeCode,
        inst: &'a InstructionData,
        dfg: &'a DataFlowGraph,
        enclist: &'static [EncListEntry],
        legalize_actions: &'static [Legalize],
        recipe_preds: &'static [RecipePredicate],
        inst_preds: &'static [InstPredicate],
        isa_preds: PredicateView<'a>,
    ) -> Self {
        Encodings {
            offset,
            inst,
            dfg,
            legalize,
            isa_preds,
            recipe_preds,
            inst_preds,
            enclist,
            legalize_actions,
        }
    }

    /// Get the legalization action that caused the enumeration of encodings to stop.
    /// This can be the default legalization action for the type or a custom code for the
    /// instruction.
    ///
    /// This method must only be called after the iterator returns `None`.
    pub fn legalize(&self) -> Legalize {
        debug_assert_eq!(self.offset, !0, "Premature Encodings::legalize()");
        self.legalize_actions[self.legalize as usize]
    }

    /// Check if the `rpred` recipe predicate s satisfied.
    fn check_recipe(&self, rpred: RecipePredicate) -> bool {
        match rpred {
            Some(p) => p(self.isa_preds, self.inst),
            None => true,
        }
    }

    /// Check an instruction or isa predicate.
    fn check_pred(&self, pred: usize) -> bool {
        if let Some(&p) = self.inst_preds.get(pred) {
            p(self.dfg, self.inst)
        } else {
            let pred = pred - self.inst_preds.len();
            self.isa_preds.test(pred)
        }
    }
}

impl<'a> Iterator for Encodings<'a> {
    type Item = Encoding;

    fn next(&mut self) -> Option<Encoding> {
        while let Some(entryref) = self.enclist.get(self.offset) {
            let entry = *entryref as usize;

            // Check for "recipe+bits".
            let recipe = entry >> 1;
            if let Some(&rpred) = self.recipe_preds.get(recipe) {
                let bits = self.offset + 1;
                if entry & 1 == 0 {
                    self.offset += 2; // Next entry.
                } else {
                    self.offset = !0; // Stop.
                }
                if self.check_recipe(rpred) {
                    return Some(Encoding::new(recipe as u16, self.enclist[bits]));
                }
                continue;
            }

            // Check for "stop with legalize".
            if entry < PRED_START {
                self.legalize = (entry - 2 * self.recipe_preds.len()) as LegalizeCode;
                self.offset = !0; // Stop.
                return None;
            }

            // Finally, this must be a predicate entry.
            let pred_entry = entry - PRED_START;
            let skip = pred_entry >> PRED_BITS;
            let pred = pred_entry & PRED_MASK;

            if self.check_pred(pred) {
                self.offset += 1;
            } else if skip == 0 {
                self.offset = !0; // Stop.
                return None;
            } else {
                self.offset += 1 + skip;
            }
        }
        None
    }
}
<commit_msg>Fix a typo in a comment.<commit_after>//! Support types for generated encoding tables.
//!
//! This module contains types and functions for working with the encoding tables generated by
//! `lib/cretonne/meta/gen_encoding.py`.

use constant_hash::{Table, probe};
use ir::{Type, Opcode, DataFlowGraph, InstructionData};
use isa::{Encoding, Legalize};
use settings::PredicateView;
use std::ops::Range;

/// A recipe predicate.
///
/// This is a predicate function capable of testing ISA and instruction predicates simultaneously.
///
/// A None predicate is always satisfied.
pub type RecipePredicate = Option<fn(PredicateView, &InstructionData) -> bool>;

/// An instruction predicate.
///
/// This is a predicate function that needs to be tested in addition to the recipe predicate. It
/// can't depend on ISA settings.
pub type InstPredicate = fn(&DataFlowGraph, &InstructionData) -> bool;

/// Legalization action to perform when no encoding can be found for an instruction.
///
/// This is an index into an ISA-specific table of legalization actions.
pub type LegalizeCode = u8;

/// Level 1 hash table entry.
///
/// One level 1 hash table is generated per CPU mode. This table is keyed by the controlling type
/// variable, using `VOID` for non-polymorphic instructions.
///
/// The hash table values are references to level 2 hash tables, encoded as an offset in `LEVEL2`
/// where the table begins, and the binary logarithm of its length. All the level 2 hash tables
/// have a power-of-two size.
///
/// Entries are generic over the offset type. It will typically be `u32` or `u16`, depending on the
/// size of the `LEVEL2` table.
///
/// Empty entries are encoded with a `!0` value for `log2len` which will always be out of range.
/// Entries that have a `legalize` value but no level 2 table have an `offset` field that is out f
/// bounds.
pub struct Level1Entry<OffT: Into<u32> + Copy> {
    pub ty: Type,
    pub log2len: u8,
    pub legalize: LegalizeCode,
    pub offset: OffT,
}

impl<OffT: Into<u32> + Copy> Level1Entry<OffT> {
    /// Get the level 2 table range indicated by this entry.
    fn range(&self) -> Range<usize> {
        let b = self.offset.into() as usize;
        b..b + (1 << self.log2len)
    }
}

impl<OffT: Into<u32> + Copy> Table<Type> for [Level1Entry<OffT>] {
    fn len(&self) -> usize {
        self.len()
    }

    fn key(&self, idx: usize) -> Option<Type> {
        if self[idx].log2len != !0 {
            Some(self[idx].ty)
        } else {
            None
        }
    }
}

/// Level 2 hash table entry.
///
/// The second level hash tables are keyed by `Opcode`, and contain an offset into the `ENCLISTS`
/// table where the encoding recipes for the instruction are stored.
///
/// Entries are generic over the offset type which depends on the size of `ENCLISTS`. A `u16`
/// offset allows the entries to be only 32 bits each. There is no benefit to dropping down to `u8`
/// for tiny ISAs. The entries won't shrink below 32 bits since the opcode is expected to be 16
/// bits.
///
/// Empty entries are encoded with a `NotAnOpcode` `opcode` field.
pub struct Level2Entry<OffT: Into<u32> + Copy> {
    pub opcode: Option<Opcode>,
    pub offset: OffT,
}

impl<OffT: Into<u32> + Copy> Table<Opcode> for [Level2Entry<OffT>] {
    fn len(&self) -> usize {
        self.len()
    }

    fn key(&self, idx: usize) -> Option<Opcode> {
        self[idx].opcode
    }
}

/// Two-level hash table lookup and iterator construction.
///
/// Given the controlling type variable and instruction opcode, find the corresponding encoding
/// list.
///
/// Returns an iterator that produces legal encodings for `inst`.
pub fn lookup_enclist<'a, OffT1, OffT2>(
    ctrl_typevar: Type,
    inst: &'a InstructionData,
    dfg: &'a DataFlowGraph,
    level1_table: &'static [Level1Entry<OffT1>],
    level2_table: &'static [Level2Entry<OffT2>],
    enclist: &'static [EncListEntry],
    legalize_actions: &'static [Legalize],
    recipe_preds: &'static [RecipePredicate],
    inst_preds: &'static [InstPredicate],
    isa_preds: PredicateView<'a>,
) -> Encodings<'a>
where
    OffT1: Into<u32> + Copy,
    OffT2: Into<u32> + Copy,
{
    let (offset, legalize) = match probe(level1_table, ctrl_typevar, ctrl_typevar.index()) {
        Err(l1idx) => {
            // No level 1 entry found for the type.
            // We have a sentinel entry with the default legalization code.
            (!0, level1_table[l1idx].legalize)
        }
        Ok(l1idx) => {
            // We have a valid level 1 entry for this type.
            let l1ent = &level1_table[l1idx];
            let offset = match level2_table.get(l1ent.range()) {
                Some(l2tab) => {
                    let opcode = inst.opcode();
                    match probe(l2tab, opcode, opcode as usize) {
                        Ok(l2idx) => l2tab[l2idx].offset.into() as usize,
                        Err(_) => !0,
                    }
                }
                // The l1ent range is invalid. This means that we just have a customized
                // legalization code for this type. The level 2 table is empty.
                None => !0,
            };
            (offset, l1ent.legalize)
        }
    };

    // Now we have an offset into `enclist` that is `!0` when no encoding list could be found.
    // The default legalization code is always valid.
    Encodings::new(
        offset,
        legalize,
        inst,
        dfg,
        enclist,
        legalize_actions,
        recipe_preds,
        inst_preds,
        isa_preds,
    )
}

/// Encoding list entry.
///
/// Encoding lists are represented as sequences of u16 words.
pub type EncListEntry = u16;

/// Number of bits used to represent a predicate. c.f. `meta/gen_encoding.py`.
const PRED_BITS: u8 = 12;
const PRED_MASK: usize = (1 << PRED_BITS) - 1;
/// First code word representing a predicate check. c.f. `meta/gen_encoding.py`.
const PRED_START: usize = 0x1000;

/// An iterator over legal encodings for the instruction.
pub struct Encodings<'a> {
    // Current offset into `enclist`, or out of bounds after we've reached the end.
    offset: usize,
    // Legalization code to use of no encoding is found.
    legalize: LegalizeCode,
    inst: &'a InstructionData,
    dfg: &'a DataFlowGraph,
    enclist: &'static [EncListEntry],
    legalize_actions: &'static [Legalize],
    recipe_preds: &'static [RecipePredicate],
    inst_preds: &'static [InstPredicate],
    isa_preds: PredicateView<'a>,
}

impl<'a> Encodings<'a> {
    /// Creates a new instance of `Encodings`.
    ///
    /// This iterator provides search for encodings that applies to the given instruction. The
    /// encoding lists are laid out such that first call to `next` returns valid entry in the list
    /// or `None`.
    pub fn new(
        offset: usize,
        legalize: LegalizeCode,
        inst: &'a InstructionData,
        dfg: &'a DataFlowGraph,
        enclist: &'static [EncListEntry],
        legalize_actions: &'static [Legalize],
        recipe_preds: &'static [RecipePredicate],
        inst_preds: &'static [InstPredicate],
        isa_preds: PredicateView<'a>,
    ) -> Self {
        Encodings {
            offset,
            inst,
            dfg,
            legalize,
            isa_preds,
            recipe_preds,
            inst_preds,
            enclist,
            legalize_actions,
        }
    }

    /// Get the legalization action that caused the enumeration of encodings to stop.
    /// This can be the default legalization action for the type or a custom code for the
    /// instruction.
    ///
    /// This method must only be called after the iterator returns `None`.
    pub fn legalize(&self) -> Legalize {
        debug_assert_eq!(self.offset, !0, "Premature Encodings::legalize()");
        self.legalize_actions[self.legalize as usize]
    }

    /// Check if the `rpred` recipe predicate is satisfied.
    fn check_recipe(&self, rpred: RecipePredicate) -> bool {
        match rpred {
            Some(p) => p(self.isa_preds, self.inst),
            None => true,
        }
    }

    /// Check an instruction or isa predicate.
    fn check_pred(&self, pred: usize) -> bool {
        if let Some(&p) = self.inst_preds.get(pred) {
            p(self.dfg, self.inst)
        } else {
            let pred = pred - self.inst_preds.len();
            self.isa_preds.test(pred)
        }
    }
}

impl<'a> Iterator for Encodings<'a> {
    type Item = Encoding;

    fn next(&mut self) -> Option<Encoding> {
        while let Some(entryref) = self.enclist.get(self.offset) {
            let entry = *entryref as usize;

            // Check for "recipe+bits".
            let recipe = entry >> 1;
            if let Some(&rpred) = self.recipe_preds.get(recipe) {
                let bits = self.offset + 1;
                if entry & 1 == 0 {
                    self.offset += 2; // Next entry.
                } else {
                    self.offset = !0; // Stop.
                }
                if self.check_recipe(rpred) {
                    return Some(Encoding::new(recipe as u16, self.enclist[bits]));
                }
                continue;
            }

            // Check for "stop with legalize".
            if entry < PRED_START {
                self.legalize = (entry - 2 * self.recipe_preds.len()) as LegalizeCode;
                self.offset = !0; // Stop.
                return None;
            }

            // Finally, this must be a predicate entry.
            let pred_entry = entry - PRED_START;
            let skip = pred_entry >> PRED_BITS;
            let pred = pred_entry & PRED_MASK;

            if self.check_pred(pred) {
                self.offset += 1;
            } else if skip == 0 {
                self.offset = !0; // Stop.
                return None;
            } else {
                self.offset += 1 + skip;
            }
        }
        None
    }
}
<|endoftext|>


<commit_before>use std::process::exit;
use chrono::naive::datetime::NaiveDateTime;

use libimagdiary::diary::Diary;
use libimagdiary::diaryid::DiaryId;
use libimagrt::runtime::Runtime;
use libimagerror::trace::trace_error_exit;
use libimagtimeui::datetime::DateTime;
use libimagtimeui::parse::Parse;

use util::get_diary_name;

pub fn delete(rt: &Runtime) {
    use libimaginteraction::ask::ask_bool;

    let diaryname = get_diary_name(rt);
    if diaryname.is_none() {
        warn!("No diary selected. Use either the configuration file or the commandline option");
        exit(1);
    }
    let diaryname = diaryname.unwrap();

    let diary = Diary::open(rt.store(), &diaryname[..]);
    debug!("Diary opened: {:?}", diary);

    let datetime : Option<NaiveDateTime> = rt
        .cli()
        .subcommand_matches("delete")
        .unwrap()
        .value_of("datetime")
        .map(|dt| { debug!("DateTime = {:?}", dt); dt })
        .and_then(DateTime::parse)
        .map(|dt| dt.into());

    let to_del = match datetime {
        Some(dt) => Some(diary.retrieve(DiaryId::from_datetime(diaryname.clone(), dt))),
        None     => diary.get_youngest_entry(),
    };

    let to_del = match to_del {
        Some(Ok(e)) => e,

        Some(Err(e)) => trace_error_exit(&e, 1),
        None => {
            warn!("No entry");
            exit(1);
        },
    };

    if !ask_bool(&format!("Deleting {:?}", to_del.get_location())[..], Some(true)) {
        info!("Aborting delete action");
        return;
    }

    match diary.delete_entry(to_del) {
        Ok(_) => info!("Ok"),
        Err(e) => trace_error_exit(&e, 1),
    }
}

<commit_msg>Replace complex match with `if let Err(e)`<commit_after>use std::process::exit;
use chrono::naive::datetime::NaiveDateTime;

use libimagdiary::diary::Diary;
use libimagdiary::diaryid::DiaryId;
use libimagrt::runtime::Runtime;
use libimagerror::trace::trace_error_exit;
use libimagtimeui::datetime::DateTime;
use libimagtimeui::parse::Parse;

use util::get_diary_name;

pub fn delete(rt: &Runtime) {
    use libimaginteraction::ask::ask_bool;

    let diaryname = get_diary_name(rt);
    if diaryname.is_none() {
        warn!("No diary selected. Use either the configuration file or the commandline option");
        exit(1);
    }
    let diaryname = diaryname.unwrap();

    let diary = Diary::open(rt.store(), &diaryname[..]);
    debug!("Diary opened: {:?}", diary);

    let datetime : Option<NaiveDateTime> = rt
        .cli()
        .subcommand_matches("delete")
        .unwrap()
        .value_of("datetime")
        .map(|dt| { debug!("DateTime = {:?}", dt); dt })
        .and_then(DateTime::parse)
        .map(|dt| dt.into());

    let to_del = match datetime {
        Some(dt) => Some(diary.retrieve(DiaryId::from_datetime(diaryname.clone(), dt))),
        None     => diary.get_youngest_entry(),
    };

    let to_del = match to_del {
        Some(Ok(e)) => e,

        Some(Err(e)) => trace_error_exit(&e, 1),
        None => {
            warn!("No entry");
            exit(1);
        },
    };

    if !ask_bool(&format!("Deleting {:?}", to_del.get_location())[..], Some(true)) {
        info!("Aborting delete action");
        return;
    }

    if let Err(e) = diary.delete_entry(to_del) {
        trace_error_exit(&e, 1)
    }

    info!("Ok!");
}

<|endoftext|>


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

use std::iter;

use crate::tyhandlers::{Direction};
use crate::idents;
use crate::model;

/// Expands the `BidirectionalTypeInfo` derive attribute.
///
/// The attribute expansion results in the following items:
///
/// - Implementation of the BidirectionalTypeInfo trait.
pub fn expand_bidirectional_type_info(
    item_tokens: TokenStreamNightly,
) -> Result<TokenStreamNightly, syn::Error>
{
    // Get the name of the type we want to implement the trait for.
    let input: syn::DeriveInput = syn::parse( item_tokens )?;
    let name = &input.ident;

    // Immpl requires the the generics in particular way.
    let (impl_generics, ty_generics, where_clause ) = input.generics.split_for_impl();
    let result = quote!{ impl #impl_generics intercom::type_system::BidirectionalTypeInfo for #name #ty_generics #where_clause {

                /// The default name is the name of the type.
                fn type_name() -> &'static str { stringify!( #name ) }
            } };

    Ok( result.into() )
}

/// Expands the `ExternType` derive attribute.
///
/// The attribute expansion results in the following items:
///
/// - Implementation of the ExternType trait.
pub fn expand_derive_extern_type(
    item_tokens: TokenStreamNightly,
) -> Result<TokenStreamNightly, syn::Error>
{
    // Get the name of the type we want to implement the trait for.
    let input: syn::DeriveInput = syn::parse( item_tokens )?;
    let name = &input.ident;

    // Immpl requires the the generics in particular way.
    let (impl_generics, ty_generics, where_clause ) = input.generics.split_for_impl();
    let result = quote!{ impl<TS: intercom::type_system::TypeSystem> #impl_generics intercom::type_system::ExternType<TS> for #name #ty_generics #where_clause {

                type ExternInputType = #name;
                type ExternOutputType = #name;
                type OwnedExternType = #name;
                type OwnedNativeType = #name;
            } };

    Ok( result.into() )
}
<commit_msg>Clean type_info warnings<commit_after>
use crate::prelude::*;

/// Expands the `BidirectionalTypeInfo` derive attribute.
///
/// The attribute expansion results in the following items:
///
/// - Implementation of the BidirectionalTypeInfo trait.
pub fn expand_bidirectional_type_info(
    item_tokens: TokenStreamNightly,
) -> Result<TokenStreamNightly, syn::Error>
{
    // Get the name of the type we want to implement the trait for.
    let input: syn::DeriveInput = syn::parse( item_tokens )?;
    let name = &input.ident;

    // Immpl requires the the generics in particular way.
    let (impl_generics, ty_generics, where_clause ) = input.generics.split_for_impl();
    let result = quote!{ impl #impl_generics intercom::type_system::BidirectionalTypeInfo for #name #ty_generics #where_clause {

                /// The default name is the name of the type.
                fn type_name() -> &'static str { stringify!( #name ) }
            } };

    Ok( result.into() )
}

/// Expands the `ExternType` derive attribute.
///
/// The attribute expansion results in the following items:
///
/// - Implementation of the ExternType trait.
pub fn expand_derive_extern_type(
    item_tokens: TokenStreamNightly,
) -> Result<TokenStreamNightly, syn::Error>
{
    // Get the name of the type we want to implement the trait for.
    let input: syn::DeriveInput = syn::parse( item_tokens )?;
    let name = &input.ident;

    // Immpl requires the the generics in particular way.
    let (impl_generics, ty_generics, where_clause ) = input.generics.split_for_impl();
    let result = quote!{ impl<TS: intercom::type_system::TypeSystem> #impl_generics intercom::type_system::ExternType<TS> for #name #ty_generics #where_clause {

                type ExternInputType = #name;
                type ExternOutputType = #name;
                type OwnedExternType = #name;
                type OwnedNativeType = #name;
            } };

    Ok( result.into() )
}
<|endoftext|>


<commit_before>//!

use collections::{Map, Set};
use ena::unify::UnificationTable;
use grammar::repr::*;
use lr1::build;
use lr1::core::*;
use lr1::first::FirstSets;
use lr1::lookahead::{Lookahead, TokenSet};
use lr1::lane_table::lane::LaneTracer;
use lr1::lane_table::table::{ConflictIndex, LaneTable};
use lr1::lane_table::table::context_set::OverlappingLookahead;
use lr1::state_graph::StateGraph;
use std::rc::Rc;

mod merge;
use self::merge::Merge;

mod state_set;
use self::state_set::StateSet;

pub struct LaneTableConstruct<'grammar> {
    grammar: &'grammar Grammar,
    first_sets: FirstSets,
    start_nt: NonterminalString,
}

impl<'grammar> LaneTableConstruct<'grammar> {
    pub fn new(grammar: &'grammar Grammar, start_nt: NonterminalString) -> Self {
        let first_sets = FirstSets::new(grammar);
        LaneTableConstruct {
            grammar: grammar,
            start_nt: start_nt,
            first_sets: first_sets,
        }
    }

    pub fn construct(self) -> Result<Vec<LR1State<'grammar>>, LR1TableConstructionError<'grammar>> {
        let TableConstructionError { states, conflicts: _ } = {
            match build::build_lr0_states(self.grammar, self.start_nt) {
                // This is the easy (and very rare...) case.
                Ok(lr0) => return Ok(self.promote_lr0_states(lr0)),
                Err(err) => err,
            }
        };

        // Convert the LR(0) states into LR(0-1) states.
        let mut states = self.promote_lr0_states(states);

        // For each inconsistent state, apply the lane-table algorithm to
        // resolve it.
        for i in 0.. {
            if i >= states.len() {
                break;
            }

            match self.resolve_inconsistencies(&mut states, StateIndex(i)) {
                Ok(()) => { }
                Err(_) => {
                    // We failed because of irreconcilable conflicts
                    // somewhere. Just compute the conflicts from the final set of
                    // states.
                    debug!("construct: failed to resolve inconsistencies in state {:#?}",
                           states[i]);
                    let conflicts: Vec<Conflict<'grammar, TokenSet>> =
                        states.iter()
                              .flat_map(|s| Lookahead::conflicts(&s))
                              .collect();
                    return Err(TableConstructionError { states: states,
                                                        conflicts: conflicts });
                }
            }
        }

        Ok(states)
    }

    /// Given a set of LR0 states, returns LR1 states where the lookahead
    /// is always `TokenSet::all()`. We refer to these states as LR(0-1)
    /// states in the README.
    fn promote_lr0_states(&self, lr0: Vec<LR0State<'grammar>>) -> Vec<LR1State<'grammar>> {
        let all = TokenSet::all();
        debug!("promote_lr0_states: all={:?}", all);
        lr0.into_iter()
            .map(|s| {
                let items = s.items
                    .vec
                    .iter()
                    .map(|item| {
                        Item {
                            production: item.production,
                            index: item.index,
                            lookahead: all.clone(),
                        }
                    })
                    .collect();
                let reductions = s.reductions
                    .into_iter()
                    .map(|(_, p)| (all.clone(), p))
                    .collect();
                State {
                    index: s.index,
                    items: Items { vec: Rc::new(items) },
                    shifts: s.shifts,
                    reductions: reductions,
                    gotos: s.gotos,
                }
            })
            .collect()
    }

    fn resolve_inconsistencies(&self,
                               states: &mut Vec<LR1State<'grammar>>,
                               inconsistent_state: StateIndex)
                               -> Result<(), StateIndex> {
        debug!("resolve_inconsistencies(inconsistent_state={:?}/{:#?}",
               inconsistent_state, states[inconsistent_state.0]);

        let mut actions = super::conflicting_actions(&states[inconsistent_state.0]);
        if actions.is_empty() {
            // This can mean one of two things: only shifts, or a
            // single reduction. We have to be careful about states
            // with a single reduction: even though such a state is
            // not inconsistent (there is only one possible course of
            // action), we still want to run the lane table algorithm,
            // because otherwise we get states with "complete"
            // lookahead, which messes with error recovery.
            //
            // In particular, if there is too much lookahead, we will
            // reduce even when it is inappropriate to do so.
            actions = states[inconsistent_state.0].reductions
                                                  .iter()
                                                  .map(|&(_, prod)| Action::Reduce(prod))
                                                  .collect();
            if actions.is_empty() {
                return Ok(());
            }
        }

        debug!("resolve_inconsistencies: conflicting_actions={:?}", actions);

        let table = self.build_lane_table(states, inconsistent_state, &actions);

        // Consider first the "LALR" case, where the lookaheads for each
        // action are completely disjoint.
        if self.attempt_lalr(&mut states[inconsistent_state.0], &table, &actions) {
            return Ok(());
        }

        // Construct the initial states; each state will map to a
        // context-set derived from its row in the lane-table. This is
        // fallible, because a state may be internally inconstent.
        //
        // (To handle unification, we also map each state to a
        // `StateSet` that is its entry in the `ena` table.)
        let rows = table.rows()?;
        let mut unify = UnificationTable::<StateSet>::new();
        let mut state_sets = Map::new();
        for (&state_index, context_set) in &rows {
            let state_set = unify.new_key(context_set.clone());
            state_sets.insert(state_index, state_set);
            debug!("resolve_inconsistencies: state_index={:?}, state_set={:?}",
                   state_index, state_set);
        }

        // Now merge state-sets, cloning states where needed.
        let mut merge = Merge::new(&table, &mut unify, states, &mut state_sets, inconsistent_state);
        let beachhead_states = table.beachhead_states();
        for beachhead_state in beachhead_states {
            match merge.start(beachhead_state) {
                Ok(()) => { }
                Err((source, _)) => {
                    debug!("resolve_inconsistencies: failed to merge, source={:?}", source);
                    return Err(source);
                }
            }
        }
        merge.patch_target_starts(&actions);

        Ok(())
    }

    fn attempt_lalr(&self,
                    state: &mut LR1State<'grammar>,
                    table: &LaneTable<'grammar>,
                    actions: &Set<Action<'grammar>>)
                    -> bool {
        match table.columns() {
            Ok(columns) => {
                debug!("attempt_lalr, columns={:#?}", columns);
                columns.apply(state, actions);
                debug!("attempt_lalr, state={:#?}", state);
                true
            }
            Err(OverlappingLookahead) => {
                debug!("attempt_lalr, OverlappingLookahead");
                false
            }
        }
    }

    fn build_lane_table(&self,
                        states: &[LR1State<'grammar>],
                        inconsistent_state: StateIndex,
                        actions: &Set<Action<'grammar>>)
                        -> LaneTable<'grammar> {
        let state_graph = StateGraph::new(states);
        let mut tracer = LaneTracer::new(self.grammar,
                                         self.start_nt,
                                         states,
                                         &self.first_sets,
                                         &state_graph,
                                         actions.len());
        for (i, &action) in actions.iter().enumerate() {
            tracer.start_trace(inconsistent_state, ConflictIndex::new(i), action);
        }
        tracer.into_table()
    }
}
<commit_msg>use lane-table even on LR(0) grammars<commit_after>//!

use collections::{Map, Set};
use ena::unify::UnificationTable;
use grammar::repr::*;
use lr1::build;
use lr1::core::*;
use lr1::first::FirstSets;
use lr1::lookahead::{Lookahead, TokenSet};
use lr1::lane_table::lane::LaneTracer;
use lr1::lane_table::table::{ConflictIndex, LaneTable};
use lr1::lane_table::table::context_set::OverlappingLookahead;
use lr1::state_graph::StateGraph;
use std::rc::Rc;

mod merge;
use self::merge::Merge;

mod state_set;
use self::state_set::StateSet;

pub struct LaneTableConstruct<'grammar> {
    grammar: &'grammar Grammar,
    first_sets: FirstSets,
    start_nt: NonterminalString,
}

impl<'grammar> LaneTableConstruct<'grammar> {
    pub fn new(grammar: &'grammar Grammar, start_nt: NonterminalString) -> Self {
        let first_sets = FirstSets::new(grammar);
        LaneTableConstruct {
            grammar: grammar,
            start_nt: start_nt,
            first_sets: first_sets,
        }
    }

    pub fn construct(self) -> Result<Vec<LR1State<'grammar>>, LR1TableConstructionError<'grammar>> {
        let states = {
            match build::build_lr0_states(self.grammar, self.start_nt) {
                Ok(states) => {
                    // In this case, the grammar is actually
                    // LR(0). This is very rare -- it means that the
                    // grammar does not need lookahead to execute. In
                    // principle, we could stop here, except that if
                    // we do so, then the lookahead values that we get
                    // are very broad.
                    //
                    // Broad lookahead values will cause "eager"
                    // reduce at runtime -- i.e., if there is some
                    // scenario where the lookahead tells you we are
                    // in error, but we would have to reduce a few
                    // states before we see it. This, in turn, can
                    // cause infinite loops around error recovery
                    // (#240).
                    //
                    // Since we want to behave as a LR(1) parser
                    // would, we'll just go ahead and run the
                    // algorithm.
                    states
                }
                Err(TableConstructionError { states, conflicts: _ }) => states,
            }
        };

        // Convert the LR(0) states into LR(0-1) states.
        let mut states = self.promote_lr0_states(states);

        // For each inconsistent state, apply the lane-table algorithm to
        // resolve it.
        for i in 0.. {
            if i >= states.len() {
                break;
            }

            match self.resolve_inconsistencies(&mut states, StateIndex(i)) {
                Ok(()) => { }
                Err(_) => {
                    // We failed because of irreconcilable conflicts
                    // somewhere. Just compute the conflicts from the final set of
                    // states.
                    debug!("construct: failed to resolve inconsistencies in state {:#?}",
                           states[i]);
                    let conflicts: Vec<Conflict<'grammar, TokenSet>> =
                        states.iter()
                              .flat_map(|s| Lookahead::conflicts(&s))
                              .collect();
                    return Err(TableConstructionError { states: states,
                                                        conflicts: conflicts });
                }
            }
        }

        Ok(states)
    }

    /// Given a set of LR0 states, returns LR1 states where the lookahead
    /// is always `TokenSet::all()`. We refer to these states as LR(0-1)
    /// states in the README.
    fn promote_lr0_states(&self, lr0: Vec<LR0State<'grammar>>) -> Vec<LR1State<'grammar>> {
        let all = TokenSet::all();
        debug!("promote_lr0_states: all={:?}", all);
        lr0.into_iter()
            .map(|s| {
                let items = s.items
                    .vec
                    .iter()
                    .map(|item| {
                        Item {
                            production: item.production,
                            index: item.index,
                            lookahead: all.clone(),
                        }
                    })
                    .collect();
                let reductions = s.reductions
                    .into_iter()
                    .map(|(_, p)| (all.clone(), p))
                    .collect();
                State {
                    index: s.index,
                    items: Items { vec: Rc::new(items) },
                    shifts: s.shifts,
                    reductions: reductions,
                    gotos: s.gotos,
                }
            })
            .collect()
    }

    fn resolve_inconsistencies(&self,
                               states: &mut Vec<LR1State<'grammar>>,
                               inconsistent_state: StateIndex)
                               -> Result<(), StateIndex> {
        debug!("resolve_inconsistencies(inconsistent_state={:?}/{:#?}",
               inconsistent_state, states[inconsistent_state.0]);

        let mut actions = super::conflicting_actions(&states[inconsistent_state.0]);
        if actions.is_empty() {
            // This can mean one of two things: only shifts, or a
            // single reduction. We have to be careful about states
            // with a single reduction: even though such a state is
            // not inconsistent (there is only one possible course of
            // action), we still want to run the lane table algorithm,
            // because otherwise we get states with "complete"
            // lookahead, which messes with error recovery.
            //
            // In particular, if there is too much lookahead, we will
            // reduce even when it is inappropriate to do so.
            actions = states[inconsistent_state.0].reductions
                                                  .iter()
                                                  .map(|&(_, prod)| Action::Reduce(prod))
                                                  .collect();
            if actions.is_empty() {
                return Ok(());
            }
        }

        debug!("resolve_inconsistencies: conflicting_actions={:?}", actions);

        let table = self.build_lane_table(states, inconsistent_state, &actions);

        // Consider first the "LALR" case, where the lookaheads for each
        // action are completely disjoint.
        if self.attempt_lalr(&mut states[inconsistent_state.0], &table, &actions) {
            return Ok(());
        }

        // Construct the initial states; each state will map to a
        // context-set derived from its row in the lane-table. This is
        // fallible, because a state may be internally inconstent.
        //
        // (To handle unification, we also map each state to a
        // `StateSet` that is its entry in the `ena` table.)
        let rows = table.rows()?;
        let mut unify = UnificationTable::<StateSet>::new();
        let mut state_sets = Map::new();
        for (&state_index, context_set) in &rows {
            let state_set = unify.new_key(context_set.clone());
            state_sets.insert(state_index, state_set);
            debug!("resolve_inconsistencies: state_index={:?}, state_set={:?}",
                   state_index, state_set);
        }

        // Now merge state-sets, cloning states where needed.
        let mut merge = Merge::new(&table, &mut unify, states, &mut state_sets, inconsistent_state);
        let beachhead_states = table.beachhead_states();
        for beachhead_state in beachhead_states {
            match merge.start(beachhead_state) {
                Ok(()) => { }
                Err((source, _)) => {
                    debug!("resolve_inconsistencies: failed to merge, source={:?}", source);
                    return Err(source);
                }
            }
        }
        merge.patch_target_starts(&actions);

        Ok(())
    }

    fn attempt_lalr(&self,
                    state: &mut LR1State<'grammar>,
                    table: &LaneTable<'grammar>,
                    actions: &Set<Action<'grammar>>)
                    -> bool {
        match table.columns() {
            Ok(columns) => {
                debug!("attempt_lalr, columns={:#?}", columns);
                columns.apply(state, actions);
                debug!("attempt_lalr, state={:#?}", state);
                true
            }
            Err(OverlappingLookahead) => {
                debug!("attempt_lalr, OverlappingLookahead");
                false
            }
        }
    }

    fn build_lane_table(&self,
                        states: &[LR1State<'grammar>],
                        inconsistent_state: StateIndex,
                        actions: &Set<Action<'grammar>>)
                        -> LaneTable<'grammar> {
        let state_graph = StateGraph::new(states);
        let mut tracer = LaneTracer::new(self.grammar,
                                         self.start_nt,
                                         states,
                                         &self.first_sets,
                                         &state_graph,
                                         actions.len());
        for (i, &action) in actions.iter().enumerate() {
            tracer.start_trace(inconsistent_state, ConflictIndex::new(i), action);
        }
        tracer.into_table()
    }
}
<|endoftext|>


<commit_before><commit_msg>Avoid a `Iter::cloned()` call in `AsciiString::push_str`<commit_after><|endoftext|>


<commit_before>//! Super fast HTML template engine.

#![allow(unstable)]

use std::fmt;
use std::io::{IoError, IoErrorKind, IoResult};

/// Escape an HTML value.
pub fn escape(s: &str) -> String {
    let mut buf = String::new();
    rt::escape(&mut buf, |w| w.write_str(s)).unwrap();
    buf
}

/// A block of HTML markup, as returned by the `html!` macro.
pub struct Markup<'a> {
    callback: &'a (Fn(&mut fmt::Writer) -> fmt::Result + 'a),
}

impl<'a> Markup<'a> {
    /// Render the markup to a `String`.
    pub fn render(&self) -> String {
        let mut buf = String::new();
        self.render_fmt(&mut buf).unwrap();
        buf
    }

    /// Render the markup to a `std::io::Writer`.
    pub fn render_to(&self, w: &mut Writer) -> IoResult<()> {
        struct WriterWrapper<'a, 'b: 'a> {
            inner: &'a mut (Writer + 'b),
        }
        impl<'a, 'b> fmt::Writer for WriterWrapper<'a, 'b> {
            fn write_str(&mut self, s: &str) -> fmt::Result {
                self.inner.write_str(s).map_err(|_| fmt::Error)
            }
        }
        self.render_fmt(&mut WriterWrapper { inner: w })
            .map_err(|_| IoError {
                kind: IoErrorKind::OtherIoError,
                desc: "formatting error",
                detail: None,
            })
    }

    /// Render the markup to a `std::fmt::Writer`.
    pub fn render_fmt(&self, w: &mut fmt::Writer) -> fmt::Result {
        (self.callback)(w)
    }
}

/// Internal functions used by the `maud_macros` package. You should
/// never need to call these directly.
#[experimental = "These functions should not be called directly.
Use the macros in `maud_macros` instead."]
pub mod rt {
    use std::fmt;
    use super::Markup;

    #[inline]
    pub fn make_markup<'a>(f: &'a (Fn(&mut fmt::Writer) -> fmt::Result + 'a)) -> Markup<'a> {
        Markup { callback: f }
    }

    struct Escaper<'a, 'b: 'a> {
        inner: &'a mut (fmt::Writer + 'b),
    }

    impl<'a, 'b> fmt::Writer for Escaper<'a, 'b> {
        fn write_str(&mut self, s: &str) -> fmt::Result {
            for c in s.chars() {
                try!(match c {
                    '&' => self.inner.write_str("&"),
                    '<' => self.inner.write_str("<"),
                    '>' => self.inner.write_str(">"),
                    '"' => self.inner.write_str("""),
                    '\'' => self.inner.write_str("'"),
                    _ => write!(self.inner, "{}", c),
                });
            }
            Ok(())
        }
    }

    #[inline]
    pub fn escape<F>(w: &mut fmt::Writer, f: F) -> fmt::Result where
        F: FnOnce(&mut fmt::Writer) -> fmt::Result
    {
        f(&mut Escaper { inner: w })
    }
}
<commit_msg>Mark `rt` module as `#[doc(hidden)]`<commit_after>//! Super fast HTML template engine.

#![allow(unstable)]

use std::fmt;
use std::io::{IoError, IoErrorKind, IoResult};

/// Escape an HTML value.
pub fn escape(s: &str) -> String {
    let mut buf = String::new();
    rt::escape(&mut buf, |w| w.write_str(s)).unwrap();
    buf
}

/// A block of HTML markup, as returned by the `html!` macro.
pub struct Markup<'a> {
    callback: &'a (Fn(&mut fmt::Writer) -> fmt::Result + 'a),
}

impl<'a> Markup<'a> {
    /// Render the markup to a `String`.
    pub fn render(&self) -> String {
        let mut buf = String::new();
        self.render_fmt(&mut buf).unwrap();
        buf
    }

    /// Render the markup to a `std::io::Writer`.
    pub fn render_to(&self, w: &mut Writer) -> IoResult<()> {
        struct WriterWrapper<'a, 'b: 'a> {
            inner: &'a mut (Writer + 'b),
        }
        impl<'a, 'b> fmt::Writer for WriterWrapper<'a, 'b> {
            fn write_str(&mut self, s: &str) -> fmt::Result {
                self.inner.write_str(s).map_err(|_| fmt::Error)
            }
        }
        self.render_fmt(&mut WriterWrapper { inner: w })
            .map_err(|_| IoError {
                kind: IoErrorKind::OtherIoError,
                desc: "formatting error",
                detail: None,
            })
    }

    /// Render the markup to a `std::fmt::Writer`.
    pub fn render_fmt(&self, w: &mut fmt::Writer) -> fmt::Result {
        (self.callback)(w)
    }
}

/// Internal functions used by the `maud_macros` package. You should
/// never need to call these directly.
#[doc(hidden)]
pub mod rt {
    use std::fmt;
    use super::Markup;

    #[inline]
    pub fn make_markup<'a>(f: &'a (Fn(&mut fmt::Writer) -> fmt::Result + 'a)) -> Markup<'a> {
        Markup { callback: f }
    }

    struct Escaper<'a, 'b: 'a> {
        inner: &'a mut (fmt::Writer + 'b),
    }

    impl<'a, 'b> fmt::Writer for Escaper<'a, 'b> {
        fn write_str(&mut self, s: &str) -> fmt::Result {
            for c in s.chars() {
                try!(match c {
                    '&' => self.inner.write_str("&"),
                    '<' => self.inner.write_str("<"),
                    '>' => self.inner.write_str(">"),
                    '"' => self.inner.write_str("""),
                    '\'' => self.inner.write_str("'"),
                    _ => write!(self.inner, "{}", c),
                });
            }
            Ok(())
        }
    }

    #[inline]
    pub fn escape<F>(w: &mut fmt::Writer, f: F) -> fmt::Result where
        F: FnOnce(&mut fmt::Writer) -> fmt::Result
    {
        f(&mut Escaper { inner: w })
    }
}
<|endoftext|>


<commit_before>use regex::Regex;

pub fn split_into_key_value(s: String) -> Option<(String, String)> {
    let r = "^(?P<KEY>(.*))=((\"(?P<DOUBLE_QVAL>(.*))\")|(\'(?P<SINGLE_QVAL>(.*)))\'|(?P<VAL>[^\'\"](.*)[^\'\"]))$";
    let regex = Regex::new(r).unwrap();
    regex.captures(&s[..]).and_then(|cap| {
        cap.name("KEY")
            .map(|name| {
                cap.name("SINGLE_QVAL")
                    .or(cap.name("DOUBLE_QVAL"))
                    .or(cap.name("VAL"))
                    .map(|value| (String::from(name), String::from(value)))
            }).unwrap_or(None)
    })
}

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

    #[test]
    fn test_single_quoted() {
        let s = String::from("foo='bar'");
        assert_eq!(Some((String::from("foo"), String::from("bar"))), split_into_key_value(s));
    }

    #[test]
    fn test_double_quoted() {
        let s = String::from("foo=\"bar\"");
        assert_eq!(Some((String::from("foo"), String::from("bar"))), split_into_key_value(s));
    }

    #[test]
    fn test_double_and_single_quoted() {
        let s = String::from("foo=\"bar\'");
        assert!(split_into_key_value(s).is_none());
    }

    #[test]
    fn test_single_and_double_quoted() {
        let s = String::from("foo=\'bar\"");
        assert!(split_into_key_value(s).is_none());
    }

    #[test]
    fn test_not_quoted() {
        let s = String::from("foo=bar");
        assert_eq!(Some((String::from("foo"), String::from("bar"))), split_into_key_value(s));
    }

}

<commit_msg>Split String->key-value with types<commit_after>use regex::Regex;

use std::convert::Into;
use std::convert::From;

use std::option::Option;

#[derive(Clone, Copy, Debug, PartialEq)]
pub struct KeyValue<K, V> {
    k: K,
    v: V,
}

impl<K, V> KeyValue<K, V> {

    pub fn new(k: K, v: V) -> KeyValue<K, V> {
        KeyValue { k: k, v: v }
    }

}

impl<K, V> Into<(K, V)> for KeyValue<K, V> {

    fn into(self) -> (K, V) {
        (self.k, self.v)
    }

}

pub trait IntoKeyValue<K, V> {
    fn into_kv(self) -> Option<KeyValue<K, V>>;
}

impl IntoKeyValue<String, String> for String {

    fn into_kv(self) -> Option<KeyValue<String, String>> {
        let r = "^(?P<KEY>(.*))=((\"(?P<DOUBLE_QVAL>(.*))\")|(\'(?P<SINGLE_QVAL>(.*)))\'|(?P<VAL>[^\'\"](.*)[^\'\"]))$";
        let regex = Regex::new(r).unwrap();
        regex.captures(&self[..]).and_then(|cap| {
            cap.name("KEY")
                .map(|name| {
                    cap.name("SINGLE_QVAL")
                        .or(cap.name("DOUBLE_QVAL"))
                        .or(cap.name("VAL"))
                        .map(|value| KeyValue::new(String::from(name), String::from(value)))
                }).unwrap_or(None)
        })
    }

}

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

    #[test]
    fn test_single_quoted() {
        let s = String::from("foo='bar'");
        assert_eq!(Some((String::from("foo"), String::from("bar"))), split_into_key_value(s));
    }

    #[test]
    fn test_double_quoted() {
        let s = String::from("foo=\"bar\"");
        assert_eq!(Some((String::from("foo"), String::from("bar"))), split_into_key_value(s));
    }

    #[test]
    fn test_double_and_single_quoted() {
        let s = String::from("foo=\"bar\'");
        assert!(split_into_key_value(s).is_none());
    }

    #[test]
    fn test_single_and_double_quoted() {
        let s = String::from("foo=\'bar\"");
        assert!(split_into_key_value(s).is_none());
    }

    #[test]
    fn test_not_quoted() {
        let s = String::from("foo=bar");
        assert_eq!(Some((String::from("foo"), String::from("bar"))), split_into_key_value(s));
    }

}

<|endoftext|>