<commit_before>use rusqlite::Connection;
use rusqlite::Error;

#[derive(Debug)]
pub struct FsDir {
    pub id: i32,
    pub fk_type: i32,
    pub name: String,
}

pub fn table_create_fs_dir(conn: &Connection) -> &Connection {
    conn.execute("CREATE TABLE FS_DIR (
                  id              INTEGER PRIMARY KEY ASC,
                  fk_type             INTEGER,
                  name            TEXT NOT NULL UNIQUE
                  )", &[]).unwrap();
    return conn;
}

pub fn insert_fs_dir(conn: &Connection, fk_type: i32, name: String) {

    let fs_dir = FsDir {
        id: 0,
        name: name,
        fk_type: fk_type,
    };
    let dir_instance = conn.execute("INSERT INTO FS_DIR (fk_type, name)
                 VALUES (?1, ?2)",
                 &[&fs_dir.fk_type, &fs_dir.name]);
    if dir_instance.is_err() {
        return;
    }
    dir_instance.unwrap();
}

pub fn list_fs_dir(conn: &Connection)-> Vec<FsDir> {
    let mut stmt = conn.prepare("SELECT id, fk_type, name FROM FS_DIR").unwrap();
    let wraped_fs_file_iter = stmt.query_map(&[], |row| {
        FsDir {
            id: row.get(0),
            fk_type: row.get(1),
            name: row.get(2),
        }
    });
    let mut items = Vec::<FsDir>::new();
    if wraped_fs_file_iter.is_err() {
        return items;
    }
    let fs_file_iter = wraped_fs_file_iter.unwrap();
    for person in fs_file_iter {
        items.push(person.unwrap());
    }
    return items;
}

pub fn list_fs_dir_filter(conn: &Connection)-> Vec<FsDir> {
    let filter = "elephant".to_string();
    let mut stmt = conn.prepare("SELECT id, fk_type, name FROM FS_DIR WHERE name = elephant").unwrap();
    let wraped_fs_file_iter = stmt.query_map(&[&filter], |row| {
        FsDir {
            id: row.get(0),
            fk_type: row.get(1),
            name: row.get(2),
        }
    });
    let mut items = Vec::<FsDir>::new();
    if wraped_fs_file_iter.is_err() {
        return items;
    }
    let fs_file_iter = wraped_fs_file_iter.unwrap();
    for person in fs_file_iter {
        items.push(person.unwrap());
    }
    return items;
}
<commit_msg>Add FOREIGN KEY to FS_DIR_TYPE<commit_after>use rusqlite::Connection;
use rusqlite::Error;

#[derive(Debug)]
pub struct FsDir {
    pub id: i32,
    pub fk_type: i32,
    pub name: String,
}

pub fn table_create_fs_dir(conn: &Connection) -> &Connection {
    conn.execute("CREATE TABLE FS_DIR (
                  id              INTEGER PRIMARY KEY ASC,
                  fk_type         INTEGER NOT NULL,
                  name            TEXT NOT NULL UNIQUE,
                  FOREIGN KEY(fk_type) REFERENCES FS_DIR_TYPE(id) ON UPDATE CASCADE
                  )", &[]).unwrap();
    return conn;
}

pub fn insert_fs_dir(conn: &Connection, fk_type: i32, name: String) {

    let fs_dir = FsDir {
        id: 0,
        name: name,
        fk_type: fk_type,
    };
    let dir_instance = conn.execute("INSERT INTO FS_DIR (fk_type, name)
                 VALUES (?1, ?2)",
                 &[&fs_dir.fk_type, &fs_dir.name]);
    if dir_instance.is_err() {
        return;
    }
    dir_instance.unwrap();
}

pub fn list_fs_dir(conn: &Connection)-> Vec<FsDir> {
    let mut stmt = conn.prepare("SELECT id, fk_type, name FROM FS_DIR").unwrap();
    let wraped_fs_file_iter = stmt.query_map(&[], |row| {
        FsDir {
            id: row.get(0),
            fk_type: row.get(1),
            name: row.get(2),
        }
    });
    let mut items = Vec::<FsDir>::new();
    if wraped_fs_file_iter.is_err() {
        return items;
    }
    let fs_file_iter = wraped_fs_file_iter.unwrap();
    for person in fs_file_iter {
        items.push(person.unwrap());
    }
    return items;
}

pub fn list_fs_dir_filter(conn: &Connection)-> Vec<FsDir> {
    let filter = "elephant".to_string();
    let mut stmt = conn.prepare("SELECT id, fk_type, name FROM FS_DIR WHERE name = elephant").unwrap();
    let wraped_fs_file_iter = stmt.query_map(&[&filter], |row| {
        FsDir {
            id: row.get(0),
            fk_type: row.get(1),
            name: row.get(2),
        }
    });
    let mut items = Vec::<FsDir>::new();
    if wraped_fs_file_iter.is_err() {
        return items;
    }
    let fs_file_iter = wraped_fs_file_iter.unwrap();
    for person in fs_file_iter {
        items.push(person.unwrap());
    }
    return items;
}
<|endoftext|>


<commit_before>use std::io;
use std::io::Read;

use serde_json;

use jsontypes::RawSourceMap;
use types::{RawToken, SourceMap, SourceMapIndex, SourceMapSection};
use errors::{Result, Error};

const B64: [i8; 123] = [
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57,
    58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,
    9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1,
    -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
    39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
];

#[derive(PartialEq)]
enum HeaderState {
    Undecided,
    Junk,
    AwaitingNewline,
    PastHeader,
}

pub struct StripHeaderReader<R: Read> {
    r: R,
    header_state: HeaderState,
}

impl<R: Read> StripHeaderReader<R> {
    pub fn new(reader: R) -> StripHeaderReader<R> {
        StripHeaderReader {
            r: reader,
            header_state: HeaderState::Undecided,
        }
    }
}

fn is_junk_json(byte: u8) -> bool {
    byte == b')' || byte == b']' || byte == b'}' || byte == b'\''
}

impl<R: Read> Read for StripHeaderReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if self.header_state == HeaderState::PastHeader {
            return self.r.read(buf);
        }

        let mut backing = vec![0; buf.len()];
        let mut local_buf : &mut [u8] = &mut *backing;

        loop {
            let read = try!(self.r.read(local_buf));
            if read == 0 {
                return Ok(0);
            }
            for (offset, &byte) in local_buf[0..read].iter().enumerate() {
                self.header_state = match self.header_state {
                    HeaderState::Undecided => {
                        if is_junk_json(byte) {
                            HeaderState::Junk
                        } else {
                            (&mut buf[..read]).copy_from_slice(&local_buf[..read]);
                            self.header_state = HeaderState::PastHeader;
                            return Ok(read);
                        }
                    },
                    HeaderState::Junk => {
                        if byte == b'\r' {
                            HeaderState::AwaitingNewline
                        } else if byte == b'\n' {
                            HeaderState::PastHeader
                        } else {
                            HeaderState::Junk
                        }
                    },
                    HeaderState::AwaitingNewline => {
                        if byte == b'\n' {
                            HeaderState::PastHeader
                        } else {
                            fail!(io::Error::new(io::ErrorKind::InvalidData,
                                                 "expected newline"));
                        }
                    },
                    HeaderState::PastHeader => {
                        let rem = read - offset;
                        (&mut buf[..rem]).copy_from_slice(&local_buf[offset..read]);
                        return Ok(rem);
                    }
                };
            }
        }
    }
}

pub fn parse_vlq_segment(segment: &str) -> Result<Vec<i64>> {
    let mut rv = vec![];

    let mut cur = 0;
    let mut shift = 0;

    for c in segment.bytes() {
        let enc = B64[c as usize] as i64;
        let val = enc & 0b11111;
        let cont = enc >> 5;
        cur += val << shift;
        shift += 5;

        if cont == 0 {
            let sign = cur & 1;
            cur = cur >> 1;
            if sign != 0 {
                cur = -cur;
            }
            rv.push(cur);
            cur = 0;
            shift = 0;
        }
    }

    if cur != 0 || shift != 0 {
        Err(Error::VlqLeftover)
    } else if rv.len() == 0 {
        Err(Error::VlqNoValues)
    } else {
        Ok(rv)
    }
}

/// Represents the result of a decode operation
pub enum DecodedMap {
    /// Indicates a regular sourcemap
    Regular(SourceMap),
    /// Indicates a sourcemap index
    Index(SourceMapIndex),
}

fn decode_regular(rsm: RawSourceMap) -> Result<SourceMap> {
    let mut dst_col;
    let mut src_id;
    let mut src_line = 0;
    let mut src_col = 0;
    let mut name_id = 0;

    let mut tokens = vec![];
    let mut index = vec![];

    for (dst_line, line) in rsm.mappings.split(';').enumerate() {
        let mut line_index = vec![];
        dst_col = 0;

        for segment in line.split(',') {
            if segment.len() == 0 {
                continue;
            }

            let nums = try!(parse_vlq_segment(segment));
            dst_col = (dst_col as i64 + nums[0]) as u32;

            let mut src = !0;
            let mut name = !0;

            if nums.len() > 1 {
                if nums.len() != 4 && nums.len() != 5 {
                    fail!(Error::BadSegmentSize(nums.len() as u32));
                }
                src_id = nums[1] as u32;
                if src_id >= rsm.sources.len() as u32 {
                    fail!(Error::BadSourceReference(src_id));
                }

                src = src_id;
                src_line = (src_line as i64 + nums[2]) as u32;
                src_col = (src_col as i64 + nums[3]) as u32;

                if nums.len() > 4 {
                    name_id = (name_id as i64 + nums[4]) as u32;
                    if name_id >= rsm.names.len() as u32 {
                        fail!(Error::BadNameReference(name_id));
                    }
                    name = name_id as u32;
                }
            }

            tokens.push(RawToken {
                dst_line: dst_line as u32,
                dst_col: dst_col,
                src_line: src_line,
                src_col: src_col,
                src_id: src,
                name_id: name,
            });
            line_index.push((dst_col, (tokens.len() - 1) as u32));
        }

        line_index.sort();
        for (dst_col, token_id) in line_index {
            index.push((dst_line as u32, dst_col, token_id));
        }
    }

    let mut sources = rsm.sources;
    if let Some(source_root) = rsm.source_root {
        let source_root = source_root.trim_right_matches('/');
        sources = sources.into_iter().map(|x| {
            if x.len() > 0 && (x.as_bytes()[0] == b'/' ||
                               x.as_bytes()[..5] == b"http:"[..] ||
                               x.as_bytes()[..6] == b"https:"[..]) {
                x
            } else {
                format!("{}/{}", source_root, x)
            }
        }).collect();
    }

    Ok(SourceMap::new(
        rsm.version, rsm.file, tokens, index, rsm.names, sources))
}

fn decode_index(rsm: RawSourceMap) -> Result<SourceMapIndex> {
    let mut sections = vec![];

    for mut raw_section in rsm.sections.unwrap_or(vec![]) {
        sections.push(SourceMapSection::new(
            (raw_section.offset.line, raw_section.offset.column),
            raw_section.url,
            match raw_section.map.take() {
                Some(map) => Some(try!(decode_regular(*map))),
                None => None,
            }
        ));
    }

    Ok(SourceMapIndex::new(
        rsm.version, rsm.file, sections))
}

