<commit_before>use crate::kind::Trivial;
use crate::ExternType;
use core::ffi::c_void;
use core::fmt::{self, Debug, Display};
use core::marker::PhantomData;
use core::mem::MaybeUninit;
use core::ops::{Deref, DerefMut};
use core::pin::Pin;

/// BInding to C++ `std::shared_ptr<T>`.
#[repr(C)]
pub struct SharedPtr<T>
where
    T: SharedPtrTarget,
{
    repr: [*mut c_void; 2],
    ty: PhantomData<T>,
}

impl<T> SharedPtr<T>
where
    T: SharedPtrTarget,
{
    /// Makes a new SharedPtr wrapping a null pointer.
    ///
    /// Matches the behavior of default-constructing a std::shared\_ptr.
    pub fn null() -> Self {
        let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
        let new = shared_ptr.as_mut_ptr().cast();
        unsafe {
            T::__null(new);
            shared_ptr.assume_init()
        }
    }

    /// Allocates memory on the heap and makes a SharedPtr owner for it.
    pub fn new(value: T) -> Self
    where
        T: ExternType<Kind = Trivial>,
    {
        let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
        let new = shared_ptr.as_mut_ptr().cast();
        unsafe {
            T::__new(value, new);
            shared_ptr.assume_init()
        }
    }

    /// Chacks whether the SharedPtr does not own an object.
    ///
    /// This is the opposite of [std::shared_ptr\<T\>::operator bool](https://en.cppreference.com/w/cpp/memory/shared_ptr/operator_bool).
    pub fn is_null(&self) -> bool {
        let this = self as *const Self as *const c_void;
        let ptr = unsafe { T::__get(this) };
        ptr.is_null()
    }

    /// Returns a reference to the object owned by this SharedPtr if any,
    /// otherwise None.
    pub fn as_ref(&self) -> Option<&T> {
        let this = self as *const Self as *const c_void;
        unsafe { T::__get(this).as_ref() }
    }

    /// Returns a mutable pinned reference to the object owned by this SharedPtr
    /// if any, otherwise None.
    pub fn as_mut(&mut self) -> Option<Pin<&mut T>> {
        let this = self as *mut Self as *mut c_void;
        unsafe {
            let mut_reference = (T::__get(this) as *mut T).as_mut()?;
            Some(Pin::new_unchecked(mut_reference))
        }
    }

    /// Returns a mutable pinned reference to the object owned by this
    /// SharedPtr.
    ///
    /// # Panics
    ///
    /// Panics if the SharedPtr holds a null pointer.
    pub fn pin_mut(&mut self) -> Pin<&mut T> {
        match self.as_mut() {
            Some(target) => target,
            None => panic!("called pin_mut on a null SharedPtr<{}>", T::__NAME),
        }
    }
}

unsafe impl<T> Send for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {}
unsafe impl<T> Sync for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {}

impl<T> Clone for SharedPtr<T>
where
    T: SharedPtrTarget,
{
    fn clone(&self) -> Self {
        let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
        let new = shared_ptr.as_mut_ptr().cast();
        let this = self as *const Self as *mut c_void;
        unsafe {
            T::__clone(this, new);
            shared_ptr.assume_init()
        }
    }
}

impl<T> Drop for SharedPtr<T>
where
    T: SharedPtrTarget,
{
    fn drop(&mut self) {
        let this = self as *mut Self as *mut c_void;
        unsafe { T::__drop(this) }
    }
}

impl<T> Deref for SharedPtr<T>
where
    T: SharedPtrTarget,
{
    type Target = T;

    fn deref(&self) -> &Self::Target {
        match self.as_ref() {
            Some(target) => target,
            None => panic!("called deref on a null SharedPtr<{}>", T::__NAME),
        }
    }
}

impl<T> DerefMut for SharedPtr<T>
where
    T: SharedPtrTarget + Unpin,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        match self.as_mut() {
            Some(target) => Pin::into_inner(target),
            None => panic!("called deref_mut on a null SharedPtr<{}>", T::__NAME),
        }
    }
}

impl<T> Debug for SharedPtr<T>
where
    T: Debug + SharedPtrTarget,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        match self.as_ref() {
            None => formatter.write_str("nullptr"),
            Some(value) => Debug::fmt(value, formatter),
        }
    }
}

impl<T> Display for SharedPtr<T>
where
    T: Display + SharedPtrTarget,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        match self.as_ref() {
            None => formatter.write_str("nullptr"),
            Some(value) => Display::fmt(value, formatter),
        }
    }
}

// Methods are private; not intended to be implemented outside of cxxbridge
// codebase.
pub unsafe trait SharedPtrTarget {
    #[doc(hidden)]
    const __NAME: &'static dyn Display;
    #[doc(hidden)]
    unsafe fn __null(new: *mut c_void);
    #[doc(hidden)]
    unsafe fn __new(value: Self, new: *mut c_void)
    where
        Self: Sized,
    {
        // Opoaque C types do not get this method because they can never exist
        // by value on the Rust side of the bridge.
        let _ = value;
        let _ = new;
        unreachable!()
    }
    #[doc(hidden)]
    unsafe fn __clone(this: *const c_void, new: *mut c_void);
    #[doc(hidden)]
    unsafe fn __get(this: *const c_void) -> *const Self;
    #[doc(hidden)]
    unsafe fn __drop(this: *mut c_void);
}
<commit_msg>Remove SharedPtr to &mut conversions<commit_after>use crate::kind::Trivial;
use crate::ExternType;
use core::ffi::c_void;
use core::fmt::{self, Debug, Display};
use core::marker::PhantomData;
use core::mem::MaybeUninit;
use core::ops::Deref;

/// BInding to C++ `std::shared_ptr<T>`.
#[repr(C)]
pub struct SharedPtr<T>
where
    T: SharedPtrTarget,
{
    repr: [*mut c_void; 2],
    ty: PhantomData<T>,
}

impl<T> SharedPtr<T>
where
    T: SharedPtrTarget,
{
    /// Makes a new SharedPtr wrapping a null pointer.
    ///
    /// Matches the behavior of default-constructing a std::shared\_ptr.
    pub fn null() -> Self {
        let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
        let new = shared_ptr.as_mut_ptr().cast();
        unsafe {
            T::__null(new);
            shared_ptr.assume_init()
        }
    }

    /// Allocates memory on the heap and makes a SharedPtr owner for it.
    pub fn new(value: T) -> Self
    where
        T: ExternType<Kind = Trivial>,
    {
        let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
        let new = shared_ptr.as_mut_ptr().cast();
        unsafe {
            T::__new(value, new);
            shared_ptr.assume_init()
        }
    }

    /// Chacks whether the SharedPtr does not own an object.
    ///
    /// This is the opposite of [std::shared_ptr\<T\>::operator bool](https://en.cppreference.com/w/cpp/memory/shared_ptr/operator_bool).
    pub fn is_null(&self) -> bool {
        let this = self as *const Self as *const c_void;
        let ptr = unsafe { T::__get(this) };
        ptr.is_null()
    }

    /// Returns a reference to the object owned by this SharedPtr if any,
    /// otherwise None.
    pub fn as_ref(&self) -> Option<&T> {
        let this = self as *const Self as *const c_void;
        unsafe { T::__get(this).as_ref() }
    }
}

unsafe impl<T> Send for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {}
unsafe impl<T> Sync for SharedPtr<T> where T: Send + Sync + SharedPtrTarget {}

impl<T> Clone for SharedPtr<T>
where
    T: SharedPtrTarget,
{
    fn clone(&self) -> Self {
        let mut shared_ptr = MaybeUninit::<SharedPtr<T>>::uninit();
        let new = shared_ptr.as_mut_ptr().cast();
        let this = self as *const Self as *mut c_void;
        unsafe {
            T::__clone(this, new);
            shared_ptr.assume_init()
        }
    }
}

impl<T> Drop for SharedPtr<T>
where
    T: SharedPtrTarget,
{
    fn drop(&mut self) {
        let this = self as *mut Self as *mut c_void;
        unsafe { T::__drop(this) }
    }
}

impl<T> Deref for SharedPtr<T>
where
    T: SharedPtrTarget,
{
    type Target = T;

    fn deref(&self) -> &Self::Target {
        match self.as_ref() {
            Some(target) => target,
            None => panic!("called deref on a null SharedPtr<{}>", T::__NAME),
        }
    }
}

impl<T> Debug for SharedPtr<T>
where
    T: Debug + SharedPtrTarget,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        match self.as_ref() {
            None => formatter.write_str("nullptr"),
            Some(value) => Debug::fmt(value, formatter),
        }
    }
}

impl<T> Display for SharedPtr<T>
where
    T: Display + SharedPtrTarget,
{
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        match self.as_ref() {
            None => formatter.write_str("nullptr"),
            Some(value) => Display::fmt(value, formatter),
        }
    }
}

// Methods are private; not intended to be implemented outside of cxxbridge
// codebase.
pub unsafe trait SharedPtrTarget {
    #[doc(hidden)]
    const __NAME: &'static dyn Display;
    #[doc(hidden)]
    unsafe fn __null(new: *mut c_void);
    #[doc(hidden)]
    unsafe fn __new(value: Self, new: *mut c_void)
    where
        Self: Sized,
    {
        // Opoaque C types do not get this method because they can never exist
        // by value on the Rust side of the bridge.
        let _ = value;
        let _ = new;
        unreachable!()
    }
    #[doc(hidden)]
    unsafe fn __clone(this: *const c_void, new: *mut c_void);
    #[doc(hidden)]
    unsafe fn __get(this: *const c_void) -> *const Self;
    #[doc(hidden)]
    unsafe fn __drop(this: *mut c_void);
}
<|endoftext|>


<commit_before>extern crate base64;

use self::base64::encode;
use http::retrieve_asset;
use regex::Regex;
use url::{ParseError, Url};

lazy_static! {
    static ref HAS_PROTOCOL: Regex = Regex::new(r"^[a-z0-9]+:").unwrap();
    static ref REGEX_URL: Regex = Regex::new(r"^https?://").unwrap();
    static ref EMPTY_STRING: String = String::new();
}

static MAGIC: [[&[u8]; 2]; 19] = [
    // Image
    [b"GIF87a", b"image/gif"],
    [b"GIF89a", b"image/gif"],
    [b"\xFF\xD8\xFF", b"image/jpeg"],
    [b"\x89PNG\x0D\x0A\x1A\x0A", b"image/png"],
    [b"<?xml ", b"image/svg+xml"],
    [b"<svg ", b"image/svg+xml"],
    [b"RIFF....WEBPVP8 ", b"image/webp"],
    [b"\x00\x00\x01\x00", b"image/x-icon"],
    // Audio
    [b"ID3", b"audio/mpeg"],
    [b"\xFF\x0E", b"audio/mpeg"],
    [b"\xFF\x0F", b"audio/mpeg"],
    [b"OggS", b"audio/ogg"],
    [b"RIFF....WAVEfmt ", b"audio/wav"],
    [b"fLaC", b"audio/x-flac"],
    // Video
    [b"RIFF....AVI LIST", b"video/avi"],
    [b"....ftyp", b"video/mp4"],
    [b"\x00\x00\x01\x0B", b"video/mpeg"],
    [b"....moov", b"video/quicktime"],
    [b"\x1A\x45\xDF\xA3", b"video/webm"],
];

pub fn data_to_dataurl(mime: &str, data: &[u8]) -> String {
    let mimetype = if mime == "" {
        detect_mimetype(data)
    } else {
        mime.to_string()
    };
    format!("data:{};base64,{}", mimetype, encode(data))
}

pub fn detect_mimetype(data: &[u8]) -> String {
    let mut re = String::new();

    for item in MAGIC.iter() {
        if data.starts_with(item[0]) {
            re = String::from_utf8(item[1].to_vec()).unwrap();
            break;
        }
    }

    re
}

pub fn url_has_protocol(url: &str) -> bool {
    HAS_PROTOCOL.is_match(&url.to_lowercase())
}

pub fn is_data_url(url: &str) -> Result<bool, ParseError> {
    match Url::parse(url) {
        Ok(parsed_url) => Ok(parsed_url.scheme() == "data"),
        Err(err) => Err(err),
    }
}

pub fn is_valid_url(path: &str) -> bool {
    REGEX_URL.is_match(path)
}

pub fn resolve_url(from: &str, to: &str) -> Result<String, ParseError> {
    let result = if is_valid_url(to) {
        to.to_string()
    } else {
        Url::parse(from)?.join(to)?.to_string()
    };

    Ok(result)
}

pub fn resolve_css_imports(
    css_string: &str,
    href: &str,
    opt_user_agent: &str,
    opt_silent: bool,
    opt_insecure: bool,
) -> Result<String, String> {
    let mut resolved_css = String::from(css_string);
    let re =
        Regex::new(r###"url\((?:(?:https?|ftp)://)?"?[\w/\-?=%.]+\.[\w/\-?=%.]+"?\)"###).unwrap();

    for link in re.captures_iter(&css_string) {
        let target_link = if link[0].chars().nth(4) == Some('"') {
            &link[0][5..link[0].len() - 2]
        } else {
            &link[0][4..link[0].len() - 1]
        };
        let embedded_url = String::from([href, "/../", &target_link.to_string()].concat());

        let (css_dataurl, _) = retrieve_asset(
            &embedded_url,
            true, // true
            "",
            opt_user_agent,
            opt_silent,
            opt_insecure,
        )
        .unwrap_or((EMPTY_STRING.clone(), EMPTY_STRING.clone()));

        let replacement = &[
            "\"",
            &css_dataurl
                .replace("\"", &["\\", "\""].concat())
                .to_string(),
            "\"",
        ]
        .concat();
        let t = resolved_css
            .replace(&link[0][4..link[0].len() - 1], &replacement)
            .to_string();
        resolved_css = t.clone();
    }

    let encoded_css = data_to_dataurl("text/css", resolved_css.as_bytes());

    Ok(encoded_css.to_string())
}
<commit_msg>Fixed some errors detecting, parsing, and transforming urls in `resolve_css_imports`<commit_after>extern crate base64;

use self::base64::encode;
use http::retrieve_asset;
use regex::Regex;
use url::{ParseError, Url};

lazy_static! {
    static ref HAS_PROTOCOL: Regex = Regex::new(r"^[a-z0-9]+:").unwrap();
    static ref REGEX_URL: Regex = Regex::new(r"^https?://").unwrap();
    static ref EMPTY_STRING: String = String::new();
}

static MAGIC: [[&[u8]; 2]; 19] = [
    // Image
    [b"GIF87a", b"image/gif"],
    [b"GIF89a", b"image/gif"],
    [b"\xFF\xD8\xFF", b"image/jpeg"],
    [b"\x89PNG\x0D\x0A\x1A\x0A", b"image/png"],
    [b"<?xml ", b"image/svg+xml"],
    [b"<svg ", b"image/svg+xml"],
    [b"RIFF....WEBPVP8 ", b"image/webp"],
    [b"\x00\x00\x01\x00", b"image/x-icon"],
    // Audio
    [b"ID3", b"audio/mpeg"],
    [b"\xFF\x0E", b"audio/mpeg"],
    [b"\xFF\x0F", b"audio/mpeg"],
    [b"OggS", b"audio/ogg"],
    [b"RIFF....WAVEfmt ", b"audio/wav"],
    [b"fLaC", b"audio/x-flac"],
    // Video
    [b"RIFF....AVI LIST", b"video/avi"],
    [b"....ftyp", b"video/mp4"],
    [b"\x00\x00\x01\x0B", b"video/mpeg"],
    [b"....moov", b"video/quicktime"],
    [b"\x1A\x45\xDF\xA3", b"video/webm"],
];

pub fn data_to_dataurl(mime: &str, data: &[u8]) -> String {
    let mimetype = if mime == "" {
        detect_mimetype(data)
    } else {
        mime.to_string()
    };
    format!("data:{};base64,{}", mimetype, encode(data))
}

pub fn detect_mimetype(data: &[u8]) -> String {
    let mut re = String::new();

    for item in MAGIC.iter() {
        if data.starts_with(item[0]) {
            re = String::from_utf8(item[1].to_vec()).unwrap();
            break;
        }
    }

    re
}

pub fn url_has_protocol(url: &str) -> bool {
    HAS_PROTOCOL.is_match(&url.to_lowercase())
}

pub fn is_data_url(url: &str) -> Result<bool, ParseError> {
    match Url::parse(url) {
        Ok(parsed_url) => Ok(parsed_url.scheme() == "data"),
        Err(err) => Err(err),
    }
}

pub fn is_valid_url(path: &str) -> bool {
    REGEX_URL.is_match(path)
}

pub fn resolve_url(from: &str, to: &str) -> Result<String, ParseError> {
    let result = if is_valid_url(to) {
        to.to_string()
    } else {
        Url::parse(from)?.join(to)?.to_string()
    };

    Ok(result)
}

pub fn resolve_css_imports(
    css_string: &str,
    href: &str,
    opt_user_agent: &str,
    opt_silent: bool,
    opt_insecure: bool,
) -> Result<String, String> {
    let mut resolved_css = String::from(css_string);
    let re = Regex::new(r###"url\("?([^"]+)"?\)"###).unwrap();

    for link in re.captures_iter(&css_string) {
        let target_link = dbg!(link.get(1).unwrap().as_str());

        // Generate absolute URL for content
        let embedded_url = match resolve_url(href, target_link) {
            Ok(url) => url,
            Err(_) => continue, // Malformed URL
        };

        let (css_dataurl, _) = retrieve_asset(
            &embedded_url,
            true, // true
            "",
            opt_user_agent,
            opt_silent,
            opt_insecure,
        )
        .unwrap_or((EMPTY_STRING.clone(), EMPTY_STRING.clone()));

        let replacement = &[
            "\"",
            &css_dataurl
                .replace("\"", &["\\", "\""].concat())
                .to_string(),
            "\"",
        ]
        .concat();
        let t = resolved_css
            .replace(&link[0][4..link[0].len() - 1], &replacement)
            .to_string();
        resolved_css = t.clone();
    }

    let encoded_css = data_to_dataurl("text/css", resolved_css.as_bytes());

    Ok(encoded_css.to_string())
}
<|endoftext|>


<commit_before>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Common utilities.

use std::cmp;
use num::Float;

/// Remove a trailing newline from the given string in place.
pub fn trim_newline(s: &mut String) {
    if s.ends_with("\n") {
        s.pop();
    }
}

/// In place implementation of scan over a slice.
pub fn scan<T: Copy, F: Fn(T, T) -> T>(a: &mut [T], op: F) {
    let mut s = a[0];
    for v in a.iter_mut().skip(1) {
        s = op(s, *v);
        *v = s;
    }
}

// Inplace implementation of prescan over a slice.
pub fn prescan<T: Copy, F: Fn(T, T) -> T>(a: &mut [T], neutral: T, op: F) {
    let mut s = neutral;
    for v in a.iter_mut() {
        let t = *v;
        *v = s;
        s = op(s, t);
    }
}

#[derive(PartialOrd, PartialEq, Debug)]
pub struct NonNaNFloat<F: Float>(F);

impl<F: Float> NonNaNFloat<F> {
    pub fn new(v: F) -> Option<Self> {
        if v.is_nan() {
            Some(NonNaNFloat(v))
        }
        else {
            None
        }
    }

    pub fn unwrap(&self) -> F {
        let &NonNaNFloat(v) = self;
        v
    }
}

impl<F: Float> Eq for NonNaNFloat<F> {}

impl<F: Float> Ord for NonNaNFloat<F> {
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        self.partial_cmp(other).unwrap()
    }
}

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

    #[test]
    fn test_scan() {
        let mut a = vec![1, 0, 0, 1];
        scan(&mut a[..], |a, b| a + b);
        assert_eq!(a, vec![1, 1, 1, 2]);
    }

    #[test]
    fn test_prescan() {
        let mut a = vec![1, 0, 0, 1];
        prescan(&mut a[..], 0, |a, b| a + b);
        assert_eq!(a, vec![0, 1, 1, 1]);
    }

    #[test]
    fn test_nonnanfloat() {
        let mut v = [NonNaNFloat(5.1), NonNaNFloat(1.3)];
        v.sort();
        assert_eq!(v, [NonNaNFloat(1.3), NonNaNFloat(5.1)]);
    }
}
<commit_msg>Implement Copy for NonNaNFloat.<commit_after>// Copyright 2014 Johannes Köster.
// Licensed under the MIT license (http://opensource.org/licenses/MIT)
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Common utilities.

use std::cmp;
use num::Float;

/// Remove a trailing newline from the given string in place.
pub fn trim_newline(s: &mut String) {
    if s.ends_with("\n") {
        s.pop();
    }
}

/// In place implementation of scan over a slice.
pub fn scan<T: Copy, F: Fn(T, T) -> T>(a: &mut [T], op: F) {
    let mut s = a[0];
    for v in a.iter_mut().skip(1) {
        s = op(s, *v);
        *v = s;
    }
}

// Inplace implementation of prescan over a slice.
pub fn prescan<T: Copy, F: Fn(T, T) -> T>(a: &mut [T], neutral: T, op: F) {
    let mut s = neutral;
    for v in a.iter_mut() {
        let t = *v;
        *v = s;
        s = op(s, t);
    }
}

#[derive(PartialOrd, PartialEq, Debug, Copy, Clone)]
pub struct NonNaNFloat<F: Float>(F);

impl<F: Float> NonNaNFloat<F> {
    pub fn new(v: F) -> Option<Self> {
        if v.is_nan() {
            Some(NonNaNFloat(v))
        }
        else {
            None
        }
    }

    pub fn unwrap(&self) -> F {
        let &NonNaNFloat(v) = self;
        v
    }
}

impl<F: Float> Eq for NonNaNFloat<F> {}