/// Decodes a sourcemap or sourcemap index from a reader
///
/// This supports both sourcemaps and sourcemap indexes unless the
/// specialized methods on the individual types.
pub fn decode<R: Read>(rdr: R) -> Result<DecodedMap> {
    let mut rdr = StripHeaderReader::new(rdr);
    let rsm : RawSourceMap = try!(serde_json::from_reader(&mut rdr));

    Ok(if rsm.sections.is_some() {
        DecodedMap::Index(try!(decode_index(rsm)))
    } else {
        DecodedMap::Regular(try!(decode_regular(rsm)))
    })
}
<commit_msg>Fixed an issue with joining onto an empty sourcemap<commit_after>use std::io;
use std::io::Read;

use serde_json;

use jsontypes::RawSourceMap;
use types::{RawToken, SourceMap, SourceMapIndex, SourceMapSection};
use errors::{Result, Error};

const B64: [i8; 123] = [
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57,
    58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8,
    9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1,
    -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
    39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
];

#[derive(PartialEq)]
enum HeaderState {
    Undecided,
    Junk,
    AwaitingNewline,
    PastHeader,
}

pub struct StripHeaderReader<R: Read> {
    r: R,
    header_state: HeaderState,
}

impl<R: Read> StripHeaderReader<R> {
    pub fn new(reader: R) -> StripHeaderReader<R> {
        StripHeaderReader {
            r: reader,
            header_state: HeaderState::Undecided,
        }
    }
}

fn is_junk_json(byte: u8) -> bool {
    byte == b')' || byte == b']' || byte == b'}' || byte == b'\''
}

impl<R: Read> Read for StripHeaderReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        if self.header_state == HeaderState::PastHeader {
            return self.r.read(buf);
        }

        let mut backing = vec![0; buf.len()];
        let mut local_buf : &mut [u8] = &mut *backing;

        loop {
            let read = try!(self.r.read(local_buf));
            if read == 0 {
                return Ok(0);
            }
            for (offset, &byte) in local_buf[0..read].iter().enumerate() {
                self.header_state = match self.header_state {
                    HeaderState::Undecided => {
                        if is_junk_json(byte) {
                            HeaderState::Junk
                        } else {
                            (&mut buf[..read]).copy_from_slice(&local_buf[..read]);
                            self.header_state = HeaderState::PastHeader;
                            return Ok(read);
                        }
                    },
                    HeaderState::Junk => {
                        if byte == b'\r' {
                            HeaderState::AwaitingNewline
                        } else if byte == b'\n' {
                            HeaderState::PastHeader
                        } else {
                            HeaderState::Junk
                        }
                    },
                    HeaderState::AwaitingNewline => {
                        if byte == b'\n' {
                            HeaderState::PastHeader
                        } else {
                            fail!(io::Error::new(io::ErrorKind::InvalidData,
                                                 "expected newline"));
                        }
                    },
                    HeaderState::PastHeader => {
                        let rem = read - offset;
                        (&mut buf[..rem]).copy_from_slice(&local_buf[offset..read]);
                        return Ok(rem);
                    }
                };
            }
        }
    }
}

pub fn parse_vlq_segment(segment: &str) -> Result<Vec<i64>> {
    let mut rv = vec![];

    let mut cur = 0;
    let mut shift = 0;

    for c in segment.bytes() {
        let enc = B64[c as usize] as i64;
        let val = enc & 0b11111;
        let cont = enc >> 5;
        cur += val << shift;
        shift += 5;

        if cont == 0 {
            let sign = cur & 1;
            cur = cur >> 1;
            if sign != 0 {
                cur = -cur;
            }
            rv.push(cur);
            cur = 0;
            shift = 0;
        }
    }

    if cur != 0 || shift != 0 {
        Err(Error::VlqLeftover)
    } else if rv.len() == 0 {
        Err(Error::VlqNoValues)
    } else {
        Ok(rv)
    }
}

/// Represents the result of a decode operation
pub enum DecodedMap {
    /// Indicates a regular sourcemap
    Regular(SourceMap),
    /// Indicates a sourcemap index
    Index(SourceMapIndex),
}

fn decode_regular(rsm: RawSourceMap) -> Result<SourceMap> {
    let mut dst_col;
    let mut src_id;
    let mut src_line = 0;
    let mut src_col = 0;
    let mut name_id = 0;

    let mut tokens = vec![];
    let mut index = vec![];

    for (dst_line, line) in rsm.mappings.split(';').enumerate() {
        let mut line_index = vec![];
        dst_col = 0;

        for segment in line.split(',') {
            if segment.len() == 0 {
                continue;
            }

            let nums = try!(parse_vlq_segment(segment));
            dst_col = (dst_col as i64 + nums[0]) as u32;

            let mut src = !0;
            let mut name = !0;

            if nums.len() > 1 {
                if nums.len() != 4 && nums.len() != 5 {
                    fail!(Error::BadSegmentSize(nums.len() as u32));
                }
                src_id = nums[1] as u32;
                if src_id >= rsm.sources.len() as u32 {
                    fail!(Error::BadSourceReference(src_id));
                }

                src = src_id;
                src_line = (src_line as i64 + nums[2]) as u32;
                src_col = (src_col as i64 + nums[3]) as u32;

                if nums.len() > 4 {
                    name_id = (name_id as i64 + nums[4]) as u32;
                    if name_id >= rsm.names.len() as u32 {
                        fail!(Error::BadNameReference(name_id));
                    }
                    name = name_id as u32;
                }
            }

            tokens.push(RawToken {
                dst_line: dst_line as u32,
                dst_col: dst_col,
                src_line: src_line,
                src_col: src_col,
                src_id: src,
                name_id: name,
            });
            line_index.push((dst_col, (tokens.len() - 1) as u32));
        }

        line_index.sort();
        for (dst_col, token_id) in line_index {
            index.push((dst_line as u32, dst_col, token_id));
        }
    }

    let mut sources = rsm.sources;
    if let Some(source_root) = rsm.source_root {
        if !source_root.is_empty() {
            let source_root = source_root.trim_right_matches('/');
            sources = sources.into_iter().map(|x| {
                if x.len() > 0 && (x.as_bytes()[0] == b'/' ||
                                   x.as_bytes()[..5] == b"http:"[..] ||
                                   x.as_bytes()[..6] == b"https:"[..]) {
                    x
                } else {
                    format!("{}/{}", source_root, x)
                }
            }).collect();
        }
    }

    Ok(SourceMap::new(
        rsm.version, rsm.file, tokens, index, rsm.names, sources))
}

fn decode_index(rsm: RawSourceMap) -> Result<SourceMapIndex> {
    let mut sections = vec![];

    for mut raw_section in rsm.sections.unwrap_or(vec![]) {
        sections.push(SourceMapSection::new(
            (raw_section.offset.line, raw_section.offset.column),
            raw_section.url,
            match raw_section.map.take() {
                Some(map) => Some(try!(decode_regular(*map))),
                None => None,
            }
        ));
    }

    Ok(SourceMapIndex::new(
        rsm.version, rsm.file, sections))
}

/// Decodes a sourcemap or sourcemap index from a reader
///
/// This supports both sourcemaps and sourcemap indexes unless the
/// specialized methods on the individual types.
pub fn decode<R: Read>(rdr: R) -> Result<DecodedMap> {
    let mut rdr = StripHeaderReader::new(rdr);
    let rsm : RawSourceMap = try!(serde_json::from_reader(&mut rdr));

    Ok(if rsm.sections.is_some() {
        DecodedMap::Index(try!(decode_index(rsm)))
    } else {
        DecodedMap::Regular(try!(decode_regular(rsm)))
    })
}
<|endoftext|>


<commit_before>//! Utilities for logging messages from the library.

use once_cell::sync::Lazy;

#[macro_export]
macro_rules! rsvg_log {
    (
        $($arg:tt)+
    ) => {
        if $crate::log::log_enabled() {
            println!("{}", format_args!($($arg)+));
        }
    };
}

#[macro_export]
macro_rules! rsvg_log_session {
    (
        $session:expr,
        $($arg:tt)+
    ) => {
        if $session.log_enabled() {
            println!("{}", format_args!($($arg)+));
        }
    };
}

pub fn log_enabled() -> bool {
    static ENABLED: Lazy<bool> = Lazy::new(|| ::std::env::var_os("RSVG_LOG").is_some());

    *ENABLED
}

/// Captures the basic state of a [`cairo::Context`] for logging purposes.
///
/// A librsvg "transaction" like rendering a
/// [`crate::api::SvgHandle`], which takes a Cairo context, depends on the state of the
/// context as it was passed in by the caller.  For example, librsvg may decide to
/// operate differently depending on the context's target surface type, or its current
/// transformation matrix.  This struct captures that sort of information.
#[derive(Copy, Clone, Debug, PartialEq)]
struct CairoContextState {
    surface_type: cairo::SurfaceType,
    matrix: cairo::Matrix,
}

impl CairoContextState {
    fn new(cr: &cairo::Context) -> Self {
        let surface_type = cr.target().type_();
        let matrix = cr.matrix();

        Self {
            surface_type,
            matrix,
        }
    }
}

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

    #[test]
    fn captures_cr_state() {
        let surface = cairo::ImageSurface::create(cairo::Format::ARgb32, 10, 10).unwrap();
        let cr = cairo::Context::new(&surface).unwrap();
        let state = CairoContextState::new(&cr);

        assert_eq!(
            CairoContextState {
                surface_type: cairo::SurfaceType::Image,
                matrix: cairo::Matrix::identity(),
            },
            state,
        );

        let surface = cairo::RecordingSurface::create(cairo::Content::ColorAlpha, None).unwrap();
        let cr = cairo::Context::new(&surface).unwrap();
        cr.scale(2.0, 3.0);
        let state = CairoContextState::new(&cr);

        let mut matrix = cairo::Matrix::identity();
        matrix.scale(2.0, 3.0);

        assert_eq!(
            CairoContextState {
                surface_type: cairo::SurfaceType::Recording,
                matrix,
            },
            state,
        );
    }
}
<commit_msg>CairoContextState: suppress a warning until we use this for real outside the tests<commit_after>//! Utilities for logging messages from the library.

use once_cell::sync::Lazy;

#[macro_export]
macro_rules! rsvg_log {
    (
        $($arg:tt)+
    ) => {
        if $crate::log::log_enabled() {
            println!("{}", format_args!($($arg)+));
        }
    };
}

#[macro_export]
macro_rules! rsvg_log_session {
    (
        $session:expr,
        $($arg:tt)+
    ) => {
        if $session.log_enabled() {
            println!("{}", format_args!($($arg)+));
        }
    };
}

pub fn log_enabled() -> bool {
    static ENABLED: Lazy<bool> = Lazy::new(|| ::std::env::var_os("RSVG_LOG").is_some());

    *ENABLED
}

/// Captures the basic state of a [`cairo::Context`] for logging purposes.
///
/// A librsvg "transaction" like rendering a
/// [`crate::api::SvgHandle`], which takes a Cairo context, depends on the state of the
/// context as it was passed in by the caller.  For example, librsvg may decide to
/// operate differently depending on the context's target surface type, or its current
/// transformation matrix.  This struct captures that sort of information.
#[derive(Copy, Clone, Debug, PartialEq)]
struct CairoContextState {
    surface_type: cairo::SurfaceType,
    matrix: cairo::Matrix,
}