impl<F: Float> Ord for NonNaNFloat<F> {
    fn cmp(&self, other: &Self) -> cmp::Ordering {
        self.partial_cmp(other).unwrap()
    }
}

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

    #[test]
    fn test_scan() {
        let mut a = vec![1, 0, 0, 1];
        scan(&mut a[..], |a, b| a + b);
        assert_eq!(a, vec![1, 1, 1, 2]);
    }

    #[test]
    fn test_prescan() {
        let mut a = vec![1, 0, 0, 1];
        prescan(&mut a[..], 0, |a, b| a + b);
        assert_eq!(a, vec![0, 1, 1, 1]);
    }

    #[test]
    fn test_nonnanfloat() {
        let mut v = [NonNaNFloat(5.1), NonNaNFloat(1.3)];
        v.sort();
        assert_eq!(v, [NonNaNFloat(1.3), NonNaNFloat(5.1)]);
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#![allow(unused_variables)]

use basetypes::*;

struct Bitboard {
    piece_type_bb: [u64; 6],
    color_bb: [u64; 2],
}

pub struct Board {
    bitboard: Bitboard,
    to_move: Color,
    castling_rights: CastlingRights,
    en_passant_square: Option<Square>,
    halfmove_clock: u32,
    fullmove_number: u32,
}

pub struct ParseError;

pub type Result<T> = ::std::result::Result<T, ParseError>;

impl Board {
    pub fn from_fen(fen: &str) -> Result<Board> {
        let parts: Vec<_> = fen.split_whitespace().collect();

        if parts.len() == 6 {
            Ok(Board {
                bitboard: try!(Board::parse_fen_piece_placement(parts[0])),
                to_move: try!(Board::parse_fen_active_color(parts[1])),
                castling_rights: try!(Board::parse_fen_castling_rights(parts[2])),
                en_passant_square: try!(Board::parse_fen_enpassant_square(parts[3])),
                halfmove_clock: try!(parts[4].parse::<u32>().map_err(|e| ParseError)),
                fullmove_number: try!(parts[5].parse::<u32>().map_err(|e| ParseError)),
            })
        } else {
            Err(ParseError)
        }
    }

    // Perform basic position sanity checks.
    // fn is_position_possible(&self) -> bool {

    // }

    // Parses a square in algebraic notation.
    fn parse_square_notation(s: &str) -> Result<Square> {
        use regex::Regex;
        let re = Regex::new(r"^[a-h][1-8]$").unwrap();  // TODO: Do this at compile time!

        if re.is_match(s) {
            let mut chars = s.chars();
            let file = (chars.next().unwrap().to_digit(18).unwrap() - 10) as File;
            let rank = (chars.next().unwrap().to_digit(9).unwrap() - 1) as Rank;
            Ok(square(file, rank))
        } else {
            Err(ParseError)
        }
    }

    // Parse FEN piece placement field.
    fn parse_fen_piece_placement(s: &str) -> Result<Bitboard> {

        // We start with an empty bitboard. FEN describes the board
        // starting at A8 and going toward H1.
        let mut bitboard = Bitboard {
            piece_type_bb: [0u64; 6],
            color_bb: [0u64; 2],
        };
        let mut file = 0;
        let mut rank = 7;

        // These are the possible productions in the grammar.
        enum Token {
            Piece(Color, PieceType),
            EmptySquares(u32),
            Separator,
        }

        for c in s.chars() {

            // Parse the next character.
            let token = match c {
                'K' => Token::Piece(WHITE, KING),
                'Q' => Token::Piece(WHITE, QUEEN),
                'R' => Token::Piece(WHITE, ROOK),
                'B' => Token::Piece(WHITE, BISHOP),
                'N' => Token::Piece(WHITE, KNIGHT),
                'P' => Token::Piece(WHITE, PAWN),
                'k' => Token::Piece(BLACK, KING),
                'q' => Token::Piece(BLACK, QUEEN),
                'r' => Token::Piece(BLACK, ROOK),
                'b' => Token::Piece(BLACK, BISHOP),
                'n' => Token::Piece(BLACK, KNIGHT),
                'p' => Token::Piece(BLACK, PAWN),
                n @ '1'...'8' => Token::EmptySquares(n.to_digit(9).unwrap()),
                '/' => Token::Separator,
                _ => return Err(ParseError),
            };

            // Update the bitboard accordting to the token.
            match token {
                Token::Piece(color, piece_type) => {
                    if file > 7 {
                        return Err(ParseError);
                    }
                    let mask = 1 << square(file, rank);
                    bitboard.piece_type_bb[piece_type] |= mask;
                    bitboard.color_bb[color] |= mask;
                    file += 1;
                }
                Token::EmptySquares(n) => {
                    file += n as File;
                    if file > 8 {
                        return Err(ParseError);
                    }
                }
                Token::Separator => {
                    if file == 8 && rank > 0 {
                        file = 0;
                        rank -= 1;
                    } else {
                        return Err(ParseError);
                    }
                }
            }
        }

        // Ensure the piece placement field had the right length.
        if file == 8 && rank == 0 {
            Ok(bitboard)
        } else {
            Err(ParseError)
        }
    }

    // Parse FEN active color field.
    fn parse_fen_active_color(s: &str) -> Result<Color> {
        match s {
            "w" => Ok(WHITE),
            "b" => Ok(BLACK),
            _ => Err(ParseError),
        }
    }

    // Parses FEN castling rights field.
    fn parse_fen_castling_rights(s: &str) -> Result<CastlingRights> {

        // We start with no caltling allowed.
        let mut castling_rights = [(false, false); 2];

        // Then we parse the content and update the castling rights.
        if s != "-" {
            for c in s.chars() {
                match c {
                    'K' => {
                        if !castling_rights[WHITE].0 {
                            castling_rights[WHITE].0 = true;
                        } else {
                            return Err(ParseError);
                        }
                    }
                    'Q' => {
                        if !castling_rights[WHITE].1 {
                            castling_rights[WHITE].1 = true;
                        } else {
                            return Err(ParseError);
                        }
                    }
                    'k' => {
                        if !castling_rights[BLACK].0 {
                            castling_rights[BLACK].0 = true;
                        } else {
                            return Err(ParseError);
                        }
                    }
                    'q' => {
                        if !castling_rights[BLACK].1 {
                            castling_rights[BLACK].1 = true;
                        } else {
                            return Err(ParseError);
                        }
                    }
                    _ => {
                        return Err(ParseError);
                    }
                };
            }
        }

        // Successfully parsed.
        Ok(castling_rights)
    }

    // Parse FEN en-passant square field.
    fn parse_fen_enpassant_square(s: &str) -> Result<Option<Square>> {
        match s {
            "-" => Ok(None),
            _ => Ok(Some(try!(Board::parse_square_notation(s).map_err(|e| ParseError)))),
        }
    }
}

pub type AttackArray = [[u64; 64]; 5];  // for example
                                   // attack_set[Pieces::Queen][0]
                                   // gives the attack set for a queen
                                   // at A1.

pub fn generate_attack_and_blockers_arrays() -> (AttackArray, AttackArray) {

    fn square2grid_index(i: Square) -> usize {
        ((i / 8) * 10 + (i % 8) + 21)
    }

    // Generate a 10x12 grid -- 0xff is the "out of board" marker.
    let mut grid = [0xffu8; 120];
    for i in 0..64 {
        grid[square2grid_index(i)] = i as u8;
    }

    // 0: Queen, 1: Rook, 3: Bishop, 3: Knight, 4: King.
    static PIECE_LONGRANGE: [bool; 5] = [true, true, true, false, false];
    static PIECE_DELTAS: [[i8; 8]; 5] = [[-11, -10, -9, -1, 1, 9, 10, 11],
                                         [0, -10, 0, -1, 1, 0, 10, 0],
                                         [-11, 0, -9, 0, 0, 9, 0, 11],
                                         [-21, -19, -12, -8, 8, 12, 19, 21],
                                         [-11, -10, -9, -1, 1, 9, 10, 11]];

    // At the end those arrays will hold the attack bitsets, and the
    // "blockers and beyond" bitsets for each piece on each possible
    // square.
    let mut attack_array = [[0u64; 64]; 5];
    let mut blockers_array = [[0u64; 64]; 5];

    for piece_type in 0..5 {
        for square in 0..64 {
            let mut attack = 0u64;
            let mut blockers = 0u64;
            for move_direction in 0..8 {
                let delta = PIECE_DELTAS[piece_type][move_direction];
                if delta != 0 {
                    let mut last_mask = 0u64;
                    let mut curr_grid_index = square2grid_index(square);
                    loop {
                        curr_grid_index = (curr_grid_index as i8 + delta) as usize;
                        let curr_square = grid[curr_grid_index];
                        if curr_square != 0xff {
                            last_mask = 1 << curr_square;
                            attack |= last_mask;
                            blockers |= last_mask;
                            if PIECE_LONGRANGE[piece_type] {
                                continue;
                            }
                        }
                        blockers &= !last_mask;
                        break;
                    }
                }
            }
            attack_array[piece_type][square] = attack;
            blockers_array[piece_type][square] = blockers;
        }
    }

    (attack_array, blockers_array)
}

// Forsyth–Edwards Notation

// The StateInfo struct stores information needed to restore a Position
// object to its previous state when we retract a move. Whenever a move
// is made on the board (by calling Position::do_move), a StateInfo
// object must be passed as a parameter.

// struct StateInfo {
//   Key pawnKey, materialKey;
//   Value npMaterial[COLOR_NB];
//   int castlingRights, rule50, pliesFromNull;
//   Score psq;
//   Square epSquare;

//   Key key;
//   Bitboard checkersBB;
//   PieceType capturedType;
//   StateInfo* previous;
// };

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

    #[test]
    fn test_fen_parsing() {
        assert!(Board::from_fen("nbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Board::from_fen("rnbqkbnr1/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Board::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBN b KQkq e3 0 1")
                    .is_err());
        assert!(Board::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR/ b KQkq e3 0 1")
                    .is_err());
        assert!(Board::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNRR b KQkq e3 0 1")
                    .is_err());
        assert!(Board::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPP01PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Board::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPP91PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Board::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPP*1PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Board::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 * 1")
                    .is_err());
        assert!(Board::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 *")
                    .is_err());
        assert!(Board::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b - e3 0 1")
                    .is_ok());
        assert!(Board::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_ok());
    }

    #[test]
    fn test_attack_sets() {
        use basetypes::*;
        let (att_sets, bl_sets) = generate_attack_and_blockers_arrays();
        assert_eq!(att_sets[KING][0], 0b11 << 8 | 0b10);
        assert_eq!(bl_sets[KING][0], 0);
        assert_eq!(att_sets[ROOK][0],
                   0b11111110 | 1 << 8 | 1 << 16 | 1 << 24 | 1 << 32 | 1 << 40 | 1 << 48 | 1 << 56);
        assert_eq!(bl_sets[ROOK][0],
                   0b01111110 | 1 << 8 | 1 << 16 | 1 << 24 | 1 << 32 | 1 << 40 | 1 << 48 | 0 << 56);
    }

}
<commit_msg>Added FEN grammar description comment.<commit_after>#![allow(dead_code)]
#![allow(unused_variables)]

use basetypes::*;

struct Bitboard {
    piece_type_bb: [u64; 6],
    color_bb: [u64; 2],
}

pub struct Board {
    bitboard: Bitboard,
    to_move: Color,
    castling_rights: CastlingRights,
    en_passant_square: Option<Square>,
    halfmove_clock: u32,
    fullmove_number: u32,
}

pub struct ParseError;

pub type Result<T> = ::std::result::Result<T, ParseError>;

impl Board {

    // A FEN string defines a particular position using only the ASCII character set.
    //
    // A FEN string contains six fields separated by a space. The fields are:
    //
    // 1) Piece placement (from white's perspective). Each rank is described, starting
    //    with rank 8 and ending with rank 1. Within each rank, the contents of each
    //    square are described from file A through file H. Following the Standard
    //    Algebraic Notation (SAN), each piece is identified by a single letter taken
    //    from the standard English names. White pieces are designated using upper-case
    //    letters ("PNBRQK") whilst Black uses lowercase ("pnbrqk"). Blank squares are
    //    noted using digits 1 through 8 (the number of blank squares), and "/"
    //    separates ranks.
    //
    // 2) Active color. "w" means white moves next, "b" means black.
    //
    // 3) Castling availability. If neither side can castle, this is "-". Otherwise,
    //    this has one or more letters: "K" (White can castle kingside), "Q" (White
    //    can castle queenside), "k" (Black can castle kingside), and/or "q" (Black
    //    can castle queenside).
    //
    // 4) En passant target square (in algebraic notation). If there's no en passant
    //    target square, this is "-". If a pawn has just made a 2-square move, this
    //    is the position "behind" the pawn. This is recorded regardless of whether
    //    there is a pawn in position to make an en passant capture.
    //
    // 5) Halfmove clock. This is the number of halfmoves since the last pawn advance
    //    or capture. This is used to determine if a draw can be claimed under the
    //    fifty-move rule.
    //
    // 6) Fullmove number. The number of the full move. It starts at 1, and is
    //    incremented after Black's move.
    //
    pub fn from_fen(fen: &str) -> Result<Board> {
        let parts: Vec<_> = fen.split_whitespace().collect();

        if parts.len() == 6 {
            Ok(Board {
                bitboard: try!(Board::parse_fen_piece_placement(parts[0])),
                to_move: try!(Board::parse_fen_active_color(parts[1])),
                castling_rights: try!(Board::parse_fen_castling_rights(parts[2])),
                en_passant_square: try!(Board::parse_fen_enpassant_square(parts[3])),
                halfmove_clock: try!(parts[4].parse::<u32>().map_err(|e| ParseError)),
                fullmove_number: try!(parts[5].parse::<u32>().map_err(|e| ParseError)),
            })
        } else {
            Err(ParseError)
        }
    }

    // Perform basic position sanity checks.
    // fn is_position_possible(&self) -> bool {

    // }

    // Parses a square in algebraic notation.
    fn parse_square_notation(s: &str) -> Result<Square> {
        use regex::Regex;
        let re = Regex::new(r"^[a-h][1-8]$").unwrap();  // TODO: Do this at compile time!

        if re.is_match(s) {
            let mut chars = s.chars();
            let file = (chars.next().unwrap().to_digit(18).unwrap() - 10) as File;
            let rank = (chars.next().unwrap().to_digit(9).unwrap() - 1) as Rank;
            Ok(square(file, rank))
        } else {
            Err(ParseError)
        }
    }

    // Parse FEN piece placement field.
    fn parse_fen_piece_placement(s: &str) -> Result<Bitboard> {

        // We start with an empty bitboard. FEN describes the board
        // starting at A8 and going toward H1.
        let mut bitboard = Bitboard {
            piece_type_bb: [0u64; 6],
            color_bb: [0u64; 2],
        };
        let mut file = 0;
        let mut rank = 7;

        // These are the possible productions in the grammar.
        enum Token {
            Piece(Color, PieceType),
            EmptySquares(u32),
            Separator,
        }

        for c in s.chars() {

            // Parse the next character.
            let token = match c {
                'K' => Token::Piece(WHITE, KING),
                'Q' => Token::Piece(WHITE, QUEEN),
                'R' => Token::Piece(WHITE, ROOK),
                'B' => Token::Piece(WHITE, BISHOP),
                'N' => Token::Piece(WHITE, KNIGHT),
                'P' => Token::Piece(WHITE, PAWN),
                'k' => Token::Piece(BLACK, KING),
                'q' => Token::Piece(BLACK, QUEEN),
                'r' => Token::Piece(BLACK, ROOK),
                'b' => Token::Piece(BLACK, BISHOP),
                'n' => Token::Piece(BLACK, KNIGHT),
                'p' => Token::Piece(BLACK, PAWN),
                n @ '1'...'8' => Token::EmptySquares(n.to_digit(9).unwrap()),
                '/' => Token::Separator,
                _ => return Err(ParseError),
            };

            // Update the bitboard accordting to the token.
            match token {
                Token::Piece(color, piece_type) => {
                    if file > 7 {
                        return Err(ParseError);
                    }
                    let mask = 1 << square(file, rank);
                    bitboard.piece_type_bb[piece_type] |= mask;
                    bitboard.color_bb[color] |= mask;
                    file += 1;
                }
                Token::EmptySquares(n) => {
                    file += n as File;
                    if file > 8 {
                        return Err(ParseError);
                    }
                }
                Token::Separator => {
                    if file == 8 && rank > 0 {
                        file = 0;
                        rank -= 1;
                    } else {
                        return Err(ParseError);
                    }
                }
            }
        }

        // Ensure the piece placement field had the right length.
        if file == 8 && rank == 0 {
            Ok(bitboard)
        } else {
            Err(ParseError)
        }
    }

    // Parse FEN active color field.
    fn parse_fen_active_color(s: &str) -> Result<Color> {
        match s {
            "w" => Ok(WHITE),
            "b" => Ok(BLACK),
            _ => Err(ParseError),
        }
    }

    // Parses FEN castling rights field.
    fn parse_fen_castling_rights(s: &str) -> Result<CastlingRights> {

        // We start with no caltling allowed.
        let mut castling_rights = [(false, false); 2];

        // Then we parse the content and update the castling rights.
        if s != "-" {
            for c in s.chars() {
                match c {
                    'K' => {
                        if !castling_rights[WHITE].0 {
                            castling_rights[WHITE].0 = true;
                        } else {
                            return Err(ParseError);
                        }
                    }
                    'Q' => {
                        if !castling_rights[WHITE].1 {
                            castling_rights[WHITE].1 = true;
                        } else {
                            return Err(ParseError);
                        }
                    }
                    'k' => {
                        if !castling_rights[BLACK].0 {
                            castling_rights[BLACK].0 = true;
                        } else {
                            return Err(ParseError);
                        }
                    }
                    'q' => {
                        if !castling_rights[BLACK].1 {
                            castling_rights[BLACK].1 = true;
                        } else {
                            return Err(ParseError);
                        }
                    }
                    _ => {
                        return Err(ParseError);
                    }
                };
            }
        }

        // Successfully parsed.
        Ok(castling_rights)
    }

    // Parse FEN en-passant square field.
    fn parse_fen_enpassant_square(s: &str) -> Result<Option<Square>> {
        match s {
            "-" => Ok(None),
            _ => Ok(Some(try!(Board::parse_square_notation(s).map_err(|e| ParseError)))),
        }
    }
}

pub type AttackArray = [[u64; 64]; 5];  // for example
                                   // attack_set[Pieces::Queen][0]
                                   // gives the attack set for a queen
                                   // at A1.

pub fn generate_attack_and_blockers_arrays() -> (AttackArray, AttackArray) {

    fn square2grid_index(i: Square) -> usize {
        ((i / 8) * 10 + (i % 8) + 21)
    }

    // Generate a 10x12 grid -- 0xff is the "out of board" marker.
    let mut grid = [0xffu8; 120];
    for i in 0..64 {
        grid[square2grid_index(i)] = i as u8;
    }

    // 0: Queen, 1: Rook, 3: Bishop, 3: Knight, 4: King.
    static PIECE_LONGRANGE: [bool; 5] = [true, true, true, false, false];
    static PIECE_DELTAS: [[i8; 8]; 5] = [[-11, -10, -9, -1, 1, 9, 10, 11],
                                         [0, -10, 0, -1, 1, 0, 10, 0],
                                         [-11, 0, -9, 0, 0, 9, 0, 11],
                                         [-21, -19, -12, -8, 8, 12, 19, 21],
                                         [-11, -10, -9, -1, 1, 9, 10, 11]];

    // At the end those arrays will hold the attack bitsets, and the
    // "blockers and beyond" bitsets for each piece on each possible
    // square.
    let mut attack_array = [[0u64; 64]; 5];
    let mut blockers_array = [[0u64; 64]; 5];

    for piece_type in 0..5 {
        for square in 0..64 {
            let mut attack = 0u64;
            let mut blockers = 0u64;
            for move_direction in 0..8 {
                let delta = PIECE_DELTAS[piece_type][move_direction];
                if delta != 0 {
                    let mut last_mask = 0u64;
                    let mut curr_grid_index = square2grid_index(square);
                    loop {
                        curr_grid_index = (curr_grid_index as i8 + delta) as usize;
                        let curr_square = grid[curr_grid_index];
                        if curr_square != 0xff {
                            last_mask = 1 << curr_square;
                            attack |= last_mask;
                            blockers |= last_mask;
                            if PIECE_LONGRANGE[piece_type] {
                                continue;
                            }
                        }
                        blockers &= !last_mask;
                        break;
                    }
                }
            }
            attack_array[piece_type][square] = attack;
            blockers_array[piece_type][square] = blockers;
        }
    }

    (attack_array, blockers_array)
}

// Forsyth–Edwards Notation

// The StateInfo struct stores information needed to restore a Position
// object to its previous state when we retract a move. Whenever a move
// is made on the board (by calling Position::do_move), a StateInfo
// object must be passed as a parameter.

// struct StateInfo {
//   Key pawnKey, materialKey;
//   Value npMaterial[COLOR_NB];
//   int castlingRights, rule50, pliesFromNull;
//   Score psq;
//   Square epSquare;

//   Key key;
//   Bitboard checkersBB;
//   PieceType capturedType;
//   StateInfo* previous;
// };

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

    #[test]
    fn test_fen_parsing() {
        assert!(Board::from_fen("nbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Board::from_fen("rnbqkbnr1/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Board::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBN b KQkq e3 0 1")
                    .is_err());
        assert!(Board::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR/ b KQkq e3 0 1")
                    .is_err());
        assert!(Board::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNRR b KQkq e3 0 1")
                    .is_err());
        assert!(Board::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPP01PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Board::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPP91PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Board::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPP*1PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_err());
        assert!(Board::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 * 1")
                    .is_err());
        assert!(Board::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 *")
                    .is_err());
        assert!(Board::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b - e3 0 1")
                    .is_ok());
        assert!(Board::from_fen("rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq e3 0 1")
                    .is_ok());
    }

    #[test]
    fn test_attack_sets() {
        use basetypes::*;
        let (att_sets, bl_sets) = generate_attack_and_blockers_arrays();
        assert_eq!(att_sets[KING][0], 0b11 << 8 | 0b10);
        assert_eq!(bl_sets[KING][0], 0);
        assert_eq!(att_sets[ROOK][0],
                   0b11111110 | 1 << 8 | 1 << 16 | 1 << 24 | 1 << 32 | 1 << 40 | 1 << 48 | 1 << 56);
        assert_eq!(bl_sets[ROOK][0],
                   0b01111110 | 1 << 8 | 1 << 16 | 1 << 24 | 1 << 32 | 1 << 40 | 1 << 48 | 0 << 56);
    }

}
<|endoftext|>


<commit_before>use std::io;
use std::iter::Iterator;
use std::slice;

use flate2::read::GzDecoder;
use tar;
use time::Timespec;

use collections::{CollectionsStatus, SignatureChain, SignatureFile};
use backend::Backend;

pub struct BackupFiles {
    snapshots: Vec<Snapshot>
}

pub struct Snapshot {
    pub time: Timespec
}

pub struct File {
    pub name: String,
    pub last_modified: Timespec
}

/// Iterator over a list of backup snapshots.
pub type Snapshots<'a> = slice::Iter<'a, Snapshot>;

impl BackupFiles {
    pub fn new<B: Backend>(backend: &B) -> io::Result<BackupFiles> {
        let collection = {
            let filenames = try!(backend.get_file_names());
            CollectionsStatus::from_filenames(&filenames)
        };
        let chains = collection.signature_chains();
        for chain in chains {
            let file = try!(backend.open_file(chain.fullsig.file_name.as_ref()));
            if chain.fullsig.compressed {
                let gz_decoder = try!(GzDecoder::new(file));
                let mut tar = tar::Archive::new(gz_decoder);
                for tarfile in try!(tar.files_mut()) {
                    if let Ok(tarfile) = tarfile {
                        let header = tarfile.header();
                        let path = unwrap_or_continue!(header.path());
                        let mut pcomps = path.components();
                        // split the path in (first directory, the remaining path)
                        // the first is the type, the remaining is the real path
                        let pfirst = unwrap_opt_or_continue!(pcomps.next());
                        let ptail = pcomps.as_path();
                    }
                }
            }
        }
        // TODO: go from signature chains to snapshots
        Ok(BackupFiles{ snapshots: Vec::new() })
    }

    pub fn snapshots(&self) -> Snapshots {
        self.snapshots.iter()
    }
}

<commit_msg>Extracted difftype from signature file path<commit_after>use std::io;
use std::iter::Iterator;
use std::slice;
use std::path::Component;

use flate2::read::GzDecoder;
use tar;
use time::Timespec;

use collections::{CollectionsStatus, SignatureChain, SignatureFile};
use backend::Backend;

pub struct BackupFiles {
    snapshots: Vec<Snapshot>
}

pub struct Snapshot {
    pub time: Timespec
}

pub struct File {
    pub name: String,
    pub last_modified: Timespec
}

/// Iterator over a list of backup snapshots.
pub type Snapshots<'a> = slice::Iter<'a, Snapshot>;

enum DiffType {
    Signature,
    Snapshot,
    Deleted
}

impl BackupFiles {
    pub fn new<B: Backend>(backend: &B) -> io::Result<BackupFiles> {
        let collection = {
            let filenames = try!(backend.get_file_names());
            CollectionsStatus::from_filenames(&filenames)
        };
        let chains = collection.signature_chains();
        for chain in chains {
            let file = try!(backend.open_file(chain.fullsig.file_name.as_ref()));
            if chain.fullsig.compressed {
                let gz_decoder = try!(GzDecoder::new(file));
                let mut tar = tar::Archive::new(gz_decoder);
                for tarfile in try!(tar.files_mut()) {
                    if let Ok(tarfile) = tarfile {
                        let header = tarfile.header();
                        let path = unwrap_or_continue!(header.path());
                        let mut pcomps = path.components();
                        // split the path in (first directory, the remaining path)
                        // the first is the type, the remaining is the real path
                        let pfirst = unwrap_opt_or_continue!(pcomps.next());
                        if let Component::Normal(strfirst) = pfirst {
                            let difftype = match strfirst.to_str() {
                                Some("signature") => DiffType::Signature,
                                Some("snapshot")  => DiffType::Snapshot,
                                Some("deleted")   => DiffType::Deleted,
                                _                 => { continue; }
                            };
                            let realpath = pcomps.as_path();
                        }
                    }
                }
            }
        }
        // TODO: go from signature chains to snapshots
        Ok(BackupFiles{ snapshots: Vec::new() })
    }

    pub fn snapshots(&self) -> Snapshots {
        self.snapshots.iter()
    }
}

<|endoftext|>


<commit_before>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
*/

use std::fmt;
use std::str::SplitWhitespace;

#[derive(Copy, Clone)]
pub struct FP {
 	x:BIG
}

use big::BIG;
use dbig::DBIG;
use rom;
use rom::Chunk;

impl fmt::Display for FP {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "FP: [ {} ]", self.x)
    }
}

impl fmt::Debug for FP {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "FP: [ {} ]", self.x)
    }
}

impl PartialEq for FP {
    fn eq(&self, other: &FP) -> bool {
        return self.x == other.x;
    }
}

impl FP {

/* Constructors */
	pub fn new() -> FP {
		FP {
				x: BIG::new()
		}
	}

	pub fn new_int(a:isize) -> FP {
		let mut f=FP::new();
		f.x.inc(a);
		f.nres();
		return f;
	}

	pub fn new_copy(y:&FP) -> FP {
		let mut f=FP::new();
		f.x.copy(&(y.x));
		return f;
	}

	pub fn new_big(y:&BIG) -> FP {
		let mut f=FP::new();
		f.x.copy(y);
        f.nres();
		return f;
	}

    pub fn nres(&mut self) {
        if rom::MODTYPE != rom::PSEUDO_MERSENNE && rom::MODTYPE != rom::GENERALISED_MERSENNE {
   			let p = BIG::new_ints(&rom::MODULUS);
            let mut d=DBIG::new_scopy(&(self.x));
            d.shl(rom::NLEN*(rom::BASEBITS as usize));
            self.x.copy(&d.dmod(&p));
        }
    }

/* convert back to regular form */
    pub fn redc(&mut self) -> BIG {
        if rom::MODTYPE != rom::PSEUDO_MERSENNE && rom::MODTYPE != rom::GENERALISED_MERSENNE {
            let mut d=DBIG::new_scopy(&(self.x));
            return BIG::modulo(&mut d);
        } else {
            let r=BIG::new_copy(&(self.x));
            return r;
        }
    }