impl CairoContextState {
    #[cfg(test)]
    fn new(cr: &cairo::Context) -> Self {
        let surface_type = cr.target().type_();
        let matrix = cr.matrix();

        Self {
            surface_type,
            matrix,
        }
    }
}

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

    #[test]
    fn captures_cr_state() {
        let surface = cairo::ImageSurface::create(cairo::Format::ARgb32, 10, 10).unwrap();
        let cr = cairo::Context::new(&surface).unwrap();
        let state = CairoContextState::new(&cr);

        assert_eq!(
            CairoContextState {
                surface_type: cairo::SurfaceType::Image,
                matrix: cairo::Matrix::identity(),
            },
            state,
        );

        let surface = cairo::RecordingSurface::create(cairo::Content::ColorAlpha, None).unwrap();
        let cr = cairo::Context::new(&surface).unwrap();
        cr.scale(2.0, 3.0);
        let state = CairoContextState::new(&cr);

        let mut matrix = cairo::Matrix::identity();
        matrix.scale(2.0, 3.0);

        assert_eq!(
            CairoContextState {
                surface_type: cairo::SurfaceType::Recording,
                matrix,
            },
            state,
        );
    }
}
<|endoftext|>


<commit_before>use std::fs;
use std::fs::File;
use std::io::prelude::*;
use std::io::{Cursor, SeekFrom, Take};
use std::marker::PhantomData;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::vec::Vec;

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use fs2::FileExt;
use regex::Regex;

use data::{Entry, Hint};
use util::{xxhash32, XxHash32, get_file_handle};

const DATA_FILE_EXTENSION: &'static str = "cask.data";
const HINT_FILE_EXTENSION: &'static str = "cask.hint";
const LOCK_FILE_NAME: &'static str = "cask.lock";

const DEFAULT_SIZE_THRESHOLD: usize = 100 * 1024 * 1024;

pub struct Log {
    pub path: PathBuf,
    sync: bool,
    size_threshold: usize,
    lock_file: File,
    files: Vec<u32>,
    current_file_id: AtomicUsize,
    pub active_file_id: u32,
    active_log_writer: LogWriter,
}

impl Log {
    pub fn open(path: &str, sync: bool) -> Log {
        let path = PathBuf::from(path);

        if path.exists() {
            assert!(path.is_dir());
        } else {
            fs::create_dir(&path).unwrap();
        }

        let lock_file = File::create(path.join(LOCK_FILE_NAME)).unwrap();
        lock_file.try_lock_exclusive().unwrap();

        let files = find_data_files(&path);

        let active_file_id = if files.is_empty() {
            0
        } else {
            files[files.len() - 1] + 1
        };

        let active_log_writer = LogWriter::new(&path, active_file_id, sync);

        info!("Created new active data file {:?}",
              active_log_writer.data_file_path);

        Log {
            path: path,
            sync: sync,
            size_threshold: DEFAULT_SIZE_THRESHOLD,
            lock_file: lock_file,
            files: files,
            current_file_id: AtomicUsize::new(active_file_id as usize),
            active_file_id: active_file_id,
            active_log_writer: active_log_writer,
        }
    }

    pub fn files(&self) -> Vec<u32> {
        self.files.clone()
    }

    pub fn entries<'a>(&self, file_id: u32) -> Entries<'a> {
        let data_file_path = get_data_file_path(&self.path, file_id);
        info!("Loading data file: {:?}", data_file_path);
        let data_file = get_file_handle(&data_file_path, false);
        let data_file_size = data_file.metadata().unwrap().len();

        Entries {
            data_file: data_file.take(data_file_size),
            data_file_pos: 0,
            phantom: PhantomData,
        }
    }

    pub fn hints<'a>(&self, file_id: u32) -> Option<Hints<'a>> {
        let hint_file_path = get_hint_file_path(&self.path, file_id);
        if is_valid_hint_file(&hint_file_path) {
            info!("Loading hint file: {:?}", hint_file_path);
            let hint_file = get_file_handle(&hint_file_path, false);
            let hint_file_size = hint_file.metadata().unwrap().len();

            Some(Hints {
                hint_file: hint_file.take(hint_file_size - 4),
                phantom: PhantomData,
            })
        } else {
            None
        }
    }

    pub fn recreate_hints<'a>(&mut self, file_id: u32) -> RecreateHints<'a> {
        let hint_file_path = get_hint_file_path(&self.path, file_id);
        warn!("Re-creating hint file: {:?}", hint_file_path);

        let hint_writer = HintWriter::new(&self.path, file_id);
        let entries = self.entries(file_id);

        RecreateHints {
            hint_writer: hint_writer,
            entries: entries,
        }
    }

    pub fn read_entry<'a>(&self, file_id: u32, entry_pos: u64) -> Entry<'a> {
        let mut data_file = get_file_handle(&get_data_file_path(&self.path, file_id), false);
        data_file.seek(SeekFrom::Start(entry_pos)).unwrap();
        Entry::from_read(&mut data_file)
    }

    pub fn append_entry<'a>(&mut self, entry: &Entry<'a>) -> (u32, u64) {
        if self.active_log_writer.data_file_pos + entry.size() > self.size_threshold as u64 {
            info!("Active data file {:?} reached file limit",
                  self.active_log_writer.data_file_path);

            self.new_active_writer();
        }

        let entry_pos = self.active_log_writer.write(entry);

        (self.active_file_id, entry_pos)
    }

    pub fn new_file_id(&self) -> u32 {
        self.current_file_id.fetch_add(1, Ordering::SeqCst) as u32 + 1
    }

    pub fn swap_file(&mut self, file_id: u32, new_file_id: u32) {
        let idx = self.files.binary_search(&file_id).unwrap();
        self.files.remove(idx);

        self.add_file(new_file_id);

        let data_file_path = get_data_file_path(&self.path, file_id);
        let hint_file_path = get_hint_file_path(&self.path, file_id);

        fs::remove_file(data_file_path).unwrap();
        fs::remove_file(hint_file_path).unwrap();
    }

    pub fn add_file(&mut self, file_id: u32) {
        self.files.push(file_id);
        self.files.sort();
    }

    fn new_active_writer(&mut self) {
        let active_file_id = self.active_file_id;
        self.add_file(active_file_id);

        info!("Closed active data file {:?}",
              self.active_log_writer.data_file_path);

        self.active_file_id = self.new_file_id();
        self.active_log_writer = LogWriter::new(&self.path, self.active_file_id, self.sync);

        info!("Created new active data file {:?}",
              self.active_log_writer.data_file_path);
    }
}

impl Drop for Log {
    fn drop(&mut self) {
        self.lock_file.unlock().unwrap();
    }
}

pub struct LogWriter {
    sync: bool,
    data_file_path: PathBuf,
    data_file: File,
    data_file_pos: u64,
    hint_writer: HintWriter,
}

impl LogWriter {
    pub fn new(path: &Path, file_id: u32, sync: bool) -> LogWriter {
        let data_file_path = get_data_file_path(path, file_id);
        let data_file = get_file_handle(&data_file_path, true);

        let hint_writer = HintWriter::new(path, file_id);

        LogWriter {
            sync: sync,
            data_file_path: data_file_path,
            data_file: data_file,
            data_file_pos: 0,
            hint_writer: hint_writer,
        }
    }

    pub fn write<'a>(&mut self, entry: &Entry<'a>) -> u64 {
        let entry_pos = self.data_file_pos;

        let hint = Hint::new(entry, entry_pos);
        entry.write_bytes(&mut self.data_file);

        self.hint_writer.write(&hint);

        if self.sync {
            self.data_file.sync_data().unwrap();
        }

        self.data_file_pos += entry.size();

        entry_pos
    }
}

impl Drop for LogWriter {
    fn drop(&mut self) {
        if self.sync {
            self.data_file.sync_data().unwrap();
        }
    }
}

struct HintWriter {
    hint_file: File,
    hint_file_hasher: XxHash32,
}

impl HintWriter {
    pub fn new(path: &Path, file_id: u32) -> HintWriter {
        let hint_file = get_file_handle(&get_hint_file_path(path, file_id), true);

        HintWriter {
            hint_file: hint_file,
            hint_file_hasher: XxHash32::new(),
        }
    }

    pub fn write<'a>(&mut self, hint: &Hint<'a>) {
        hint.write_bytes(&mut self.hint_file);
        hint.write_bytes(&mut self.hint_file_hasher);
    }
}

impl Drop for HintWriter {
    fn drop(&mut self) {
        self.hint_file
            .write_u32::<LittleEndian>(self.hint_file_hasher.get())
            .unwrap();
    }
}

pub struct Entries<'a> {
    data_file: Take<File>,
    data_file_pos: u64,
    phantom: PhantomData<&'a ()>,
}

impl<'a> Iterator for Entries<'a> {
    type Item = (u64, Entry<'a>);

    fn next(&mut self) -> Option<(u64, Entry<'a>)> {
        if self.data_file.limit() == 0 {
            None
        } else {
            let entry = Entry::from_read(&mut self.data_file);
            let entry_pos = self.data_file_pos;

            self.data_file_pos += entry.size();

            Some((entry_pos, entry))
        }
    }
}

pub struct Hints<'a> {
    hint_file: Take<File>,
    phantom: PhantomData<&'a ()>,
}

impl<'a> Iterator for Hints<'a> {
    type Item = Hint<'a>;

    fn next(&mut self) -> Option<Hint<'a>> {
        if self.hint_file.limit() == 0 {
            None
        } else {
            Some(Hint::from_read(&mut self.hint_file))
        }
    }
}

pub struct RecreateHints<'a> {
    hint_writer: HintWriter,
    entries: Entries<'a>,
}

impl<'a> Iterator for RecreateHints<'a> {
    type Item = Hint<'a>;

    fn next(&mut self) -> Option<Hint<'a>> {
        self.entries.next().map(|e| {
            let (entry_pos, entry) = e;
            let hint = Hint::from(entry, entry_pos);
            self.hint_writer.write(&hint);
            hint
        })
    }
}

impl<'a> Drop for RecreateHints<'a> {
    fn drop(&mut self) {
        while self.next().is_some() {}
    }
}

fn get_data_file_path(path: &Path, file_id: u32) -> PathBuf {
    let file_id = format!("{:010}", file_id);
    path.join(file_id).with_extension(DATA_FILE_EXTENSION)
}

fn get_hint_file_path(path: &Path, file_id: u32) -> PathBuf {
    let file_id = format!("{:010}", file_id);
    path.join(file_id).with_extension(HINT_FILE_EXTENSION)
}

fn find_data_files(path: &Path) -> Vec<u32> {
    let files = fs::read_dir(path).unwrap();

    lazy_static! {
        static ref RE: Regex =
            Regex::new(&format!("(\\d+).{}$", DATA_FILE_EXTENSION)).unwrap();
    }

    let mut files: Vec<u32> = files.flat_map(|f| {
            let file = f.unwrap();
            let file_metadata = file.metadata().unwrap();

            if file_metadata.is_file() {
                let file_name = file.file_name();
                let captures = RE.captures(file_name.to_str().unwrap());
                captures.and_then(|c| c.at(1).and_then(|n| n.parse::<u32>().ok()))
            } else {
                None
            }
        })
        .collect();

    files.sort();

    files
}

fn is_valid_hint_file(path: &Path) -> bool {
    path.is_file() &&
    {
        let mut hint_file = get_file_handle(path, false);

        // FIXME: avoid reading the whole hint file into memory;
        let mut buf = Vec::new();
        hint_file.read_to_end(&mut buf).unwrap();

        buf.len() >= 4 &&
        {
            let hash = xxhash32(&buf[..buf.len() - 4]);

            let mut cursor = Cursor::new(&buf[buf.len() - 4..]);
            let checksum = cursor.read_u32::<LittleEndian>().unwrap();

            let valid = hash == checksum;

            if !valid {
                warn!("Found corrupt hint file: {:?}", &path);
            }

            valid
        }
    }
}
<commit_msg>increase default data file size<commit_after>use std::fs;
use std::fs::File;
use std::io::prelude::*;
use std::io::{Cursor, SeekFrom, Take};
use std::marker::PhantomData;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::vec::Vec;

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use fs2::FileExt;
use regex::Regex;

use data::{Entry, Hint};
use util::{xxhash32, XxHash32, get_file_handle};

const DATA_FILE_EXTENSION: &'static str = "cask.data";
const HINT_FILE_EXTENSION: &'static str = "cask.hint";
const LOCK_FILE_NAME: &'static str = "cask.lock";

const DEFAULT_SIZE_THRESHOLD: usize = 2000 * 1024 * 1024;

pub struct Log {
    pub path: PathBuf,
    sync: bool,
    size_threshold: usize,
    lock_file: File,
    files: Vec<u32>,
    current_file_id: AtomicUsize,
    pub active_file_id: u32,
    active_log_writer: LogWriter,
}

impl Log {
    pub fn open(path: &str, sync: bool) -> Log {
        let path = PathBuf::from(path);

        if path.exists() {
            assert!(path.is_dir());
        } else {
            fs::create_dir(&path).unwrap();
        }

        let lock_file = File::create(path.join(LOCK_FILE_NAME)).unwrap();
        lock_file.try_lock_exclusive().unwrap();

        let files = find_data_files(&path);

        let active_file_id = if files.is_empty() {
            0
        } else {
            files[files.len() - 1] + 1
        };

        let active_log_writer = LogWriter::new(&path, active_file_id, sync);

        info!("Created new active data file {:?}",
              active_log_writer.data_file_path);

        Log {
            path: path,
            sync: sync,
            size_threshold: DEFAULT_SIZE_THRESHOLD,
            lock_file: lock_file,
            files: files,
            current_file_id: AtomicUsize::new(active_file_id as usize),
            active_file_id: active_file_id,
            active_log_writer: active_log_writer,
        }
    }

    pub fn files(&self) -> Vec<u32> {
        self.files.clone()
    }

    pub fn entries<'a>(&self, file_id: u32) -> Entries<'a> {
        let data_file_path = get_data_file_path(&self.path, file_id);
        info!("Loading data file: {:?}", data_file_path);
        let data_file = get_file_handle(&data_file_path, false);
        let data_file_size = data_file.metadata().unwrap().len();

        Entries {
            data_file: data_file.take(data_file_size),
            data_file_pos: 0,
            phantom: PhantomData,
        }
    }

    pub fn hints<'a>(&self, file_id: u32) -> Option<Hints<'a>> {
        let hint_file_path = get_hint_file_path(&self.path, file_id);
        if is_valid_hint_file(&hint_file_path) {
            info!("Loading hint file: {:?}", hint_file_path);
            let hint_file = get_file_handle(&hint_file_path, false);
            let hint_file_size = hint_file.metadata().unwrap().len();

            Some(Hints {
                hint_file: hint_file.take(hint_file_size - 4),
                phantom: PhantomData,
            })
        } else {
            None
        }
    }

    pub fn recreate_hints<'a>(&mut self, file_id: u32) -> RecreateHints<'a> {
        let hint_file_path = get_hint_file_path(&self.path, file_id);
        warn!("Re-creating hint file: {:?}", hint_file_path);

        let hint_writer = HintWriter::new(&self.path, file_id);
        let entries = self.entries(file_id);

        RecreateHints {
            hint_writer: hint_writer,
            entries: entries,
        }
    }

    pub fn read_entry<'a>(&self, file_id: u32, entry_pos: u64) -> Entry<'a> {
        let mut data_file = get_file_handle(&get_data_file_path(&self.path, file_id), false);
        data_file.seek(SeekFrom::Start(entry_pos)).unwrap();
        Entry::from_read(&mut data_file)
    }

    pub fn append_entry<'a>(&mut self, entry: &Entry<'a>) -> (u32, u64) {
        if self.active_log_writer.data_file_pos + entry.size() > self.size_threshold as u64 {
            info!("Active data file {:?} reached file limit",
                  self.active_log_writer.data_file_path);

            self.new_active_writer();
        }

        let entry_pos = self.active_log_writer.write(entry);

        (self.active_file_id, entry_pos)
    }

    pub fn new_file_id(&self) -> u32 {
        self.current_file_id.fetch_add(1, Ordering::SeqCst) as u32 + 1
    }

    pub fn swap_file(&mut self, file_id: u32, new_file_id: u32) {
        let idx = self.files.binary_search(&file_id).unwrap();
        self.files.remove(idx);

        self.add_file(new_file_id);

        let data_file_path = get_data_file_path(&self.path, file_id);
        let hint_file_path = get_hint_file_path(&self.path, file_id);

        fs::remove_file(data_file_path).unwrap();
        fs::remove_file(hint_file_path).unwrap();
    }

    pub fn add_file(&mut self, file_id: u32) {
        self.files.push(file_id);
        self.files.sort();
    }

    fn new_active_writer(&mut self) {
        let active_file_id = self.active_file_id;
        self.add_file(active_file_id);

        info!("Closed active data file {:?}",
              self.active_log_writer.data_file_path);

        self.active_file_id = self.new_file_id();
        self.active_log_writer = LogWriter::new(&self.path, self.active_file_id, self.sync);

        info!("Created new active data file {:?}",
              self.active_log_writer.data_file_path);
    }
}

impl Drop for Log {
    fn drop(&mut self) {
        self.lock_file.unlock().unwrap();
    }
}

pub struct LogWriter {
    sync: bool,
    data_file_path: PathBuf,
    data_file: File,
    data_file_pos: u64,
    hint_writer: HintWriter,
}

impl LogWriter {
    pub fn new(path: &Path, file_id: u32, sync: bool) -> LogWriter {
        let data_file_path = get_data_file_path(path, file_id);
        let data_file = get_file_handle(&data_file_path, true);

        let hint_writer = HintWriter::new(path, file_id);

        LogWriter {
            sync: sync,
            data_file_path: data_file_path,
            data_file: data_file,
            data_file_pos: 0,
            hint_writer: hint_writer,
        }
    }

    pub fn write<'a>(&mut self, entry: &Entry<'a>) -> u64 {
        let entry_pos = self.data_file_pos;

        let hint = Hint::new(entry, entry_pos);
        entry.write_bytes(&mut self.data_file);

        self.hint_writer.write(&hint);

        if self.sync {
            self.data_file.sync_data().unwrap();
        }

        self.data_file_pos += entry.size();

        entry_pos
    }
}

impl Drop for LogWriter {
    fn drop(&mut self) {
        if self.sync {
            self.data_file.sync_data().unwrap();
        }
    }
}

struct HintWriter {
    hint_file: File,
    hint_file_hasher: XxHash32,
}

impl HintWriter {
    pub fn new(path: &Path, file_id: u32) -> HintWriter {
        let hint_file = get_file_handle(&get_hint_file_path(path, file_id), true);

        HintWriter {
            hint_file: hint_file,
            hint_file_hasher: XxHash32::new(),
        }
    }

    pub fn write<'a>(&mut self, hint: &Hint<'a>) {
        hint.write_bytes(&mut self.hint_file);
        hint.write_bytes(&mut self.hint_file_hasher);
    }
}

impl Drop for HintWriter {
    fn drop(&mut self) {
        self.hint_file
            .write_u32::<LittleEndian>(self.hint_file_hasher.get())
            .unwrap();
    }
}

pub struct Entries<'a> {
    data_file: Take<File>,
    data_file_pos: u64,
    phantom: PhantomData<&'a ()>,
}

impl<'a> Iterator for Entries<'a> {
    type Item = (u64, Entry<'a>);

    fn next(&mut self) -> Option<(u64, Entry<'a>)> {
        if self.data_file.limit() == 0 {
            None
        } else {
            let entry = Entry::from_read(&mut self.data_file);
            let entry_pos = self.data_file_pos;

            self.data_file_pos += entry.size();

            Some((entry_pos, entry))
        }
    }
}

pub struct Hints<'a> {
    hint_file: Take<File>,
    phantom: PhantomData<&'a ()>,
}

impl<'a> Iterator for Hints<'a> {
    type Item = Hint<'a>;

    fn next(&mut self) -> Option<Hint<'a>> {
        if self.hint_file.limit() == 0 {
            None
        } else {
            Some(Hint::from_read(&mut self.hint_file))
        }
    }
}

pub struct RecreateHints<'a> {
    hint_writer: HintWriter,
    entries: Entries<'a>,
}

impl<'a> Iterator for RecreateHints<'a> {
    type Item = Hint<'a>;

    fn next(&mut self) -> Option<Hint<'a>> {
        self.entries.next().map(|e| {
            let (entry_pos, entry) = e;
            let hint = Hint::from(entry, entry_pos);
            self.hint_writer.write(&hint);
            hint
        })
    }
}

impl<'a> Drop for RecreateHints<'a> {
    fn drop(&mut self) {
        while self.next().is_some() {}
    }
}

fn get_data_file_path(path: &Path, file_id: u32) -> PathBuf {
    let file_id = format!("{:010}", file_id);
    path.join(file_id).with_extension(DATA_FILE_EXTENSION)
}

fn get_hint_file_path(path: &Path, file_id: u32) -> PathBuf {
    let file_id = format!("{:010}", file_id);
    path.join(file_id).with_extension(HINT_FILE_EXTENSION)
}

fn find_data_files(path: &Path) -> Vec<u32> {
    let files = fs::read_dir(path).unwrap();

    lazy_static! {
        static ref RE: Regex =
            Regex::new(&format!("(\\d+).{}$", DATA_FILE_EXTENSION)).unwrap();
    }

    let mut files: Vec<u32> = files.flat_map(|f| {
            let file = f.unwrap();
            let file_metadata = file.metadata().unwrap();

            if file_metadata.is_file() {
                let file_name = file.file_name();
                let captures = RE.captures(file_name.to_str().unwrap());
                captures.and_then(|c| c.at(1).and_then(|n| n.parse::<u32>().ok()))
            } else {
                None
            }
        })
        .collect();

    files.sort();

    files
}

fn is_valid_hint_file(path: &Path) -> bool {
    path.is_file() &&
    {
        let mut hint_file = get_file_handle(path, false);

        // FIXME: avoid reading the whole hint file into memory;
        let mut buf = Vec::new();
        hint_file.read_to_end(&mut buf).unwrap();

        buf.len() >= 4 &&
        {
            let hash = xxhash32(&buf[..buf.len() - 4]);

            let mut cursor = Cursor::new(&buf[buf.len() - 4..]);
            let checksum = cursor.read_u32::<LittleEndian>().unwrap();

            let valid = hash == checksum;

            if !valid {
                warn!("Found corrupt hint file: {:?}", &path);
            }

            valid
        }
    }
}
<|endoftext|>


<commit_before>use super::*;
use crate::token::{Brace, Bracket, Paren};
use proc_macro2::TokenStream;
#[cfg(feature = "parsing")]
use proc_macro2::{Delimiter, Span, TokenTree};

#[cfg(feature = "parsing")]
use crate::parse::{Parse, ParseStream, Parser, Result};
#[cfg(feature = "extra-traits")]
use crate::tt::TokenStreamHelper;
#[cfg(feature = "extra-traits")]
use std::hash::{Hash, Hasher};