   /* convert to string */
	pub fn tostring(&mut self) -> String {
        let s=self.redc().tostring();
        return s;
    }

    pub fn to_hex(&self) -> String {
        self.x.to_hex()
    }

    pub fn from_hex_iter(iter: &mut SplitWhitespace) -> FP {
        FP {
            x: BIG::from_hex_iter(iter)
        }
    }

    pub fn from_hex(val: String) -> FP {
        FP {
            x: BIG::from_hex(val)
        }
    }

/* reduce this mod Modulus */
    pub fn reduce(&mut self) {
  		let p = BIG::new_ints(&rom::MODULUS);
        self.x.rmod(&p)
    }

/* test this=0? */
    pub fn iszilch(&mut self) -> bool {
        self.reduce();
        return self.x.iszilch();
    }

/* copy from FP b */
    pub fn copy(&mut self,b: &FP) {
        self.x.copy(&(b.x));
    }

/* copy from BIG b */
    pub fn bcopy(&mut self,b: &BIG) {
        self.x.copy(&b);
        self.nres();
    }

/* set this=0 */
    pub fn zero(&mut self) {
        self.x.zero();
    }

/* set this=1 */
    pub fn one(&mut self) {
        self.x.one(); self.nres()
    }

/* normalise this */
    pub fn norm(&mut self) {
        self.x.norm();
    }
/* swap FPs depending on d */
    pub fn cswap(&mut self,b: &mut FP,d: isize) {
        self.x.cswap(&mut (b.x),d);
    }

/* copy FPs depending on d */
    pub fn cmove(&mut self,b: &FP,d: isize) {
        self.x.cmove(&(b.x),d);
    }

/* this*=b mod Modulus */
    pub fn mul(&mut self,b: &mut FP)
    {
        self.norm();
        b.norm();
        if BIG::pexceed(&(self.x),&(b.x)) {self.reduce()}

        let mut d=BIG::mul(&(self.x),&(b.x));
        self.x.copy(&BIG::modulo(&mut d))
    }

    fn logb2(w: u32) -> usize {
        let mut v=w;
        v |= v >> 1;
        v |= v >> 2;
        v |= v >> 4;
        v |= v >> 8;
        v |= v >> 16;

        v = v - ((v >> 1) & 0x55555555);
        v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
        let r= ((   ((v + (v >> 4)) & 0xF0F0F0F)   * 0x1010101) >> 24) as usize;
        return r+1;
    }

/* this = -this mod Modulus */
    pub fn neg(&mut self) {
  		let mut p = BIG::new_ints(&rom::MODULUS);

        self.norm();

        let sb=FP::logb2(BIG::excess(&(self.x)) as u32);

    //    let mut ov=BIG::excess(&(self.x));
    //    let mut sb=1; while ov != 0 {sb += 1;ov>>=1}

        p.fshl(sb);
        self.x.rsub(&p);

        if BIG::excess(&(self.x))>=rom::FEXCESS {self.reduce()}
    }

    /* this*=c mod Modulus, where c is a small int */
    pub fn imul(&mut self,c: isize) {
        let mut cc=c;
        self.norm();
        let mut s=false;
        if cc<0 {
            cc = -cc;
            s=true;
        }
        let afx=(BIG::excess(&(self.x))+1)*((cc as Chunk)+1)+1;
        if cc<rom::NEXCESS && afx<rom::FEXCESS {
            self.x.imul(cc);
        } else {
            if afx<rom::FEXCESS {
            	self.x.pmul(cc);
            } else {
  				let p = BIG::new_ints(&rom::MODULUS);
				let mut d=self.x.pxmul(cc);
				self.x.copy(&d.dmod(&p));
            }
        }
        if s {self.neg()}
        self.norm();
    }

/* self*=self mod Modulus */
    pub fn sqr(&mut self) {
        self.norm();
        if BIG::sexceed(&(self.x)) {self.reduce()}

        let mut d=BIG::sqr(&(self.x));
        self.x.copy(&BIG::modulo(&mut d))
    }

/* self+=b */
    pub fn add(&mut self,b: &FP) {
        self.x.add(&(b.x));
        if BIG::excess(&(self.x))+2>=rom::FEXCESS {self.reduce()}
    }

/* self+=self */
    pub fn dbl(&mut self) {
        self.x.dbl();
        if BIG::excess(&(self.x))+2>=rom::FEXCESS {self.reduce()}
    }

/* self-=b */
    pub fn sub(&mut self,b: &FP)
    {
        let mut n=FP::new_copy(b);
        n.neg();
        self.add(&n);
    }

/* self/=2 mod Modulus */
    pub fn div2(&mut self) {
        self.x.norm();
        if self.x.parity()==0 {
        	self.x.fshr(1);
        } else {
  			let p = BIG::new_ints(&rom::MODULUS);
            self.x.add(&p);
            self.x.norm();
            self.x.fshr(1);
        }
    }
/* self=1/self mod Modulus */
    pub fn inverse(&mut self) {
  		let mut p = BIG::new_ints(&rom::MODULUS);
        let mut r=self.redc();
        r.invmodp(&mut p);
        self.x.copy(&r);
        self.nres();
    }

/* return TRUE if self==a */
    pub fn equals(&mut self,a: &mut FP) -> bool {
        a.reduce();
        self.reduce();
        if BIG::comp(&(a.x),(&self.x))==0 {return true}
        return false;
    }

/* return self^e mod Modulus */
    pub fn pow(&mut self,e: &mut BIG) -> FP {
      	let p = BIG::new_ints(&rom::MODULUS);
        let mut r=FP::new_int(1);
        e.norm();
        self.x.norm();
		let mut m=FP::new_copy(self);
        loop {
            let bt=e.parity();
            e.fshr(1);
            if bt==1 {r.mul(&mut m)}
            if e.iszilch() {break}
            m.sqr();
        }
        r.x.rmod(&p);
        return r;
    }

/* return sqrt(this) mod Modulus */
    pub fn sqrt(&mut self) -> FP {
        self.reduce();
      	let mut p = BIG::new_ints(&rom::MODULUS);
        if rom::MOD8==5 {
            p.dec(5); p.norm(); p.shr(3);
            let mut i=FP::new_copy(self); i.x.shl(1);
            let mut v=i.pow(&mut p);
            i.mul(&mut v); i.mul(&mut v);
            i.x.dec(1);
            let mut r=FP::new_copy(self);
            r.mul(&mut v); r.mul(&mut i);
            r.reduce();
            return r;
        }
        else
        {
            p.inc(1); p.norm(); p.shr(2);
            return self.pow(&mut p);
        }
    }
/* return jacobi symbol (this/Modulus) */
    pub fn jacobi(&mut self) -> isize
    {
     	let mut p = BIG::new_ints(&rom::MODULUS);
        let mut w=self.redc();
        return w.jacobi(&mut p);
    }

}
/*
fn main() {
    let p = BIG::new_ints(&rom::MODULUS);
	let mut e = BIG::new_copy(&p);
	e.dec(1);

    let mut x = FP::new_int(3);
    let mut s=x.pow(&mut e);

    println!("s= {}",s.tostring());
}
*/
<commit_msg>fix for fp<commit_after>/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
*/