ast_struct! {
    /// A macro invocation: `println!("{}", mac)`.
    ///
    /// *This type is available if Syn is built with the `"derive"` or `"full"`
    /// feature.*
    pub struct Macro #manual_extra_traits {
        pub path: Path,
        pub bang_token: Token![!],
        pub delimiter: MacroDelimiter,
        pub tokens: TokenStream,
    }
}

ast_enum! {
    /// A grouping token that surrounds a macro body: `m!(...)` or `m!{...}` or `m![...]`.
    ///
    /// *This type is available if Syn is built with the `"derive"` or `"full"`
    /// feature.*
    pub enum MacroDelimiter {
        Paren(Paren),
        Brace(Brace),
        Bracket(Bracket),
    }
}

#[cfg(feature = "extra-traits")]
impl Eq for Macro {}

#[cfg(feature = "extra-traits")]
impl PartialEq for Macro {
    fn eq(&self, other: &Self) -> bool {
        self.path == other.path
            && self.bang_token == other.bang_token
            && self.delimiter == other.delimiter
            && TokenStreamHelper(&self.tokens) == TokenStreamHelper(&other.tokens)
    }
}

#[cfg(feature = "extra-traits")]
impl Hash for Macro {
    fn hash<H>(&self, state: &mut H)
    where
        H: Hasher,
    {
        self.path.hash(state);
        self.bang_token.hash(state);
        self.delimiter.hash(state);
        TokenStreamHelper(&self.tokens).hash(state);
    }
}

#[cfg(feature = "parsing")]
fn delimiter_span(delimiter: &MacroDelimiter) -> Span {
    match delimiter {
        MacroDelimiter::Paren(token) => token.span,
        MacroDelimiter::Brace(token) => token.span,
        MacroDelimiter::Bracket(token) => token.span,
    }
}

impl Macro {
    /// Parse the tokens within the macro invocation's delimiters into a syntax
    /// tree.
    ///
    /// This is equivalent to `syn::parse2::<T>(mac.tokens)` except that it
    /// produces a more useful span when `tokens` is empty.
    ///
    /// # Example
    ///
    /// ```edition2018
    /// use syn::{parse_quote, Expr, ExprLit, Ident, Lit, LitStr, Macro, Token};
    /// use syn::ext::IdentExt;
    /// use syn::parse::{Error, Parse, ParseStream, Result};
    /// use syn::punctuated::Punctuated;
    ///
    /// // The arguments expected by libcore's format_args macro, and as a
    /// // result most other formatting and printing macros like println.
    /// //
    /// //     println!("{} is {number:.prec$}", "x", prec=5, number=0.01)
    /// struct FormatArgs {
    ///     format_string: Expr,
    ///     positional_args: Vec<Expr>,
    ///     named_args: Vec<(Ident, Expr)>,
    /// }
    ///
    /// impl Parse for FormatArgs {
    ///     fn parse(input: ParseStream) -> Result<Self> {
    ///         let format_string: Expr;
    ///         let mut positional_args = Vec::new();
    ///         let mut named_args = Vec::new();
    ///
    ///         format_string = input.parse()?;
    ///         while !input.is_empty() {
    ///             input.parse::<Token![,]>()?;
    ///             if input.is_empty() {
    ///                 break;
    ///             }
    ///             if input.peek(Ident::peek_any) && input.peek2(Token![=]) {
    ///                 while !input.is_empty() {
    ///                     let name: Ident = input.call(Ident::parse_any)?;
    ///                     input.parse::<Token![=]>()?;
    ///                     let value: Expr = input.parse()?;
    ///                     named_args.push((name, value));
    ///                     if input.is_empty() {
    ///                         break;
    ///                     }
    ///                     input.parse::<Token![,]>()?;
    ///                 }
    ///                 break;
    ///             }
    ///             positional_args.push(input.parse()?);
    ///         }
    ///
    ///         Ok(FormatArgs {
    ///             format_string,
    ///             positional_args,
    ///             named_args,
    ///         })
    ///     }
    /// }
    ///
    /// // Extract the first argument, the format string literal, from an
    /// // invocation of a formatting or printing macro.
    /// fn get_format_string(m: &Macro) -> Result<LitStr> {
    ///     let args: FormatArgs = m.parse_body()?;
    ///     match args.format_string {
    ///         Expr::Lit(ExprLit { lit: Lit::Str(lit), .. }) => Ok(lit),
    ///         other => {
    ///             // First argument was not a string literal expression.
    ///             // Maybe something like: println!(concat!(...), ...)
    ///             Err(Error::new_spanned(other, "format string must be a string literal"))
    ///         }
    ///     }
    /// }
    ///
    /// fn main() {
    ///     let invocation = parse_quote! {
    ///         println!("{:?}", Instant::now())
    ///     };
    ///     let lit = get_format_string(&invocation).unwrap();
    ///     assert_eq!(lit.value(), "{:?}");
    /// }
    /// ```
    #[cfg(feature = "parsing")]
    pub fn parse_body<T: Parse>(&self) -> Result<T> {
        self.parse_body_with(T::parse)
    }

    /// Parse the tokens within the macro invocation's delimiters using the
    /// given parser.
    #[cfg(feature = "parsing")]
    pub fn parse_body_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
        // TODO: see if we can get a group.span_close() span in here as the
        // scope, rather than the span of the whole group.
        let scope = delimiter_span(&self.delimiter);
        crate::parse::parse_scoped(parser, scope, self.tokens.clone())
    }
}

#[cfg(feature = "parsing")]
pub fn parse_delimiter(input: ParseStream) -> Result<(MacroDelimiter, TokenStream)> {
    input.step(|cursor| {
        if let Some((TokenTree::Group(g), rest)) = cursor.token_tree() {
            let span = g.span();
            let delimiter = match g.delimiter() {
                Delimiter::Parenthesis => MacroDelimiter::Paren(Paren(span)),
                Delimiter::Brace => MacroDelimiter::Brace(Brace(span)),
                Delimiter::Bracket => MacroDelimiter::Bracket(Bracket(span)),
                Delimiter::None => {
                    return Err(cursor.error("expected delimiter"));
                }
            };
            Ok(((delimiter, g.stream().clone()), rest))
        } else {
            Err(cursor.error("expected delimiter"))
        }
    })
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;

    use crate::parse::{Parse, ParseStream, Result};

    impl Parse for Macro {
        fn parse(input: ParseStream) -> Result<Self> {
            let tokens;
            Ok(Macro {
                path: input.call(Path::parse_mod_style)?,
                bang_token: input.parse()?,
                delimiter: {
                    let (delimiter, content) = parse_delimiter(input)?;
                    tokens = content;
                    delimiter
                },
                tokens,
            })
        }
    }
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use proc_macro2::TokenStream;
    use quote::ToTokens;

    impl ToTokens for Macro {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.path.to_tokens(tokens);
            self.bang_token.to_tokens(tokens);
            match &self.delimiter {
                MacroDelimiter::Paren(paren) => {
                    paren.surround(tokens, |tokens| self.tokens.to_tokens(tokens));
                }
                MacroDelimiter::Brace(brace) => {
                    brace.surround(tokens, |tokens| self.tokens.to_tokens(tokens));
                }
                MacroDelimiter::Bracket(bracket) => {
                    bracket.surround(tokens, |tokens| self.tokens.to_tokens(tokens));
                }
            }
        }
    }
}
<commit_msg>Remove unneeded clone in parse_delimiter<commit_after>use super::*;
use crate::token::{Brace, Bracket, Paren};
use proc_macro2::TokenStream;
#[cfg(feature = "parsing")]
use proc_macro2::{Delimiter, Span, TokenTree};

#[cfg(feature = "parsing")]
use crate::parse::{Parse, ParseStream, Parser, Result};
#[cfg(feature = "extra-traits")]
use crate::tt::TokenStreamHelper;
#[cfg(feature = "extra-traits")]
use std::hash::{Hash, Hasher};

ast_struct! {
    /// A macro invocation: `println!("{}", mac)`.
    ///
    /// *This type is available if Syn is built with the `"derive"` or `"full"`
    /// feature.*
    pub struct Macro #manual_extra_traits {
        pub path: Path,
        pub bang_token: Token![!],
        pub delimiter: MacroDelimiter,
        pub tokens: TokenStream,
    }
}

ast_enum! {
    /// A grouping token that surrounds a macro body: `m!(...)` or `m!{...}` or `m![...]`.
    ///
    /// *This type is available if Syn is built with the `"derive"` or `"full"`
    /// feature.*
    pub enum MacroDelimiter {
        Paren(Paren),
        Brace(Brace),
        Bracket(Bracket),
    }
}

#[cfg(feature = "extra-traits")]
impl Eq for Macro {}

#[cfg(feature = "extra-traits")]
impl PartialEq for Macro {
    fn eq(&self, other: &Self) -> bool {
        self.path == other.path
            && self.bang_token == other.bang_token
            && self.delimiter == other.delimiter
            && TokenStreamHelper(&self.tokens) == TokenStreamHelper(&other.tokens)
    }
}

#[cfg(feature = "extra-traits")]
impl Hash for Macro {
    fn hash<H>(&self, state: &mut H)
    where
        H: Hasher,
    {
        self.path.hash(state);
        self.bang_token.hash(state);
        self.delimiter.hash(state);
        TokenStreamHelper(&self.tokens).hash(state);
    }
}

#[cfg(feature = "parsing")]
fn delimiter_span(delimiter: &MacroDelimiter) -> Span {
    match delimiter {
        MacroDelimiter::Paren(token) => token.span,
        MacroDelimiter::Brace(token) => token.span,
        MacroDelimiter::Bracket(token) => token.span,
    }
}

impl Macro {
    /// Parse the tokens within the macro invocation's delimiters into a syntax
    /// tree.
    ///
    /// This is equivalent to `syn::parse2::<T>(mac.tokens)` except that it
    /// produces a more useful span when `tokens` is empty.
    ///
    /// # Example
    ///
    /// ```edition2018
    /// use syn::{parse_quote, Expr, ExprLit, Ident, Lit, LitStr, Macro, Token};
    /// use syn::ext::IdentExt;
    /// use syn::parse::{Error, Parse, ParseStream, Result};
    /// use syn::punctuated::Punctuated;
    ///
    /// // The arguments expected by libcore's format_args macro, and as a
    /// // result most other formatting and printing macros like println.
    /// //
    /// //     println!("{} is {number:.prec$}", "x", prec=5, number=0.01)
    /// struct FormatArgs {
    ///     format_string: Expr,
    ///     positional_args: Vec<Expr>,
    ///     named_args: Vec<(Ident, Expr)>,
    /// }
    ///
    /// impl Parse for FormatArgs {
    ///     fn parse(input: ParseStream) -> Result<Self> {
    ///         let format_string: Expr;
    ///         let mut positional_args = Vec::new();
    ///         let mut named_args = Vec::new();
    ///
    ///         format_string = input.parse()?;
    ///         while !input.is_empty() {
    ///             input.parse::<Token![,]>()?;
    ///             if input.is_empty() {
    ///                 break;
    ///             }
    ///             if input.peek(Ident::peek_any) && input.peek2(Token![=]) {
    ///                 while !input.is_empty() {
    ///                     let name: Ident = input.call(Ident::parse_any)?;
    ///                     input.parse::<Token![=]>()?;
    ///                     let value: Expr = input.parse()?;
    ///                     named_args.push((name, value));
    ///                     if input.is_empty() {
    ///                         break;
    ///                     }
    ///                     input.parse::<Token![,]>()?;
    ///                 }
    ///                 break;
    ///             }
    ///             positional_args.push(input.parse()?);
    ///         }
    ///
    ///         Ok(FormatArgs {
    ///             format_string,
    ///             positional_args,
    ///             named_args,
    ///         })
    ///     }
    /// }
    ///
    /// // Extract the first argument, the format string literal, from an
    /// // invocation of a formatting or printing macro.
    /// fn get_format_string(m: &Macro) -> Result<LitStr> {
    ///     let args: FormatArgs = m.parse_body()?;
    ///     match args.format_string {
    ///         Expr::Lit(ExprLit { lit: Lit::Str(lit), .. }) => Ok(lit),
    ///         other => {
    ///             // First argument was not a string literal expression.
    ///             // Maybe something like: println!(concat!(...), ...)
    ///             Err(Error::new_spanned(other, "format string must be a string literal"))
    ///         }
    ///     }
    /// }
    ///
    /// fn main() {
    ///     let invocation = parse_quote! {
    ///         println!("{:?}", Instant::now())
    ///     };
    ///     let lit = get_format_string(&invocation).unwrap();
    ///     assert_eq!(lit.value(), "{:?}");
    /// }
    /// ```
    #[cfg(feature = "parsing")]
    pub fn parse_body<T: Parse>(&self) -> Result<T> {
        self.parse_body_with(T::parse)
    }