use std::fmt;
use std::str::SplitWhitespace;

#[derive(Copy, Clone)]
pub struct FP {
 	x:BIG
}

use big::BIG;
use dbig::DBIG;
use rom;
use rom::{Chunk, BIG_HEX_STRING_LEN};

impl fmt::Display for FP {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "FP: [ {} ]", self.x)
    }
}

impl fmt::Debug for FP {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "FP: [ {} ]", self.x)
    }
}

impl PartialEq for FP {
    fn eq(&self, other: &FP) -> bool {
        return self.x == other.x;
    }
}

impl FP {

/* Constructors */
	pub fn new() -> FP {
		FP {
				x: BIG::new()
		}
	}

	pub fn new_int(a:isize) -> FP {
		let mut f=FP::new();
		f.x.inc(a);
		f.nres();
		return f;
	}

	pub fn new_copy(y:&FP) -> FP {
		let mut f=FP::new();
		f.x.copy(&(y.x));
		return f;
	}

	pub fn new_big(y:&BIG) -> FP {
		let mut f=FP::new();
		f.x.copy(y);
        f.nres();
		return f;
	}

    pub fn nres(&mut self) {
        if rom::MODTYPE != rom::PSEUDO_MERSENNE && rom::MODTYPE != rom::GENERALISED_MERSENNE {
   			let p = BIG::new_ints(&rom::MODULUS);
            let mut d=DBIG::new_scopy(&(self.x));
            d.shl(rom::NLEN*(rom::BASEBITS as usize));
            self.x.copy(&d.dmod(&p));
        }
    }

/* convert back to regular form */
    pub fn redc(&mut self) -> BIG {
        if rom::MODTYPE != rom::PSEUDO_MERSENNE && rom::MODTYPE != rom::GENERALISED_MERSENNE {
            let mut d=DBIG::new_scopy(&(self.x));
            return BIG::modulo(&mut d);
        } else {
            let r=BIG::new_copy(&(self.x));
            return r;
        }
    }

   /* convert to string */
	pub fn tostring(&mut self) -> String {
        let s=self.redc().tostring();
        return s;
    }

    pub fn to_hex(&self) -> String {
        let mut ret: String = String::with_capacity(2 * BIG_HEX_STRING_LEN);
        ret.push_str(&format!("{}", self.x.to_hex()));
        return ret;
    }

    pub fn from_hex_iter(iter: &mut SplitWhitespace) -> FP {
        FP {
            x: BIG::from_hex_iter(iter)
        }
    }

    pub fn from_hex(val: String) -> FP {
        let mut iter = val.split_whitespace();
        return FP::from_hex_iter(&mut iter);
    }

/* reduce this mod Modulus */
    pub fn reduce(&mut self) {
  		let p = BIG::new_ints(&rom::MODULUS);
        self.x.rmod(&p)
    }

/* test this=0? */
    pub fn iszilch(&mut self) -> bool {
        self.reduce();
        return self.x.iszilch();
    }

/* copy from FP b */
    pub fn copy(&mut self,b: &FP) {
        self.x.copy(&(b.x));
    }

/* copy from BIG b */
    pub fn bcopy(&mut self,b: &BIG) {
        self.x.copy(&b);
        self.nres();
    }

/* set this=0 */
    pub fn zero(&mut self) {
        self.x.zero();
    }

/* set this=1 */
    pub fn one(&mut self) {
        self.x.one(); self.nres()
    }

/* normalise this */
    pub fn norm(&mut self) {
        self.x.norm();
    }
/* swap FPs depending on d */
    pub fn cswap(&mut self,b: &mut FP,d: isize) {
        self.x.cswap(&mut (b.x),d);
    }

/* copy FPs depending on d */
    pub fn cmove(&mut self,b: &FP,d: isize) {
        self.x.cmove(&(b.x),d);
    }

/* this*=b mod Modulus */
    pub fn mul(&mut self,b: &mut FP)
    {
        self.norm();
        b.norm();
        if BIG::pexceed(&(self.x),&(b.x)) {self.reduce()}

        let mut d=BIG::mul(&(self.x),&(b.x));
        self.x.copy(&BIG::modulo(&mut d))
    }

    fn logb2(w: u32) -> usize {
        let mut v=w;
        v |= v >> 1;
        v |= v >> 2;
        v |= v >> 4;
        v |= v >> 8;
        v |= v >> 16;

        v = v - ((v >> 1) & 0x55555555);
        v = (v & 0x33333333) + ((v >> 2) & 0x33333333);
        let r= ((   ((v + (v >> 4)) & 0xF0F0F0F)   * 0x1010101) >> 24) as usize;
        return r+1;
    }

/* this = -this mod Modulus */
    pub fn neg(&mut self) {
  		let mut p = BIG::new_ints(&rom::MODULUS);

        self.norm();

        let sb=FP::logb2(BIG::excess(&(self.x)) as u32);

    //    let mut ov=BIG::excess(&(self.x));
    //    let mut sb=1; while ov != 0 {sb += 1;ov>>=1}

        p.fshl(sb);
        self.x.rsub(&p);

        if BIG::excess(&(self.x))>=rom::FEXCESS {self.reduce()}
    }

    /* this*=c mod Modulus, where c is a small int */
    pub fn imul(&mut self,c: isize) {
        let mut cc=c;
        self.norm();
        let mut s=false;
        if cc<0 {
            cc = -cc;
            s=true;
        }
        let afx=(BIG::excess(&(self.x))+1)*((cc as Chunk)+1)+1;
        if cc<rom::NEXCESS && afx<rom::FEXCESS {
            self.x.imul(cc);
        } else {
            if afx<rom::FEXCESS {
            	self.x.pmul(cc);
            } else {
  				let p = BIG::new_ints(&rom::MODULUS);
				let mut d=self.x.pxmul(cc);
				self.x.copy(&d.dmod(&p));
            }
        }
        if s {self.neg()}
        self.norm();
    }

/* self*=self mod Modulus */
    pub fn sqr(&mut self) {
        self.norm();
        if BIG::sexceed(&(self.x)) {self.reduce()}

        let mut d=BIG::sqr(&(self.x));
        self.x.copy(&BIG::modulo(&mut d))
    }

/* self+=b */
    pub fn add(&mut self,b: &FP) {
        self.x.add(&(b.x));
        if BIG::excess(&(self.x))+2>=rom::FEXCESS {self.reduce()}
    }

/* self+=self */
    pub fn dbl(&mut self) {
        self.x.dbl();
        if BIG::excess(&(self.x))+2>=rom::FEXCESS {self.reduce()}
    }

/* self-=b */
    pub fn sub(&mut self,b: &FP)
    {
        let mut n=FP::new_copy(b);
        n.neg();
        self.add(&n);
    }

/* self/=2 mod Modulus */
    pub fn div2(&mut self) {
        self.x.norm();
        if self.x.parity()==0 {
        	self.x.fshr(1);
        } else {
  			let p = BIG::new_ints(&rom::MODULUS);
            self.x.add(&p);
            self.x.norm();
            self.x.fshr(1);
        }
    }
/* self=1/self mod Modulus */
    pub fn inverse(&mut self) {
  		let mut p = BIG::new_ints(&rom::MODULUS);
        let mut r=self.redc();
        r.invmodp(&mut p);
        self.x.copy(&r);
        self.nres();
    }

/* return TRUE if self==a */
    pub fn equals(&mut self,a: &mut FP) -> bool {
        a.reduce();
        self.reduce();
        if BIG::comp(&(a.x),(&self.x))==0 {return true}
        return false;
    }

/* return self^e mod Modulus */
    pub fn pow(&mut self,e: &mut BIG) -> FP {
      	let p = BIG::new_ints(&rom::MODULUS);
        let mut r=FP::new_int(1);
        e.norm();
        self.x.norm();
		let mut m=FP::new_copy(self);
        loop {
            let bt=e.parity();
            e.fshr(1);
            if bt==1 {r.mul(&mut m)}
            if e.iszilch() {break}
            m.sqr();
        }
        r.x.rmod(&p);
        return r;
    }

/* return sqrt(this) mod Modulus */
    pub fn sqrt(&mut self) -> FP {
        self.reduce();
      	let mut p = BIG::new_ints(&rom::MODULUS);
        if rom::MOD8==5 {
            p.dec(5); p.norm(); p.shr(3);
            let mut i=FP::new_copy(self); i.x.shl(1);
            let mut v=i.pow(&mut p);
            i.mul(&mut v); i.mul(&mut v);
            i.x.dec(1);
            let mut r=FP::new_copy(self);
            r.mul(&mut v); r.mul(&mut i);
            r.reduce();
            return r;
        }
        else
        {
            p.inc(1); p.norm(); p.shr(2);
            return self.pow(&mut p);
        }
    }
/* return jacobi symbol (this/Modulus) */
    pub fn jacobi(&mut self) -> isize
    {
     	let mut p = BIG::new_ints(&rom::MODULUS);
        let mut w=self.redc();
        return w.jacobi(&mut p);
    }

}
/*
fn main() {
    let p = BIG::new_ints(&rom::MODULUS);
	let mut e = BIG::new_copy(&p);
	e.dec(1);

    let mut x = FP::new_int(3);
    let mut s=x.pow(&mut e);

    println!("s= {}",s.tostring());
}
*/
<|endoftext|>


<commit_before>use super::database::Database;
use super::database::Value;
use super::parser::Parser;

pub enum Response {
    Nil,
    Data(Vec<u8>),
    Err(String),
    Status(String),
}

impl Response {
    pub fn as_bytes(&self) -> Vec<u8> {
        match *self {
            Response::Nil => return b"*-1\r\n".to_vec(),
            Response::Data(ref d) => {
                return b"$".to_vec() + format!("{}\r\n", d.len()).as_bytes() + d + format!("\r\n").as_bytes();
            }
            Response::Err(ref d) => {
                return b"-".to_vec() + (*d).as_bytes() + format!("\r\n").as_bytes();
            }
            Response::Status(ref d) => {
                return b"+".to_vec() + (*d).as_bytes() + format!("\r\n").as_bytes();
            }
        }
    }
}

pub fn set(parser: &Parser, db: &mut Database) -> Response {
    if parser.argc != 3 {
        return Response::Err("Wrong number of parameters".to_string());
    }
    let try_key = parser.get_vec(1);
    if try_key.is_err() {
        return Response::Err("Invalid key".to_string());
    }
    let try_val = parser.get_vec(2);
    if try_val.is_err() {
        return Response::Err("Invalid value".to_string());
    }
    db.set(&try_key.unwrap(), try_val.unwrap());
    return Response::Status("OK".to_string());
}

pub fn append(parser: &Parser, db: &mut Database) -> Response {
    if parser.argc != 3 {
        return Response::Err("Wrong number of parameters".to_string());
    }
    let try_key = parser.get_vec(1);
    if try_key.is_err() {
        return Response::Err("Invalid key".to_string());
    }
    let try_val = parser.get_vec(2);
    if try_val.is_err() {
        return Response::Err("Invalid value".to_string());
    }
    db.append(&try_key.unwrap(), try_val.unwrap());
    return Response::Status("OK".to_string());
}

pub fn get(parser: &Parser, db: &mut Database) -> Response {
    if parser.argc != 2 {
        return Response::Err("Wrong number of parameters".to_string());
    }
    let try_key = parser.get_vec(1);
    if try_key.is_err() {
        return Response::Err("Invalid key".to_string());
    }
    let obj = db.get(&try_key.unwrap());
    match obj {
        Some(value) => {
            match value {
                &Value::Data(ref data) => return Response::Data(data.clone()),
            }
        }
        None => return Response::Nil,
    }
}

pub fn ping(parser: &Parser, db: &mut Database) -> Response {
    #![allow(unused_variables)]
    if parser.argc > 2 {
        return Response::Err("Wrong number of parameters".to_string());
    }
    if parser.argc == 2 {
        return Response::Data(parser.get_vec(1).unwrap());
    }
    return Response::Data(b"PONG".to_vec());
}

pub fn command(parser: &Parser, db: &mut Database) -> Response {
    if parser.argc == 0 {
        return Response::Err("Not enough arguments".to_string());
    }
    let try_command = parser.get_str(0);
    if try_command.is_err() {
        return Response::Err("Invalid command".to_string());
    }
    match try_command.unwrap() {
        "set" => return set(parser, db),
        "append" => return append(parser, db),
        "get" => return get(parser, db),
        "ping" => return ping(parser, db),
        _ => return Response::Err("Uknown command".to_string()),
    };
}
<commit_msg>Use macros to avoid duplicated code<commit_after>use super::database::Database;
use super::database::Value;
use super::parser::Parser;

pub enum Response {
    Nil,
    Data(Vec<u8>),
    Err(String),
    Status(String),
}

impl Response {
    pub fn as_bytes(&self) -> Vec<u8> {
        match *self {
            Response::Nil => return b"*-1\r\n".to_vec(),
            Response::Data(ref d) => {
                return b"$".to_vec() + format!("{}\r\n", d.len()).as_bytes() + d + format!("\r\n").as_bytes();
            }
            Response::Err(ref d) => {
                return b"-".to_vec() + (*d).as_bytes() + format!("\r\n").as_bytes();
            }
            Response::Status(ref d) => {
                return b"+".to_vec() + (*d).as_bytes() + format!("\r\n").as_bytes();
            }
        }
    }
}

macro_rules! validate {
    ($expr: expr, $err: expr) => (
        if !($expr) {
            return Response::Err($err.to_string());
        }
    )
}

macro_rules! try_validate {
    ($expr: expr, $err: expr) => ({
        let res = $expr;
        validate!(res.is_ok(), $err);
        res.unwrap()
    })
}

pub fn set(parser: &Parser, db: &mut Database) -> Response {
    validate!(parser.argc == 3, "Wrong number of parameters");
    let key = try_validate!(parser.get_vec(1), "Invalid key");
    let val = try_validate!(parser.get_vec(2), "Invalid value");
    db.set(&key, val);
    return Response::Status("OK".to_string());
}

pub fn append(parser: &Parser, db: &mut Database) -> Response {
    validate!(parser.argc == 3, "Wrong number of parameters");
    let key = try_validate!(parser.get_vec(1), "Invalid key");
    let val = try_validate!(parser.get_vec(2), "Invalid value");
    db.append(&key, val);
    return Response::Status("OK".to_string());
}

pub fn get(parser: &Parser, db: &mut Database) -> Response {
    validate!(parser.argc == 2, "Wrong number of parameters");
    let key = try_validate!(parser.get_vec(1), "Invalid key");
    let obj = db.get(&key);
    match obj {
        Some(value) => {
            match value {
                &Value::Data(ref data) => return Response::Data(data.clone()),
            }
        }
        None => return Response::Nil,
    }
}

pub fn ping(parser: &Parser, db: &mut Database) -> Response {
    #![allow(unused_variables)]
    validate!(parser.argc <= 2, "Wrong number of parameters");
    if parser.argc == 2 {
        return Response::Data(parser.get_vec(1).unwrap());
    }
    return Response::Data(b"PONG".to_vec());
}

pub fn command(parser: &Parser, db: &mut Database) -> Response {
    if parser.argc == 0 {
        return Response::Err("Not enough arguments".to_string());
    }
    let try_command = parser.get_str(0);
    if try_command.is_err() {
        return Response::Err("Invalid command".to_string());
    }
    match try_command.unwrap() {
        "set" => return set(parser, db),
        "append" => return append(parser, db),
        "get" => return get(parser, db),
        "ping" => return ping(parser, db),
        _ => return Response::Err("Uknown command".to_string()),
    };
}
<|endoftext|>


<commit_before>//! This module contains an abstraction for HTTP clients as well as friendly-named re-exports of
//! client types that implement this trait.

use std::{future::Future, pin::Pin};

use async_trait::async_trait;
use bytes::BufMut;
use ruma_api::{OutgoingRequest, SendAccessToken};
use ruma_identifiers::UserId;

use crate::{add_user_id_to_query, ResponseError, ResponseResult};

#[cfg(feature = "hyper")]
mod hyper;
#[cfg(feature = "reqwest")]
mod reqwest;

#[cfg(feature = "hyper")]
pub use self::hyper::Hyper;
#[cfg(feature = "hyper-native-tls")]
pub use self::hyper::HyperNativeTls;
#[cfg(feature = "hyper-rustls")]
pub use self::hyper::HyperRustls;
#[cfg(feature = "reqwest")]
pub use self::reqwest::Reqwest;

/// An HTTP client that can be used to send requests to a Matrix homeserver.
#[async_trait]
pub trait HttpClient: Sync {
    /// The type to use for `try_into_http_request`.
    type RequestBody: Default + BufMut + Send;

    /// The type to use for `try_from_http_response`.
    type ResponseBody: AsRef<[u8]>;

    /// The error type for the `send_request` function.
    type Error: Send + Unpin;

    /// Send an `http::Request` to get back an `http::Response`.
    async fn send_http_request(
        &self,
        req: http::Request<Self::RequestBody>,
    ) -> Result<http::Response<Self::ResponseBody>, Self::Error>;
}

/// An HTTP client that has a default configuration.
pub trait DefaultConstructibleHttpClient: HttpClient {
    /// Creates a new HTTP client with default configuration.
    fn default() -> Self;
}

/// Convenience functionality on top of `HttpClient`.
///
/// If you want to build your own matrix client type instead of using `ruma_client::Client`, this
/// trait should make that relatively easy.
pub trait HttpClientExt: HttpClient {
    /// Send a strongly-typed matrix request to get back a strongly-typed response.
    // TODO: `R: 'a` bound should not be needed
    fn send_request<'a, R: OutgoingRequest + 'a>(
        &'a self,
        homeserver_url: &str,
        access_token: SendAccessToken<'_>,
        request: R,
    ) -> Pin<Box<dyn Future<Output = ResponseResult<Self, R>> + 'a>> {
        self.send_customized_request(homeserver_url, access_token, request, |_| Ok(()))
    }

    /// Turn a strongly-typed matrix request into an `http::Request`, customize it and send it to
    /// get back a strongly-typed response.
    // TODO: `R: 'a` and `F: 'a` should not be needed
    fn send_customized_request<'a, R, F>(
        &'a self,
        homeserver_url: &str,
        access_token: SendAccessToken<'_>,
        request: R,
        customize: F,
    ) -> Pin<Box<dyn Future<Output = ResponseResult<Self, R>> + 'a>>
    where
        R: OutgoingRequest + 'a,
        F: FnOnce(&mut http::Request<Self::RequestBody>) -> Result<(), ResponseError<Self, R>> + 'a,
    {
        Box::pin(crate::send_customized_request(
            self,
            homeserver_url,
            access_token,
            request,
            customize,
        ))
    }

    /// Turn a strongly-typed matrix request into an `http::Request`, add a `user_id` query
    /// parameter to it and send it to get back a strongly-typed response.
    ///
    /// This method is meant to be used by application services when interacting with the
    /// client-server API.
    fn send_request_as<'a, R: OutgoingRequest + 'a>(
        &'a self,
        homeserver_url: &str,
        access_token: SendAccessToken<'_>,
        user_id: &'a UserId,
        request: R,
    ) -> Pin<Box<dyn Future<Output = ResponseResult<Self, R>> + 'a>> {
        self.send_customized_request(
            homeserver_url,
            access_token,
            request,
            add_user_id_to_query::<Self, R>(user_id),
        )
    }
}

#[async_trait]
impl<T: HttpClient> HttpClientExt for T {}

#[doc(hidden)]
#[derive(Debug)]
pub struct Dummy;

#[async_trait]
impl HttpClient for Dummy {
    type RequestBody = Vec<u8>;
    type ResponseBody = Vec<u8>;
    type Error = ();

    async fn send_http_request(
        &self,
        _req: http::Request<Self::RequestBody>,
    ) -> Result<http::Response<Self::ResponseBody>, Self::Error> {
        unimplemented!("this client only exists to allow doctests to compile")
    }
}

impl DefaultConstructibleHttpClient for Dummy {
    fn default() -> Self {
        Dummy
    }
}
<commit_msg>client: Rename HttpClientExt methods to be much less likely to conflict with inherent methods<commit_after>//! This module contains an abstraction for HTTP clients as well as friendly-named re-exports of
//! client types that implement this trait.

use std::{future::Future, pin::Pin};

use async_trait::async_trait;
use bytes::BufMut;
use ruma_api::{OutgoingRequest, SendAccessToken};
use ruma_identifiers::UserId;

use crate::{add_user_id_to_query, ResponseError, ResponseResult};

#[cfg(feature = "hyper")]
mod hyper;
#[cfg(feature = "reqwest")]
mod reqwest;

#[cfg(feature = "hyper")]
pub use self::hyper::Hyper;
#[cfg(feature = "hyper-native-tls")]
pub use self::hyper::HyperNativeTls;
#[cfg(feature = "hyper-rustls")]
pub use self::hyper::HyperRustls;
#[cfg(feature = "reqwest")]
pub use self::reqwest::Reqwest;

/// An HTTP client that can be used to send requests to a Matrix homeserver.
#[async_trait]
pub trait HttpClient: Sync {
    /// The type to use for `try_into_http_request`.
    type RequestBody: Default + BufMut + Send;

    /// The type to use for `try_from_http_response`.
    type ResponseBody: AsRef<[u8]>;

    /// The error type for the `send_request` function.
    type Error: Send + Unpin;

    /// Send an `http::Request` to get back an `http::Response`.
    async fn send_http_request(
        &self,
        req: http::Request<Self::RequestBody>,
    ) -> Result<http::Response<Self::ResponseBody>, Self::Error>;
}

/// An HTTP client that has a default configuration.
pub trait DefaultConstructibleHttpClient: HttpClient {
    /// Creates a new HTTP client with default configuration.
    fn default() -> Self;
}