    /// Parse the tokens within the macro invocation's delimiters using the
    /// given parser.
    #[cfg(feature = "parsing")]
    pub fn parse_body_with<F: Parser>(&self, parser: F) -> Result<F::Output> {
        // TODO: see if we can get a group.span_close() span in here as the
        // scope, rather than the span of the whole group.
        let scope = delimiter_span(&self.delimiter);
        crate::parse::parse_scoped(parser, scope, self.tokens.clone())
    }
}

#[cfg(feature = "parsing")]
pub fn parse_delimiter(input: ParseStream) -> Result<(MacroDelimiter, TokenStream)> {
    input.step(|cursor| {
        if let Some((TokenTree::Group(g), rest)) = cursor.token_tree() {
            let span = g.span();
            let delimiter = match g.delimiter() {
                Delimiter::Parenthesis => MacroDelimiter::Paren(Paren(span)),
                Delimiter::Brace => MacroDelimiter::Brace(Brace(span)),
                Delimiter::Bracket => MacroDelimiter::Bracket(Bracket(span)),
                Delimiter::None => {
                    return Err(cursor.error("expected delimiter"));
                }
            };
            Ok(((delimiter, g.stream()), rest))
        } else {
            Err(cursor.error("expected delimiter"))
        }
    })
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;

    use crate::parse::{Parse, ParseStream, Result};

    impl Parse for Macro {
        fn parse(input: ParseStream) -> Result<Self> {
            let tokens;
            Ok(Macro {
                path: input.call(Path::parse_mod_style)?,
                bang_token: input.parse()?,
                delimiter: {
                    let (delimiter, content) = parse_delimiter(input)?;
                    tokens = content;
                    delimiter
                },
                tokens,
            })
        }
    }
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use proc_macro2::TokenStream;
    use quote::ToTokens;

    impl ToTokens for Macro {
        fn to_tokens(&self, tokens: &mut TokenStream) {
            self.path.to_tokens(tokens);
            self.bang_token.to_tokens(tokens);
            match &self.delimiter {
                MacroDelimiter::Paren(paren) => {
                    paren.surround(tokens, |tokens| self.tokens.to_tokens(tokens));
                }
                MacroDelimiter::Brace(brace) => {
                    brace.surround(tokens, |tokens| self.tokens.to_tokens(tokens));
                }
                MacroDelimiter::Bracket(bracket) => {
                    bracket.surround(tokens, |tokens| self.tokens.to_tokens(tokens));
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Domain name related scanning, used by both email and URL scanners.
//!
//! This is called domains for familiarity but it's about the authority part of URLs as defined in
//! https://datatracker.ietf.org/doc/html/rfc3986#section-3.2
//!
//! ```text
//! authority   = [ userinfo "@" ] host [ ":" port ]
//!
//!
//! userinfo    = *( unreserved / pct-encoded / sub-delims / ":" )
//!
//! host        = IP-literal / IPv4address / reg-name
//!
//! IP-literal = "[" ( IPv6address / IPvFuture  ) "]"
//!
//! IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
//!
//! reg-name    = *( unreserved / pct-encoded / sub-delims )
//!
//!
//! unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"
//!
//! sub-delims  = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
//! ```

use std::char;

pub(crate) fn find_authority_end(
    s: &str,
    mut userinfo_allowed: bool,
    require_host: bool,
    port_allowed: bool,
) -> (Option<usize>, Option<usize>) {
    let mut end = Some(0);

    let mut maybe_last_dot = None;
    let mut last_dot = None;
    let mut dot_allowed = false;
    let mut hyphen_allowed = false;
    let mut all_numeric = true;
    let mut maybe_host = true;
    let mut host_ended = false;

    for (i, c) in s.char_indices() {
        let can_be_last = match c {
            // ALPHA
            'a'..='z' | 'A'..='Z' | '\u{80}'..=char::MAX => {
                // Can start or end a domain label, but not numeric
                dot_allowed = true;
                hyphen_allowed = true;
                last_dot = maybe_last_dot;
                all_numeric = false;

                if host_ended {
                    maybe_host = false;
                }

                !require_host || !host_ended
            }
            // DIGIT
            '0'..='9' => {
                // Same as above, except numeric
                dot_allowed = true;
                hyphen_allowed = true;
                last_dot = maybe_last_dot;

                if host_ended {
                    maybe_host = false;
                }

                !require_host || !host_ended
            }
            // unreserved
            '-' => {
                // Hyphen can't be at start of a label, e.g. `-b` in `a.-b.com`
                if !hyphen_allowed {
                    maybe_host = false;
                }
                // Hyphen can't be at end of a label, e.g. `b-` in `a.b-.com`
                dot_allowed = false;
                all_numeric = false;

                !require_host
            }
            '.' => {
                if !dot_allowed {
                    // Label can't be empty, e.g. `.example.com` or `a..com`
                    host_ended = true;
                }
                dot_allowed = false;
                hyphen_allowed = false;
                maybe_last_dot = Some(i);

                false
            }
            '_' | '~' => {
                // Hostnames can't contain these and we don't want to treat them as delimiters.
                maybe_host = false;

                false
            }
            // sub-delims
            '!' | '$' | '&' | '\'' | '(' | ')' | '*' | '+' | ',' | ';' | '=' => {
                // Can't be in hostnames, but we treat them as delimiters
                host_ended = true;

                if !userinfo_allowed && require_host {
                    // We don't have to look further
                    break;
                }

                false
            }
            ':' => {
                // Could be in userinfo, or we're getting a port now.
                if !userinfo_allowed && !port_allowed {
                    break;
                }

                // Don't advance the last dot when we get to port numbers
                maybe_last_dot = last_dot;

                false
            }
            '@' => {
                if !userinfo_allowed {
                    // We already had userinfo, can't have another `@` in a valid authority.
                    return (None, None);
                }

                // Sike! Everything before this has been userinfo, so let's reset our
                // opinions about all the host bits.
                userinfo_allowed = false;

                maybe_last_dot = None;
                last_dot = None;
                dot_allowed = false;
                hyphen_allowed = false;
                all_numeric = true;
                maybe_host = true;
                host_ended = false;

                false
            }
            '/' => {
                if !require_host {
                    // For schemes where we allow anything, we want to stop at delimiter characters
                    // except if we get a slash closing the URL, which happened here.
                    end = Some(i);
                }
                break;
            }
            _ => {
                // Anything else, this might be the end of the authority (can be empty).
                // Now let the rest of the code handle checking whether the end of the URL is
                // valid.
                break;
            }
        };

        if can_be_last {
            end = Some(i + c.len_utf8());
        }
    }

    if require_host {
        if maybe_host {
            // Can't have just a number without dots as the authority
            if all_numeric && last_dot.is_none() && end != Some(0) {
                return (None, None);
            }

            // If we have something that is not just numeric (not an IP address),
            // check that the TLD looks reasonable. This is to avoid linking things like
            // `abc@v1.1`.
            if !all_numeric {
                if let Some(last_dot) = last_dot {
                    if !valid_tld(&s[last_dot + 1..]) {
                        return (None, None);
                    }
                }
            }

            return (end, last_dot);
        } else {
            return (None, None);
        }
    } else {
        return (end, last_dot);
    }
}

fn valid_tld(tld: &str) -> bool {
    tld.chars()
        .take_while(|c| c.is_ascii_alphabetic())
        .take(2)
        .count()
        >= 2
}
<commit_msg>Add pct-encoded to docs<commit_after>//! Domain name related scanning, used by both email and URL scanners.
//!
//! This is called domains for familiarity but it's about the authority part of URLs as defined in
//! https://datatracker.ietf.org/doc/html/rfc3986#section-3.2
//!
//! ```text
//! authority   = [ userinfo "@" ] host [ ":" port ]
//!
//!
//! userinfo    = *( unreserved / pct-encoded / sub-delims / ":" )
//!
//! host        = IP-literal / IPv4address / reg-name
//!
//! IP-literal = "[" ( IPv6address / IPvFuture  ) "]"
//!
//! IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
//!
//! reg-name    = *( unreserved / pct-encoded / sub-delims )
//!
//!
//! unreserved  = ALPHA / DIGIT / "-" / "." / "_" / "~"
//!
//! sub-delims  = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
//!
//! pct-encoded = "%" HEXDIG HEXDIG
//! ```

use std::char;

pub(crate) fn find_authority_end(
    s: &str,
    mut userinfo_allowed: bool,
    require_host: bool,
    port_allowed: bool,
) -> (Option<usize>, Option<usize>) {
    let mut end = Some(0);

    let mut maybe_last_dot = None;
    let mut last_dot = None;
    let mut dot_allowed = false;
    let mut hyphen_allowed = false;
    let mut all_numeric = true;
    let mut maybe_host = true;
    let mut host_ended = false;

    for (i, c) in s.char_indices() {
        let can_be_last = match c {
            // ALPHA
            'a'..='z' | 'A'..='Z' | '\u{80}'..=char::MAX => {
                // Can start or end a domain label, but not numeric
                dot_allowed = true;
                hyphen_allowed = true;
                last_dot = maybe_last_dot;
                all_numeric = false;

                if host_ended {
                    maybe_host = false;
                }

                !require_host || !host_ended
            }
            // DIGIT
            '0'..='9' => {
                // Same as above, except numeric
                dot_allowed = true;
                hyphen_allowed = true;
                last_dot = maybe_last_dot;

                if host_ended {
                    maybe_host = false;
                }

                !require_host || !host_ended
            }
            // unreserved
            '-' => {
                // Hyphen can't be at start of a label, e.g. `-b` in `a.-b.com`
                if !hyphen_allowed {
                    maybe_host = false;
                }
                // Hyphen can't be at end of a label, e.g. `b-` in `a.b-.com`
                dot_allowed = false;
                all_numeric = false;

                !require_host
            }
            '.' => {
                if !dot_allowed {
                    // Label can't be empty, e.g. `.example.com` or `a..com`
                    host_ended = true;
                }
                dot_allowed = false;
                hyphen_allowed = false;
                maybe_last_dot = Some(i);

                false
            }
            '_' | '~' => {
                // Hostnames can't contain these and we don't want to treat them as delimiters.
                maybe_host = false;

                false
            }
            // sub-delims
            '!' | '$' | '&' | '\'' | '(' | ')' | '*' | '+' | ',' | ';' | '=' => {
                // Can't be in hostnames, but we treat them as delimiters
                host_ended = true;

                if !userinfo_allowed && require_host {
                    // We don't have to look further
                    break;
                }

                false
            }
            ':' => {
                // Could be in userinfo, or we're getting a port now.
                if !userinfo_allowed && !port_allowed {
                    break;
                }

                // Don't advance the last dot when we get to port numbers
                maybe_last_dot = last_dot;

                false
            }
            '@' => {
                if !userinfo_allowed {
                    // We already had userinfo, can't have another `@` in a valid authority.
                    return (None, None);
                }

                // Sike! Everything before this has been userinfo, so let's reset our
                // opinions about all the host bits.
                userinfo_allowed = false;

                maybe_last_dot = None;
                last_dot = None;
                dot_allowed = false;
                hyphen_allowed = false;
                all_numeric = true;
                maybe_host = true;
                host_ended = false;

                false
            }
            '/' => {
                if !require_host {
                    // For schemes where we allow anything, we want to stop at delimiter characters
                    // except if we get a slash closing the URL, which happened here.
                    end = Some(i);
                }
                break;
            }
            _ => {
                // Anything else, this might be the end of the authority (can be empty).
                // Now let the rest of the code handle checking whether the end of the URL is
                // valid.
                break;
            }
        };

        if can_be_last {
            end = Some(i + c.len_utf8());
        }
    }

    if require_host {
        if maybe_host {
            // Can't have just a number without dots as the authority
            if all_numeric && last_dot.is_none() && end != Some(0) {
                return (None, None);
            }

            // If we have something that is not just numeric (not an IP address),
            // check that the TLD looks reasonable. This is to avoid linking things like
            // `abc@v1.1`.
            if !all_numeric {
                if let Some(last_dot) = last_dot {
                    if !valid_tld(&s[last_dot + 1..]) {
                        return (None, None);
                    }
                }
            }

            return (end, last_dot);
        } else {
            return (None, None);
        }
    } else {
        return (end, last_dot);
    }
}

fn valid_tld(tld: &str) -> bool {
    tld.chars()
        .take_while(|c| c.is_ascii_alphabetic())
        .take(2)
        .count()
        >= 2
}
<|endoftext|>


<commit_before>// Implements http://rosettacode.org/wiki/Entropy
extern crate collections;

use std::str::StrSlice;
use collections::hashmap::HashMap;

pub fn shannon_entropy(s: &str) -> f64 {
    let mut map = HashMap::<char, uint>::new();

    for c in s.chars() {
        map.insert_or_update_with(c, 1, |_,v| *v += 1);
    }

    map.iter().fold(0f64, |mut acc, (_, nb)| {
        let p = (*nb as f64)/(s.len() as f64);
        acc -= p * p.log2();
        acc
    })
}

fn main() {
    println!("{:f}", shannon_entropy("1223334444"));
}
<commit_msg>Commented shannon entropy<commit_after>// Implements http://rosettacode.org/wiki/Entropy
extern crate collections;

use std::str::StrSlice;
use collections::hashmap::HashMap;

pub fn shannon_entropy(s: &str) -> f64 {
    let mut map = HashMap::<char, uint>::new();

    // Count occurrences of each char
    for c in s.chars() {
        map.insert_or_update_with(c, 1, |_,v| *v += 1);
    }

    // Calculate the entropy
    let len = s.len() as f64;
    map.iter().fold(0f64, |mut acc, (_, nb)| {
        let p = (*nb as f64) / len;
        acc -= p * p.log2();
        acc
    })
}

fn main() {
    println!("{:f}", shannon_entropy("1223334444"));
}<|endoftext|>


<commit_before>mod abort;
mod breakpoint;
mod bti;
mod common;
mod fp;
mod hvc;
mod ld64b;
mod ldc;
mod mcr;
mod msr;
mod pauth;
mod serror;
mod sve;
#[cfg(test)]
mod tests;
mod wf;

use super::{DecodeError, FieldInfo};
use abort::{decode_iss_data_abort, decode_iss_instruction_abort};
use breakpoint::{
    decode_iss_breakpoint, decode_iss_breakpoint_vector_catch, decode_iss_software_step,
    decode_iss_watchpoint,
};
use bti::decode_iss_bti;
use fp::decode_iss_fp;
use hvc::decode_iss_hvc;
use ld64b::decode_iss_ld64b;
use ldc::decode_iss_ldc;
use mcr::{decode_iss_mcr, decode_iss_mcrr};
use msr::decode_iss_msr;
use pauth::decode_iss_pauth;
use serror::decode_iss_serror;
use sve::decode_iss_sve;
use wf::decode_iss_wf;

fn decode_iss_res0(iss: u64) -> Result<Vec<FieldInfo>, DecodeError> {
    let res0 = FieldInfo::get(iss, "RES0", Some("Reserved"), 0, 25)
        .check_res0()?
        .with_description("ISS is RES0".to_string());
    Ok(vec![res0])
}

/// Decodes the given Exception Syndrome Register value, or returns an error if it is not valid.
pub fn decode(esr: u64) -> Result<Vec<FieldInfo>, DecodeError> {
    let res0 = FieldInfo::get(esr, "RES0", Some("Reserved"), 37, 64).check_res0()?;
    let iss2 = FieldInfo::get(esr, "ISS2", None, 32, 37);
    let ec = FieldInfo::get(esr, "EC", Some("Exception Class"), 26, 32);
    let il =
        FieldInfo::get_bit(esr, "IL", Some("Instruction Length"), 25).describe_bit(describe_il);
    let iss = FieldInfo::get(esr, "ISS", Some("Instruction Specific Syndrome"), 0, 25);
    let (class, iss_subfields, iss_description) = match ec.value {
        0b000000 => ("Unknown reason", decode_iss_res0(iss.value)?, None),
        0b000001 => (
            "Wrapped WF* instruction execution",
            decode_iss_wf(iss.value)?,
            None,
        ),
        0b000011 => (
            "Trapped MCR or MRC access with coproc=0b1111",
            decode_iss_mcr(iss.value)?,
            None,
        ),
        0b000100 => (
            "Trapped MCRR or MRRC access with coproc=0b1111",
            decode_iss_mcrr(iss.value)?,
            None,
        ),
        0b000101 => (
            "Trapped MCR or MRC access with coproc=0b1110",
            decode_iss_mcr(iss.value)?,
            None,
        ),
        0b000110 => (
            "Trapped LDC or STC access",
            decode_iss_ldc(iss.value)?,
            None,
        ),
        0b000111 => (
            "Trapped access to SVE, Advanced SIMD or floating point",
            decode_iss_sve(iss.value)?,
            None,
        ),
        0b001010 => (
            "Trapped execution of an LD64B, ST64B, ST64BV, or ST64BV0 instruction",
            decode_iss_ld64b(iss.value)?,
            None,
        ),
        0b001100 => (
            "Trapped MRRC access with (coproc==0b1110)",
            decode_iss_mcrr(iss.value)?,
            None,
        ),
        0b001101 => ("Branch Target Exception", decode_iss_bti(iss.value)?, None),
        0b001110 => ("Illegal Execution state", decode_iss_res0(iss.value)?, None),
        0b010001 => (
            "SVC instruction execution in AArch32 state",
            decode_iss_hvc(iss.value)?,
            None,
        ),
        0b010101 => (
            "SVC instruction execution in AArch64 state",
            decode_iss_hvc(iss.value)?,
            None,
        ),
        0b011000 => {
            let (subfields, description) = decode_iss_msr(iss.value)?;
            (
                "Trapped MSR, MRS or System instruction execution in AArch64 state",
                subfields,
                description,
            )
        }
        0b011001 => (
            "Access to SVE functionality trapped as a result of CPACR_EL1.ZEN, CPTR_EL2.ZEN, \
                 CPTR_EL2.TZ, or CPTR_EL3.EZ",
            decode_iss_res0(iss.value)?,
            None,
        ),
        0b011100 => (
            "Exception from a Pointer Authentication instruction authentication failure",
            decode_iss_pauth(iss.value)?,
            None,
        ),
        0b100000 => (
            "Instruction Abort from a lower Exception level",
            decode_iss_instruction_abort(iss.value)?,
            None,
        ),
        0b100001 => (
            "Instruction Abort taken without a change in Exception level",
            decode_iss_instruction_abort(iss.value)?,
            None,
        ),
        0b100010 => (
            "PC alignment fault exception",
            decode_iss_res0(iss.value)?,
            None,
        ),
        0b100100 => (
            "Data Abort from a lower Exception level",
            decode_iss_data_abort(iss.value)?,
            None,
        ),
        0b100101 => (
            "Data Abort taken without a change in Exception level",
            decode_iss_data_abort(iss.value)?,
            None,
        ),
        0b100110 => (
            "SP alignment fault exception",
            decode_iss_res0(iss.value)?,
            None,
        ),
        0b101000 => (
            "Trapped floating-point exception taken from AArch32 state",
            decode_iss_fp(iss.value)?,
            None,
        ),
        0b101100 => (
            "Trapped floating-point exception taken from AArch64 state",
            decode_iss_fp(iss.value)?,
            None,
        ),
        0b101111 => ("SError interrupt", decode_iss_serror(iss.value)?, None),
        0b110000 => (
            "Breakpoint exception from a lower Exception level",
            decode_iss_breakpoint_vector_catch(iss.value)?,
            None,
        ),
        0b110001 => (
            "Breakpoint exception taken without a change in Exception level",
            decode_iss_breakpoint_vector_catch(iss.value)?,
            None,
        ),
        0b110010 => (
            "Software Step exception from a lower Exception level",
            decode_iss_software_step(iss.value)?,
            None,
        ),
        0b110011 => (
            "Software Step exception taken without a change in Exception level",
            decode_iss_software_step(iss.value)?,
            None,
        ),
        0b110100 => (
            "Watchpoint exception from a lower Exception level",
            decode_iss_watchpoint(iss.value)?,
            None,
        ),
        0b110101 => (
            "Watchpoint exception taken without a change in Exception level",
            decode_iss_watchpoint(iss.value)?,
            None,
        ),
        0b111000 => (
            "BKPT instruction execution in AArch32 state",
            decode_iss_breakpoint(iss.value)?,
            None,
        ),
        0b111100 => (
            "BRK instruction execution in AArch64 state",
            decode_iss_breakpoint(iss.value)?,
            None,
        ),
        _ => return Err(DecodeError::InvalidEc { ec: ec.value }),
    };
    let iss = FieldInfo {
        description: iss_description,
        subfields: iss_subfields,
        ..iss
    };
    let ec = ec.with_description(class.to_string());
    Ok(vec![res0, iss2, ec, il, iss])
}

fn describe_il(il: bool) -> &'static str {
    if il {
        "32-bit instruction trapped"
    } else {
        "16-bit instruction trapped"
    }
}
<commit_msg>esr: Add HVC and SMC ECs for ESR_EL2<commit_after>mod abort;
mod breakpoint;
mod bti;
mod common;
mod fp;
mod hvc;
mod ld64b;
mod ldc;
mod mcr;
mod msr;
mod pauth;
mod serror;
mod sve;
#[cfg(test)]
mod tests;
mod wf;

use super::{DecodeError, FieldInfo};
use abort::{decode_iss_data_abort, decode_iss_instruction_abort};
use breakpoint::{
    decode_iss_breakpoint, decode_iss_breakpoint_vector_catch, decode_iss_software_step,
    decode_iss_watchpoint,
};
use bti::decode_iss_bti;
use fp::decode_iss_fp;
use hvc::decode_iss_hvc;
use ld64b::decode_iss_ld64b;
use ldc::decode_iss_ldc;
use mcr::{decode_iss_mcr, decode_iss_mcrr};
use msr::decode_iss_msr;
use pauth::decode_iss_pauth;
use serror::decode_iss_serror;
use sve::decode_iss_sve;
use wf::decode_iss_wf;

fn decode_iss_res0(iss: u64) -> Result<Vec<FieldInfo>, DecodeError> {
    let res0 = FieldInfo::get(iss, "RES0", Some("Reserved"), 0, 25)
        .check_res0()?
        .with_description("ISS is RES0".to_string());
    Ok(vec![res0])
}

/// Decodes the given Exception Syndrome Register value, or returns an error if it is not valid.
pub fn decode(esr: u64) -> Result<Vec<FieldInfo>, DecodeError> {
    let res0 = FieldInfo::get(esr, "RES0", Some("Reserved"), 37, 64).check_res0()?;
    let iss2 = FieldInfo::get(esr, "ISS2", None, 32, 37);
    let ec = FieldInfo::get(esr, "EC", Some("Exception Class"), 26, 32);
    let il =
        FieldInfo::get_bit(esr, "IL", Some("Instruction Length"), 25).describe_bit(describe_il);
    let iss = FieldInfo::get(esr, "ISS", Some("Instruction Specific Syndrome"), 0, 25);
    let (class, iss_subfields, iss_description) = match ec.value {
        0b000000 => ("Unknown reason", decode_iss_res0(iss.value)?, None),
        0b000001 => (
            "Wrapped WF* instruction execution",
            decode_iss_wf(iss.value)?,
            None,
        ),
        0b000011 => (
            "Trapped MCR or MRC access with coproc=0b1111",
            decode_iss_mcr(iss.value)?,
            None,
        ),
        0b000100 => (
            "Trapped MCRR or MRRC access with coproc=0b1111",
            decode_iss_mcrr(iss.value)?,
            None,
        ),
        0b000101 => (
            "Trapped MCR or MRC access with coproc=0b1110",
            decode_iss_mcr(iss.value)?,
            None,
        ),
        0b000110 => (
            "Trapped LDC or STC access",
            decode_iss_ldc(iss.value)?,
            None,
        ),
        0b000111 => (
            "Trapped access to SVE, Advanced SIMD or floating point",
            decode_iss_sve(iss.value)?,
            None,
        ),
        0b001010 => (
            "Trapped execution of an LD64B, ST64B, ST64BV, or ST64BV0 instruction",
            decode_iss_ld64b(iss.value)?,
            None,
        ),
        0b001100 => (
            "Trapped MRRC access with (coproc==0b1110)",
            decode_iss_mcrr(iss.value)?,
            None,
        ),
        0b001101 => ("Branch Target Exception", decode_iss_bti(iss.value)?, None),
        0b001110 => ("Illegal Execution state", decode_iss_res0(iss.value)?, None),
        0b010001 => (
            "SVC instruction execution in AArch32 state",
            decode_iss_hvc(iss.value)?,
            None,
        ),
        0b010101 => (
            "SVC instruction execution in AArch64 state",
            decode_iss_hvc(iss.value)?,
            None,
        ),
        0b010110 => (
            "HVC instruction execution in AArch64 state",
            decode_iss_hvc(iss.value)?,
            None,
        ),
        0b010111 => (
            "SMC instruction execution in AArch64 state",
            decode_iss_hvc(iss.value)?,
            None,
        ),
        0b011000 => {
            let (subfields, description) = decode_iss_msr(iss.value)?;
            (
                "Trapped MSR, MRS or System instruction execution in AArch64 state",
                subfields,
                description,
            )
        }
        0b011001 => (
            "Access to SVE functionality trapped as a result of CPACR_EL1.ZEN, CPTR_EL2.ZEN, \
                 CPTR_EL2.TZ, or CPTR_EL3.EZ",
            decode_iss_res0(iss.value)?,
            None,
        ),
        0b011100 => (
            "Exception from a Pointer Authentication instruction authentication failure",
            decode_iss_pauth(iss.value)?,
            None,
        ),
        0b100000 => (
            "Instruction Abort from a lower Exception level",
            decode_iss_instruction_abort(iss.value)?,
            None,
        ),
        0b100001 => (
            "Instruction Abort taken without a change in Exception level",
            decode_iss_instruction_abort(iss.value)?,
            None,
        ),
        0b100010 => (
            "PC alignment fault exception",
            decode_iss_res0(iss.value)?,
            None,
        ),
        0b100100 => (
            "Data Abort from a lower Exception level",
            decode_iss_data_abort(iss.value)?,
            None,
        ),
        0b100101 => (
            "Data Abort taken without a change in Exception level",
            decode_iss_data_abort(iss.value)?,
            None,
        ),
        0b100110 => (
            "SP alignment fault exception",
            decode_iss_res0(iss.value)?,
            None,
        ),
        0b101000 => (
            "Trapped floating-point exception taken from AArch32 state",
            decode_iss_fp(iss.value)?,
            None,
        ),
        0b101100 => (
            "Trapped floating-point exception taken from AArch64 state",
            decode_iss_fp(iss.value)?,
            None,
        ),
        0b101111 => ("SError interrupt", decode_iss_serror(iss.value)?, None),
        0b110000 => (
            "Breakpoint exception from a lower Exception level",
            decode_iss_breakpoint_vector_catch(iss.value)?,
            None,
        ),
        0b110001 => (
            "Breakpoint exception taken without a change in Exception level",
            decode_iss_breakpoint_vector_catch(iss.value)?,
            None,
        ),
        0b110010 => (
            "Software Step exception from a lower Exception level",
            decode_iss_software_step(iss.value)?,
            None,
        ),
        0b110011 => (
            "Software Step exception taken without a change in Exception level",
            decode_iss_software_step(iss.value)?,
            None,
        ),
        0b110100 => (
            "Watchpoint exception from a lower Exception level",
            decode_iss_watchpoint(iss.value)?,
            None,
        ),
        0b110101 => (
            "Watchpoint exception taken without a change in Exception level",
            decode_iss_watchpoint(iss.value)?,
            None,
        ),
        0b111000 => (
            "BKPT instruction execution in AArch32 state",
            decode_iss_breakpoint(iss.value)?,
            None,
        ),
        0b111100 => (
            "BRK instruction execution in AArch64 state",
            decode_iss_breakpoint(iss.value)?,
            None,
        ),
        _ => return Err(DecodeError::InvalidEc { ec: ec.value }),
    };
    let iss = FieldInfo {
        description: iss_description,
        subfields: iss_subfields,
        ..iss
    };
    let ec = ec.with_description(class.to_string());
    Ok(vec![res0, iss2, ec, il, iss])
}

fn describe_il(il: bool) -> &'static str {
    if il {
        "32-bit instruction trapped"
    } else {
        "16-bit instruction trapped"
    }
}
<|endoftext|>


<commit_before>#![cfg(test)]
use crate::per_block_processing;
use super::block_processing_builder::BlockProcessingBuilder;
use types::*;

pub const VALIDATOR_COUNT: usize = 10;

#[test]
fn runs_without_error() {
    let spec = ChainSpec::foundation();
    let mut builder = BlockProcessingBuilder::new(VALIDATOR_COUNT, &spec);

    // Set the state and block to be in the last slot of the 4th epoch.
    let last_slot_of_epoch = (spec.genesis_epoch + 4).end_slot(spec.slots_per_epoch);
    builder.set_slot(last_slot_of_epoch, &spec);

    builder.build_caches(&spec);

    let (block, mut state) = builder.build(&spec);

    per_block_processing(&mut state, &block, &spec).unwrap();
}

<commit_msg>mapped out invalid states... 59<commit_after>#![cfg(test)]
use crate::per_block_processing;
use super::block_processing_builder::BlockProcessingBuilder;
use types::*;

pub const VALIDATOR_COUNT: usize = 10;

#[test]
fn runs_without_error() {
    let spec = ChainSpec::foundation();
    let mut builder = BlockProcessingBuilder::new(VALIDATOR_COUNT, &spec);

    // Set the state and block to be in the last slot of the 4th epoch.
    let last_slot_of_epoch = (spec.genesis_epoch + 4).end_slot(spec.slots_per_epoch);
    builder.set_slot(last_slot_of_epoch, &spec);

    builder.build_caches(&spec);

    let (block, mut state) = builder.build(&spec);

    per_block_processing(&mut state, &block, &spec).unwrap();
}

//  process_block_header
//      Invalid::StateSlotMismatch
//      Invalid::ParentBlockRootMismatch

//  verify_block_signature
//      Invalid::BadSignature

//  process_randao
//      Invalid::BadRandaoSignature

//  process_proposer_slashings
//      Invalid::MaxProposerSlashingsExceeded
//      verify_proposer_slashing
//          Invalid::ProposerUnknown
//          Invalid::ProposalSlotMismatch
//          Invalid::ProposalsIdentical
//          Invalid::ProposerAlreadySlashed
//          Invalid::ProposerAlreadyWithdrawn
//          Invalid::BadProposal1Signature
//          Invalid::BadProposal2Signature

//  process_attester_slashings
//      Invalid::MaxAttesterSlashingsExceed
//      verify_attester_slashing
//          Invalid::AttestationDataIdentical
//          Invalid::NotSlashable
//          Invalid::SlashableAttestation1Invalid
//          Invalid::SlashableAttestation2Invalid

//  process_attestations
//      Invalid::MaxAttestationsExceeded
//      validate_attestation
//          Invalid::PreGenesis
//          Invalid::IncludedTooLate
//          Invalid::IncludedTooEarly
//          Invalid::BadPreviousCrosslink
//          Invalid::AggregationBitfieldIsEmpty
//          Invalid::CustodyBitfieldHasSetBits
//          Invalid::NoCommitteeForShard
//          Invalid::BadCustodyBitfieldLength
//          Invalid::BadAggregationBitfieldLength
//          Invalid::ShardBlockRootNotZero
//          verify_justified_epoch_and_root
//              Invalid::WrongJustifiedEpoch (current)
//              Invalid::WrongJustifiedRoot (current)
//              Invalid::WrongJustifiedEpoch (previous)
//              Invalid::WrongJustifiedRoot (previous)
//          verify_attestation_signature
//              Invalid::BadAggregationBitfieldLength
//              Invalid::BadCustodyBitfieldLength
//              BeaconStateError::UnknownValidator
//              Invalid::BadSignature

//  process_deposits
//      Invalid::MaxDepositsExceeded
//      verify_deposit
//          Invalid::BadProofOfPossession
//          Invalid::BadMerkleProof
//      verify_deposit_index
//          Invalid::BadIndex

//  process_exits
//      Invalid::MaxExitsExceeded
//      verify_exit
//          Invalid::ValidatorUnknown
//          Invalid::AlreadyExited
//          Invalid::AlreadyInitiatedExited
//          Invalid::FutureEpoch
//          Invalid::TooYoungToLeave
//          Invalid::BadSignature

<|endoftext|>