/// Convenience functionality on top of `HttpClient`.
///
/// If you want to build your own matrix client type instead of using `ruma_client::Client`, this
/// trait should make that relatively easy.
pub trait HttpClientExt: HttpClient {
    /// Send a strongly-typed matrix request to get back a strongly-typed response.
    // TODO: `R: 'a` bound should not be needed
    fn send_matrix_request<'a, R: OutgoingRequest + 'a>(
        &'a self,
        homeserver_url: &str,
        access_token: SendAccessToken<'_>,
        request: R,
    ) -> Pin<Box<dyn Future<Output = ResponseResult<Self, R>> + 'a>> {
        self.send_customized_matrix_request(homeserver_url, access_token, request, |_| Ok(()))
    }

    /// Turn a strongly-typed matrix request into an `http::Request`, customize it and send it to
    /// get back a strongly-typed response.
    // TODO: `R: 'a` and `F: 'a` should not be needed
    fn send_customized_matrix_request<'a, R, F>(
        &'a self,
        homeserver_url: &str,
        access_token: SendAccessToken<'_>,
        request: R,
        customize: F,
    ) -> Pin<Box<dyn Future<Output = ResponseResult<Self, R>> + 'a>>
    where
        R: OutgoingRequest + 'a,
        F: FnOnce(&mut http::Request<Self::RequestBody>) -> Result<(), ResponseError<Self, R>> + 'a,
    {
        Box::pin(crate::send_customized_request(
            self,
            homeserver_url,
            access_token,
            request,
            customize,
        ))
    }

    /// Turn a strongly-typed matrix request into an `http::Request`, add a `user_id` query
    /// parameter to it and send it to get back a strongly-typed response.
    ///
    /// This method is meant to be used by application services when interacting with the
    /// client-server API.
    fn send_matrix_request_as<'a, R: OutgoingRequest + 'a>(
        &'a self,
        homeserver_url: &str,
        access_token: SendAccessToken<'_>,
        user_id: &'a UserId,
        request: R,
    ) -> Pin<Box<dyn Future<Output = ResponseResult<Self, R>> + 'a>> {
        self.send_customized_matrix_request(
            homeserver_url,
            access_token,
            request,
            add_user_id_to_query::<Self, R>(user_id),
        )
    }
}

#[async_trait]
impl<T: HttpClient> HttpClientExt for T {}

#[doc(hidden)]
#[derive(Debug)]
pub struct Dummy;

#[async_trait]
impl HttpClient for Dummy {
    type RequestBody = Vec<u8>;
    type ResponseBody = Vec<u8>;
    type Error = ();

    async fn send_http_request(
        &self,
        _req: http::Request<Self::RequestBody>,
    ) -> Result<http::Response<Self::ResponseBody>, Self::Error> {
        unimplemented!("this client only exists to allow doctests to compile")
    }
}

impl DefaultConstructibleHttpClient for Dummy {
    fn default() -> Self {
        Dummy
    }
}
<|endoftext|>


<commit_before>#![allow(unused)]
use cairo;
use gio;
use glib;

use librsvg::{CairoRenderer, Loader, LoadingError, RenderingError, SvgHandle};

use rsvg_internals::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};

use rsvg_internals::{compare_surfaces, BufferDiff};

use std::env;
use std::fs::{self, File};
use std::io::BufReader;
use std::path::PathBuf;

pub fn load_svg(input: &'static [u8]) -> Result<SvgHandle, LoadingError> {
    let bytes = glib::Bytes::from_static(input);
    let stream = gio::MemoryInputStream::new_from_bytes(&bytes);

    Loader::new().read_stream(&stream, None::<&gio::File>, None::<&gio::Cancellable>)
}

#[derive(Copy, Clone)]
pub struct SurfaceSize(pub i32, pub i32);

pub fn render_document<F: FnOnce(&cairo::Context)>(
    svg: &SvgHandle,
    surface_size: SurfaceSize,
    cr_transform: F,
    viewport: cairo::Rectangle,
) -> Result<SharedImageSurface, RenderingError> {
    let renderer = CairoRenderer::new(svg);

    let SurfaceSize(width, height) = surface_size;

    let output = cairo::ImageSurface::create(cairo::Format::ARgb32, width, height).unwrap();

    let res = {
        let cr = cairo::Context::new(&output);
        cr_transform(&cr);
        Ok(renderer.render_document(&cr, &viewport)?)
    };

    res.and_then(|_| Ok(SharedImageSurface::wrap(output, SurfaceType::SRgb)?))
}

pub fn output_dir() -> PathBuf {
    let path = PathBuf::from(
        env::var_os("OUT_DIR")
            .expect(r#"OUT_DIR is not set, please set it or run under "cargo test""#),
    );

    fs::create_dir_all(&path).expect("could not create output directory for tests");

    println!("outputting to {}", path.to_string_lossy());

    path
}

pub fn fixture_dir() -> PathBuf {
    let path = PathBuf::from(
        env::var_os("CARGO_MANIFEST_DIR")
            .expect(r#"CARGO_MANIFEST_DIR" is not set, please set it or run under "cargo test""#),
    )
    .join("tests")
    .join("fixtures");

    println!("looking for fixtures at {}", path.to_string_lossy());

    path
}

pub fn compare_to_file(
    output_surf: &SharedImageSurface,
    output_base_name: &str,
    fixture_filename: &str,
) {
    let output_path = output_dir().join(&format!("{}-out.png", output_base_name));
    let fixture_path = fixture_dir().join(fixture_filename);

    let mut output_file = File::create(output_path).unwrap();
    output_surf
        .clone()
        .into_image_surface()
        .unwrap()
        .write_to_png(&mut output_file)
        .unwrap();

    let file =
        File::open(fixture_path).expect("cannot find {} - are you in the librsvg_crate directory?");

    let mut fixture_file = BufReader::new(file);

    let expected = cairo::ImageSurface::create_from_png(&mut fixture_file).unwrap();
    let expected_surf = SharedImageSurface::wrap(expected, SurfaceType::SRgb).unwrap();

    let diff = compare_surfaces(output_surf, &expected_surf).unwrap();

    match diff {
        BufferDiff::DifferentSizes => unreachable!("surfaces should be of the same size"),

        BufferDiff::Diff(diff) => {
            let surf = diff.surface.into_image_surface().unwrap();
            let diff_path = output_dir().join(&format!("{}-diff.png", output_base_name));
            let mut output_file = File::create(diff_path).unwrap();
            surf.write_to_png(&mut output_file).unwrap();

            assert_eq!(diff.num_pixels_changed, 0);
        }
    }
}

const MAX_DIFF: u8 = 2;

pub fn compare_to_surface(
    output_surf: &SharedImageSurface,
    reference_surf: &SharedImageSurface,
    output_base_name: &str,
) {
    let output_path = output_dir().join(&format!("{}-out.png", output_base_name));

    let mut output_file = File::create(output_path).unwrap();
    output_surf
        .clone()
        .into_image_surface()
        .unwrap()
        .write_to_png(&mut output_file)
        .unwrap();

    let diff = compare_surfaces(output_surf, reference_surf).unwrap();

    match diff {
        BufferDiff::DifferentSizes => unreachable!("surfaces should be of the same size"),

        BufferDiff::Diff(diff) => {
            let surf = diff.surface.into_image_surface().unwrap();
            let diff_path = output_dir().join(&format!("{}-diff.png", output_base_name));
            let mut output_file = File::create(diff_path).unwrap();
            surf.write_to_png(&mut output_file).unwrap();

            if diff.num_pixels_changed != 0 && diff.max_diff > MAX_DIFF {
                println!(
                    "{}: {} pixels changed with maximum difference of {}",
                    output_base_name, diff.num_pixels_changed, diff.max_diff,
                );
                unreachable!("surfaces are too different");
            }
        }
    }
}
<commit_msg>Reduce amount of duplicated code in compare_to_file and compare_to_surface<commit_after>#![allow(unused)]
use cairo;
use gio;
use glib;

use librsvg::{CairoRenderer, Loader, LoadingError, RenderingError, SvgHandle};

use rsvg_internals::surface_utils::shared_surface::{SharedImageSurface, SurfaceType};

use rsvg_internals::{compare_surfaces, BufferDiff};

use std::env;
use std::fs::{self, File};
use std::io::BufReader;
use std::path::PathBuf;

pub fn load_svg(input: &'static [u8]) -> Result<SvgHandle, LoadingError> {
    let bytes = glib::Bytes::from_static(input);
    let stream = gio::MemoryInputStream::new_from_bytes(&bytes);

    Loader::new().read_stream(&stream, None::<&gio::File>, None::<&gio::Cancellable>)
}

#[derive(Copy, Clone)]
pub struct SurfaceSize(pub i32, pub i32);

pub fn render_document<F: FnOnce(&cairo::Context)>(
    svg: &SvgHandle,
    surface_size: SurfaceSize,
    cr_transform: F,
    viewport: cairo::Rectangle,
) -> Result<SharedImageSurface, RenderingError> {
    let renderer = CairoRenderer::new(svg);

    let SurfaceSize(width, height) = surface_size;

    let output = cairo::ImageSurface::create(cairo::Format::ARgb32, width, height).unwrap();

    let res = {
        let cr = cairo::Context::new(&output);
        cr_transform(&cr);
        Ok(renderer.render_document(&cr, &viewport)?)
    };

    res.and_then(|_| Ok(SharedImageSurface::wrap(output, SurfaceType::SRgb)?))
}

pub fn output_dir() -> PathBuf {
    let path = PathBuf::from(
        env::var_os("OUT_DIR")
            .expect(r#"OUT_DIR is not set, please set it or run under "cargo test""#),
    );

    fs::create_dir_all(&path).expect("could not create output directory for tests");

    println!("outputting to {}", path.to_string_lossy());

    path
}

pub fn fixture_dir() -> PathBuf {
    let path = PathBuf::from(
        env::var_os("CARGO_MANIFEST_DIR")
            .expect(r#"CARGO_MANIFEST_DIR" is not set, please set it or run under "cargo test""#),
    )
    .join("tests")
    .join("fixtures");

    println!("looking for fixtures at {}", path.to_string_lossy());

    path
}

pub fn compare_to_file(
    output_surf: &SharedImageSurface,
    output_base_name: &str,
    reference_filename: &str,
) {
    let output_path = output_dir().join(&format!("{}-out.png", output_base_name));
    let reference_path = fixture_dir().join(reference_filename);

    let mut output_file = File::create(output_path).unwrap();
    output_surf
        .clone()
        .into_image_surface()
        .unwrap()
        .write_to_png(&mut output_file)
        .unwrap();

    let file =
        File::open(reference_path).expect("cannot find {} - are you in the librsvg_crate directory?");

    let mut reference_file = BufReader::new(file);

    let reference = cairo::ImageSurface::create_from_png(&mut reference_file).unwrap();
    let reference_surf = SharedImageSurface::wrap(reference, SurfaceType::SRgb).unwrap();

    let diff = compare_surfaces(output_surf, &reference_surf).unwrap();
    evaluate_diff(&diff, output_base_name);
}

pub fn compare_to_surface(
    output_surf: &SharedImageSurface,
    reference_surf: &SharedImageSurface,
    output_base_name: &str,
) {
    let output_path = output_dir().join(&format!("{}-out.png", output_base_name));

    let mut output_file = File::create(output_path).unwrap();
    output_surf
        .clone()
        .into_image_surface()
        .unwrap()
        .write_to_png(&mut output_file)
        .unwrap();

    let diff = compare_surfaces(output_surf, reference_surf).unwrap();
    evaluate_diff(&diff, output_base_name);
}

const MAX_DIFF: u8 = 2;

fn evaluate_diff(diff: &BufferDiff, output_base_name: &str) {
    match diff {
        BufferDiff::DifferentSizes => unreachable!("surfaces should be of the same size"),

        BufferDiff::Diff(diff) => {
            let surf = diff.surface.clone().into_image_surface().unwrap();
            let diff_path = output_dir().join(&format!("{}-diff.png", output_base_name));
            let mut output_file = File::create(diff_path).unwrap();
            surf.write_to_png(&mut output_file).unwrap();

            if diff.num_pixels_changed != 0 && diff.max_diff > MAX_DIFF {
                println!(
                    "{}: {} pixels changed with maximum difference of {}",
                    output_base_name, diff.num_pixels_changed, diff.max_diff,
                );
                panic!("surfaces are too different");
            }
        }
    }
}
<|endoftext|>