<commit_before>use self::ChainState::{Buffered, Linked};
use crate::Chain;
use std::error::Error as StdError;
use std::vec;

#[derive(Clone)]
pub(crate) enum ChainState<'a> {
    Linked {
        next: Option<&'a (dyn StdError + 'static)>,
    },
    Buffered {
        rest: vec::IntoIter<&'a (dyn StdError + 'static)>,
    },
}

impl<'a> Chain<'a> {
    pub fn new(head: &'a (dyn StdError + 'static)) -> Self {
        Chain {
            state: ChainState::Linked { next: Some(head) },
        }
    }
}

impl<'a> Iterator for Chain<'a> {
    type Item = &'a (dyn StdError + 'static);

    fn next(&mut self) -> Option<Self::Item> {
        match &mut self.state {
            Linked { next } => {
                let error = (*next)?;
                *next = error.source();
                Some(error)
            }
            Buffered { rest } => rest.next(),
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len();
        (len, Some(len))
    }
}

impl DoubleEndedIterator for Chain<'_> {
    fn next_back(&mut self) -> Option<Self::Item> {
        match &mut self.state {
            Linked { mut next } => {
                let mut rest = Vec::new();
                while let Some(cause) = next {
                    next = cause.source();
                    rest.push(cause);
                }
                let mut rest = rest.into_iter();
                let last = rest.next_back();
                self.state = Buffered { rest };
                last
            }
            Buffered { rest } => rest.next_back(),
        }
    }
}

impl ExactSizeIterator for Chain<'_> {
    fn len(&self) -> usize {
        match &self.state {
            Linked { mut next } => {
                let mut len = 0;
                while let Some(cause) = next {
                    next = cause.source();
                    len += 1;
                }
                len
            }
            Buffered { rest } => rest.len(),
        }
    }
}
<commit_msg>Implement Default for Chain to be an empty chain<commit_after>use self::ChainState::{Buffered, Linked};
use crate::Chain;
use std::error::Error as StdError;
use std::vec;

#[derive(Clone)]
pub(crate) enum ChainState<'a> {
    Linked {
        next: Option<&'a (dyn StdError + 'static)>,
    },
    Buffered {
        rest: vec::IntoIter<&'a (dyn StdError + 'static)>,
    },
}

impl<'a> Chain<'a> {
    pub fn new(head: &'a (dyn StdError + 'static)) -> Self {
        Chain {
            state: ChainState::Linked { next: Some(head) },
        }
    }
}

impl<'a> Iterator for Chain<'a> {
    type Item = &'a (dyn StdError + 'static);

    fn next(&mut self) -> Option<Self::Item> {
        match &mut self.state {
            Linked { next } => {
                let error = (*next)?;
                *next = error.source();
                Some(error)
            }
            Buffered { rest } => rest.next(),
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len();
        (len, Some(len))
    }
}

impl DoubleEndedIterator for Chain<'_> {
    fn next_back(&mut self) -> Option<Self::Item> {
        match &mut self.state {
            Linked { mut next } => {
                let mut rest = Vec::new();
                while let Some(cause) = next {
                    next = cause.source();
                    rest.push(cause);
                }
                let mut rest = rest.into_iter();
                let last = rest.next_back();
                self.state = Buffered { rest };
                last
            }
            Buffered { rest } => rest.next_back(),
        }
    }
}

impl ExactSizeIterator for Chain<'_> {
    fn len(&self) -> usize {
        match &self.state {
            Linked { mut next } => {
                let mut len = 0;
                while let Some(cause) = next {
                    next = cause.source();
                    len += 1;
                }
                len
            }
            Buffered { rest } => rest.len(),
        }
    }
}

impl Default for Chain<'_> {
    fn default() -> Self {
        Chain {
            state: ChainState::Buffered {
                rest: Vec::new().into_iter(),
            },
        }
    }
}
<|endoftext|>


<commit_before>
use utils::clampf32;
use std::default::Default;
use std::fmt::{Show, Formatter, FormatError};
use std::num::abs;
use std::rand::random;
use std::ascii::OwnedAsciiExt;
use serialize::hex::ToHex;
use serialize::{Decodable, Decoder, DecoderHelpers};

/// A basic color struct for general color use
/// made of red, green, blue and alpha elements.
pub struct Color(pub [f32, ..4]);

impl Color {

    /// Basic constructor for a Color struct.
    pub fn new(r: f32, g: f32, b: f32, a: f32) -> Color {
        Color([r, g, b, a])
    }

    /// Returns the red component of the color.
    #[inline(always)]
    pub fn r(&self) -> f32 {
        let &Color(c) = self;
        c[0]
    }

    /// Returns the green component of the color.
    #[inline(always)]
    pub fn g(&self) -> f32 {
        let &Color(c) = self;
        c[1]
    }

    /// Returns the blue component of the color.
    #[inline(always)]
    pub fn b(&self) -> f32 {
        let &Color(c) = self;
        c[2]
    }

    /// Sets the red component of the color.
    #[inline(always)]
    pub fn set_r(&mut self, r: f32) {
        let &Color(ref mut c) = self;
        c[0] = r;
    }

    /// Sets the green component of the color.
    #[inline(always)]
    pub fn set_g(&mut self, g: f32) {
        let &Color(ref mut c) = self;
        c[1] = g;
    }

    /// Sets the blue component of the color.
    #[inline(always)]
    pub fn set_b(&mut self, b: f32) {
        let &Color(ref mut c) = self;
        c[2] = b;
    }

    /// Sets the alpha component of the color.
    #[inline(always)]
    pub fn set_a(&mut self, a: f32) {
        let &Color(ref mut c) = self;
        c[3] = a;
    }

    /// Returns the alpha component of the color.
    #[inline(always)]
    pub fn a(&self) -> f32 {
        let &Color(c) = self;
        c[3]
    }

    /// Basic constructor for a Black Color struct.
    pub fn black() -> Color {
        Color([0f32, 0f32, 0f32, 1f32])
    }

    /// Basic constructor for a White Color struct.
    pub fn white() -> Color {
        Color([1f32, 1f32, 1f32, 1f32])
    }

    /// Return color as a vector.
    pub fn as_vec(&self) -> Vec<f32> {
        vec![self.r(), self.g(), self.b(), self.a()]
    }

    /// Return color as a tuple.
    pub fn as_tuple(&self) -> (f32, f32, f32, f32) {
        let &Color(c) = self;
        (c[0], c[1], c[2], c[3])
    }

    /// Clamp the Color's values between 0f32 and 1f32.
    fn clamp(c: Color) -> Color {
        Color([
            clampf32(c.r()),
            clampf32(c.g()),
            clampf32(c.b()),
            clampf32(c.a())
        ])
    }

    /// Return a highlighted version of the current Color.
    pub fn highlighted(&self) -> Color {
        let luminance = self.luminance();
        let (r, g, b) = {
            if luminance > 0.8 {
                (self.r() - 0.2,
                 self.g() - 0.2,
                 self.b() - 0.2)
            }
            else if luminance < 0.2 {
                (self.r() + 0.2,
                 self.g() + 0.2,
                 self.b() + 0.2)
            }
            else {
                (clampf32((1f32 - self.r()) * 0.5f32 * self.r() + self.r()),
                 clampf32((1f32 - self.g()) * 0.1f32 * self.g() + self.g()),
                 clampf32((1f32 - self.b()) * 0.1f32 * self.b() + self.b()))
            }
        };
        let a = clampf32((1f32 - self.a()) * 0.5f32 + self.a());
        Color::new(r, g, b, a)
    }

    /// Return a clicked version of the current Color.
    pub fn clicked(&self) -> Color {
        let luminance = self.luminance();
        let (r, g, b) = {
            if luminance > 0.8 {
                (self.r(),
                 self.g() - 0.2,
                 self.b() - 0.2)
            }
            else if luminance < 0.2 {
                (self.r() + 0.4,
                 self.g() + 0.2,
                 self.b() + 0.2)
            }
            else {
                (clampf32((1f32 - self.r()) * 0.75f32 + self.r()),
                 clampf32((1f32 - self.g()) * 0.25f32 + self.g()),
                 clampf32((1f32 - self.b()) * 0.25f32 + self.b()))
            }
        };
        let a = clampf32((1f32 - self.a()) * 0.75f32 + self.a());
        Color::new(r, g, b, a)
    }

    /// Return a random color.
    pub fn random() -> Color {
        let r = random::<f32>();
        let g = random::<f32>();
        let b = random::<f32>();
        let a = 1f32;
        Color::new(r, g, b, a)
    }

    /// Return an inverted version of the color.
    pub fn invert(&self) -> Color {
        let r = abs(1f32 - self.r());
        let g = abs(1f32 - self.g());
        let b = abs(1f32 - self.b());
        Color::new(r, g, b, self.a())
    }

    /// Return either black or white, depending which contrasts
    /// the Color the most. This will be useful for determining
    /// a readable color for text on any given background Color.
    pub fn plain_contrast(&self) -> Color {
        if self.luminance() > 0.5f32 { Color::black() }
        else { Color::white() }
    }

    /// Return the luminance of the color.
    pub fn luminance(&self) -> f32 {
        (self.r() + self.g() + self.b()) / 3f32
    }

    /// Return an array of the channels in this color
    /// clamped to [0..255]
    pub fn to_32_bit(&self) -> [u8, ..4] {
        [
            to_8_bit(self.r()),
            to_8_bit(self.g()),
            to_8_bit(self.b()),
            to_8_bit(self.a()),
        ]
    }

    /// Return the hex representation of this color
    /// in the format #RRGGBBAA
    /// e.g. `Color(1.0, 0.0, 5.0, 1.0) == "#FF0080FF"`
    pub fn to_hex(&self) -> String {
        let vals = self.to_32_bit();
        // Hex colors are always uppercased
        let hex = vals.as_slice().to_hex().into_ascii_upper();
        format!("#{}", hex.as_slice())
    }
}

fn to_8_bit(chan: f32) -> u8 {
    let chan = clampf32(chan);
    (chan * 255.0) as u8
}

impl Clone for Color {
    fn clone(&self) -> Color {
        *self
    }
}

impl Default for Color {
    /// Default constructor for a Color struct.
    fn default() -> Color {
        Color([0.5, 0.8, 0.6, 1.0])
    }
}

impl Add<Color, Color> for Color {
    fn add(&self, rhs: &Color) -> Color {
        Color::clamp(
            Color([
                self.r() + rhs.r(),
                self.g() + rhs.g(),
                self.b() + rhs.b(),
                self.a()
            ])
        )
    }
}

impl Sub<Color, Color> for Color {
    fn sub(&self, rhs: &Color) -> Color {
        Color::clamp(
            Color([
                self.r() - rhs.r(),
                self.g() - rhs.g(),
                self.b() - rhs.b(),
                self.a()
            ])
        )
    }
}

impl Div<Color, Color> for Color {
    fn div(&self, rhs: &Color) -> Color {
        Color::clamp(
            Color([
                self.r() / rhs.r(),
                self.g() / rhs.g(),
                self.b() / rhs.b(),
                self.a() / rhs.a(),
            ])
        )
    }
}

impl Mul<Color, Color> for Color {
    fn mul(&self, rhs: &Color) -> Color {
        Color::clamp(
            Color([
                self.r() * rhs.r(),
                self.g() * rhs.g(),
                self.b() * rhs.b(),
                self.a() * rhs.a(),
            ])
        )
    }
}

impl Show for Color {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FormatError> {
        let hex = self.to_hex();
        fmt.pad(hex.as_slice())
    }
}

impl<E, D: Decoder<E>> Decodable<E, D> for Color {
    fn decode(dec: &mut D) -> Result<Color, E> {
        let vec = try!(dec.read_to_vec(|le_dec| le_dec.read_f32()));

        if vec.len() != 4 {
            return dec.err(format!(
                "Expected a 4 element vector when decoding Color.
                Found a vector of length {}.", vec.len()));
        }

        Ok(Color([vec[0], vec[1], vec[2], vec[3]]))
    }
}
<commit_msg>Implement Encodable for Color. Closes #58.<commit_after>
use utils::clampf32;
use std::default::Default;
use std::fmt::{Show, Formatter, FormatError};
use std::num::abs;
use std::rand::random;
use std::ascii::OwnedAsciiExt;
use serialize::hex::ToHex;
// I consulted the style guide, but there was nothing about multi-line imports.
// This should be readable.
use serialize::{
    Decodable, Encodable,
    Decoder, Encoder,
    DecoderHelpers, EncoderHelpers
};

/// A basic color struct for general color use
/// made of red, green, blue and alpha elements.
pub struct Color(pub [f32, ..4]);

impl Color {

    /// Basic constructor for a Color struct.
    pub fn new(r: f32, g: f32, b: f32, a: f32) -> Color {
        Color([r, g, b, a])
    }

    /// Returns the red component of the color.
    #[inline(always)]
    pub fn r(&self) -> f32 {
        let &Color(c) = self;
        c[0]
    }

    /// Returns the green component of the color.
    #[inline(always)]
    pub fn g(&self) -> f32 {
        let &Color(c) = self;
        c[1]
    }

    /// Returns the blue component of the color.
    #[inline(always)]
    pub fn b(&self) -> f32 {
        let &Color(c) = self;
        c[2]
    }

    /// Sets the red component of the color.
    #[inline(always)]
    pub fn set_r(&mut self, r: f32) {
        let &Color(ref mut c) = self;
        c[0] = r;
    }

    /// Sets the green component of the color.
    #[inline(always)]
    pub fn set_g(&mut self, g: f32) {
        let &Color(ref mut c) = self;
        c[1] = g;
    }

    /// Sets the blue component of the color.
    #[inline(always)]
    pub fn set_b(&mut self, b: f32) {
        let &Color(ref mut c) = self;
        c[2] = b;
    }

    /// Sets the alpha component of the color.
    #[inline(always)]
    pub fn set_a(&mut self, a: f32) {
        let &Color(ref mut c) = self;
        c[3] = a;
    }

    /// Returns the alpha component of the color.
    #[inline(always)]
    pub fn a(&self) -> f32 {
        let &Color(c) = self;
        c[3]
    }

    /// Basic constructor for a Black Color struct.
    pub fn black() -> Color {
        Color([0f32, 0f32, 0f32, 1f32])
    }

    /// Basic constructor for a White Color struct.
    pub fn white() -> Color {
        Color([1f32, 1f32, 1f32, 1f32])
    }

    /// Return color as a vector.
    pub fn as_vec(&self) -> Vec<f32> {
        vec![self.r(), self.g(), self.b(), self.a()]
    }

    /// Return color as a tuple.
    pub fn as_tuple(&self) -> (f32, f32, f32, f32) {
        let &Color(c) = self;
        (c[0], c[1], c[2], c[3])
    }

    /// Clamp the Color's values between 0f32 and 1f32.
    fn clamp(c: Color) -> Color {
        Color([
            clampf32(c.r()),
            clampf32(c.g()),
            clampf32(c.b()),
            clampf32(c.a())
        ])
    }

    /// Return a highlighted version of the current Color.
    pub fn highlighted(&self) -> Color {
        let luminance = self.luminance();
        let (r, g, b) = {
            if luminance > 0.8 {
                (self.r() - 0.2,
                 self.g() - 0.2,
                 self.b() - 0.2)
            }
            else if luminance < 0.2 {
                (self.r() + 0.2,
                 self.g() + 0.2,
                 self.b() + 0.2)
            }
            else {
                (clampf32((1f32 - self.r()) * 0.5f32 * self.r() + self.r()),
                 clampf32((1f32 - self.g()) * 0.1f32 * self.g() + self.g()),
                 clampf32((1f32 - self.b()) * 0.1f32 * self.b() + self.b()))
            }
        };
        let a = clampf32((1f32 - self.a()) * 0.5f32 + self.a());
        Color::new(r, g, b, a)
    }

    /// Return a clicked version of the current Color.
    pub fn clicked(&self) -> Color {
        let luminance = self.luminance();
        let (r, g, b) = {
            if luminance > 0.8 {
                (self.r(),
                 self.g() - 0.2,
                 self.b() - 0.2)
            }
            else if luminance < 0.2 {
                (self.r() + 0.4,
                 self.g() + 0.2,
                 self.b() + 0.2)
            }
            else {
                (clampf32((1f32 - self.r()) * 0.75f32 + self.r()),
                 clampf32((1f32 - self.g()) * 0.25f32 + self.g()),
                 clampf32((1f32 - self.b()) * 0.25f32 + self.b()))
            }
        };
        let a = clampf32((1f32 - self.a()) * 0.75f32 + self.a());
        Color::new(r, g, b, a)
    }

    /// Return a random color.
    pub fn random() -> Color {
        let r = random::<f32>();
        let g = random::<f32>();
        let b = random::<f32>();
        let a = 1f32;
        Color::new(r, g, b, a)
    }

    /// Return an inverted version of the color.
    pub fn invert(&self) -> Color {
        let r = abs(1f32 - self.r());
        let g = abs(1f32 - self.g());
        let b = abs(1f32 - self.b());
        Color::new(r, g, b, self.a())
    }

    /// Return either black or white, depending which contrasts
    /// the Color the most. This will be useful for determining
    /// a readable color for text on any given background Color.
    pub fn plain_contrast(&self) -> Color {
        if self.luminance() > 0.5f32 { Color::black() }
        else { Color::white() }
    }

    /// Return the luminance of the color.
    pub fn luminance(&self) -> f32 {
        (self.r() + self.g() + self.b()) / 3f32
    }

    /// Return an array of the channels in this color
    /// clamped to [0..255]
    pub fn to_32_bit(&self) -> [u8, ..4] {
        [
            to_8_bit(self.r()),
            to_8_bit(self.g()),
            to_8_bit(self.b()),
            to_8_bit(self.a()),
        ]
    }

    /// Return the hex representation of this color
    /// in the format #RRGGBBAA
    /// e.g. `Color(1.0, 0.0, 5.0, 1.0) == "#FF0080FF"`
    pub fn to_hex(&self) -> String {
        let vals = self.to_32_bit();
        // Hex colors are always uppercased
        let hex = vals.as_slice().to_hex().into_ascii_upper();
        format!("#{}", hex.as_slice())
    }
}

fn to_8_bit(chan: f32) -> u8 {
    let chan = clampf32(chan);
    (chan * 255.0) as u8
}

impl Clone for Color {
    fn clone(&self) -> Color {
        *self
    }
}

impl Default for Color {
    /// Default constructor for a Color struct.
    fn default() -> Color {
        Color([0.5, 0.8, 0.6, 1.0])
    }
}

impl Add<Color, Color> for Color {
    fn add(&self, rhs: &Color) -> Color {
        Color::clamp(
            Color([
                self.r() + rhs.r(),
                self.g() + rhs.g(),
                self.b() + rhs.b(),
                self.a()
            ])
        )
    }
}

impl Sub<Color, Color> for Color {
    fn sub(&self, rhs: &Color) -> Color {
        Color::clamp(
            Color([
                self.r() - rhs.r(),
                self.g() - rhs.g(),
                self.b() - rhs.b(),
                self.a()
            ])
        )
    }
}

impl Div<Color, Color> for Color {
    fn div(&self, rhs: &Color) -> Color {
        Color::clamp(
            Color([
                self.r() / rhs.r(),
                self.g() / rhs.g(),
                self.b() / rhs.b(),
                self.a() / rhs.a(),
            ])
        )
    }
}

impl Mul<Color, Color> for Color {
    fn mul(&self, rhs: &Color) -> Color {
        Color::clamp(
            Color([
                self.r() * rhs.r(),
                self.g() * rhs.g(),
                self.b() * rhs.b(),
                self.a() * rhs.a(),
            ])
        )
    }
}

impl Show for Color {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FormatError> {
        let hex = self.to_hex();
        fmt.pad(hex.as_slice())
    }
}

impl<E, D: Decoder<E>> Decodable<E, D> for Color {
    fn decode(dec: &mut D) -> Result<Color, E> {
        let vec = try!(dec.read_to_vec(|le_dec| le_dec.read_f32()));

        if vec.len() != 4 {
            return dec.err(format!(
                "Expected a 4 element vector when decoding Color.
                Found a vector of length {}.", vec.len()));
        }

        Ok(Color([vec[0], vec[1], vec[2], vec[3]]))
    }
}

impl<E, S: Encoder<E>> Encodable<E, D> for Color {
    fn encode(&self, enc: &mut S) -> Result<(), E> {
        let Color(ref vec) = *self;

        enc.emit_from_vec(vec, |le_enc, elt| le_enc.emit_f32(elt))
    }
}
<|endoftext|>


<commit_before>#![allow(unused_imports, unused_variables, unused_mut)]

extern crate crypto;
extern crate "rustc-serialize" as serialize;

use crypto::aes::{mod, KeySize};
use crypto::digest::Digest;
use crypto::sha2::Sha256;
use crypto::symmetriccipher::SynchronousStreamCipher;

use serialize::base64::{STANDARD, ToBase64};

use std::rand::{OsRng, Rng};

fn main() {
    println!("24 days of Rust - rust-crypto (day 21)");
    let input = "Hello world!";
    let mut sha = Sha256::new();
    sha.input_str(input);
    println!("{}", sha.result_str());
    let mut bytes = Vec::from_elem(sha.output_bytes(), 0u8);
    sha.result(bytes.as_mut_slice());
    println!("{}", bytes.to_base64(STANDARD));

    let mut gen = OsRng::new().ok().expect("Failed to get OS random generator");
    let mut key = Vec::from_elem(16, 0u8);
    gen.fill_bytes(key.as_mut_slice());
    let mut nonce = Vec::from_elem(16, 0u8);
    gen.fill_bytes(nonce.as_mut_slice());
    println!("Key: {}", key.to_base64(STANDARD));
    println!("Nonce: {}", nonce.to_base64(STANDARD));
    let mut cipher = aes::ctr(KeySize::KeySize128, key.as_slice(), nonce.as_slice());
    let secret = "I like Nickelback";
    let mut output = Vec::from_elem(secret.len(), 0u8);
    //cipher.process(secret.as_bytes(), output.as_mut_slice());
    //println!("{}", output.to_base64(STANDARD));
}
<commit_msg>HMAC example.<commit_after>#![allow(unused_imports, unused_variables, unused_mut)]

extern crate crypto;
extern crate "rustc-serialize" as serialize;

use crypto::aes::{mod, KeySize};
use crypto::digest::Digest;
use crypto::hmac::Hmac;
use crypto::mac::Mac;
use crypto::sha2::Sha256;
use crypto::symmetriccipher::SynchronousStreamCipher;

use serialize::base64::{STANDARD, ToBase64};
use serialize::hex::ToHex;

use std::rand::{OsRng, Rng};

fn main() {
    println!("24 days of Rust - rust-crypto (day 21)");
    let input = "Hello world!";
    let mut sha = Sha256::new();
    sha.input_str(input);
    println!("{}", sha.result_str());
    let mut bytes = Vec::from_elem(sha.output_bytes(), 0u8);
    sha.result(bytes.as_mut_slice());
    println!("{}", bytes.to_base64(STANDARD));

    let mut gen = OsRng::new().ok().expect("Failed to get OS random generator");
    let mut key = Vec::from_elem(16, 0u8);
    gen.fill_bytes(key.as_mut_slice());
    let mut nonce = Vec::from_elem(16, 0u8);
    gen.fill_bytes(nonce.as_mut_slice());
    println!("Key: {}", key.to_base64(STANDARD));
    println!("Nonce: {}", nonce.to_base64(STANDARD));
    let mut cipher = aes::ctr(KeySize::KeySize128, key.as_slice(), nonce.as_slice());
    let secret = "I like Nickelback";
    let mut output = Vec::from_elem(secret.len(), 0u8);
    //cipher.process(secret.as_bytes(), output.as_mut_slice());
    //println!("{}", output.to_base64(STANDARD));

    let mut hmac_key = Vec::from_elem(32, 0u8);
    gen.fill_bytes(hmac_key.as_mut_slice());
    let message = "Ceterum censeo Carthaginem esse delendam";
    println!("Message: {}", message);
    println!("HMAC key: {}", hmac_key.to_base64(STANDARD));
    let mut hmac = Hmac::new(Sha256::new(), hmac_key.as_slice());
    hmac.input(message.as_bytes());
    println!("HMAC digest: {}", hmac.result().code().to_hex());
}
<|endoftext|>


<commit_before>use crate::npyffi::{NpyTypes, PyArray_Descr, NPY_TYPES, PY_ARRAY_API};
use cfg_if::cfg_if;
use pyo3::{ffi, prelude::*, pyobject_native_type_core, types::PyType, AsPyPointer, PyNativeType};
use std::os::raw::c_int;

pub use num_complex::Complex32 as c32;
pub use num_complex::Complex64 as c64;

/// Binding of [`numpy.dtype`](https://numpy.org/doc/stable/reference/generated/numpy.dtype.html).
///
/// # Example
/// ```
/// use pyo3::types::IntoPyDict;
/// pyo3::Python::with_gil(|py| {
///     let locals = [("np", numpy::get_array_module(py).unwrap())].into_py_dict(py);
///     let dtype: &numpy::PyArrayDescr = py
///         .eval("np.array([1, 2, 3.0]).dtype", Some(locals), None)
///         .unwrap()
///         .downcast()
///         .unwrap();
///     assert_eq!(dtype.get_datatype().unwrap(), numpy::DataType::Float64);
/// });
/// ```
pub struct PyArrayDescr(PyAny);

pyobject_native_type_core!(
    PyArrayDescr,
    *PY_ARRAY_API.get_type_object(NpyTypes::PyArrayDescr_Type),
    #module=Some("numpy"),
    #checkfunction=arraydescr_check
);

unsafe fn arraydescr_check(op: *mut ffi::PyObject) -> c_int {
    ffi::PyObject_TypeCheck(
        op,
        PY_ARRAY_API.get_type_object(NpyTypes::PyArrayDescr_Type),
    )
}

impl PyArrayDescr {
    /// Returns `self` as `*mut PyArray_Descr`.
    pub fn as_dtype_ptr(&self) -> *mut PyArray_Descr {
        self.as_ptr() as _
    }

    /// Returns `self` as `*mut PyArray_Descr` while increasing the reference count.
    ///
    /// Useful in cases where the descriptor is stolen by the API.
    pub fn into_dtype_ptr(&self) -> *mut PyArray_Descr {
        self.into_ptr() as _
    }

    /// Returns the internal `PyType` that this `dtype` holds.
    ///
    /// # Example
    /// ```
    /// pyo3::Python::with_gil(|py| {
    ///    let array = numpy::PyArray::from_vec(py, vec![0.0, 1.0, 2.0f64]);
    ///    let dtype = array.dtype();
    ///    assert_eq!(dtype.get_type().name().unwrap().to_string(), "float64");
    /// });
    /// ```
    pub fn get_type(&self) -> &PyType {
        let dtype_type_ptr = unsafe { *self.as_dtype_ptr() }.typeobj;
        unsafe { PyType::from_type_ptr(self.py(), dtype_type_ptr) }
    }

    /// Returns the data type as `DataType` enum.
    pub fn get_datatype(&self) -> Option<DataType> {
        DataType::from_typenum(self.get_typenum())
    }

    /// Shortcut for creating a descriptor of 'object' type.
    pub fn object(py: Python) -> &Self {
        Self::from_npy_type(py, NPY_TYPES::NPY_OBJECT)
    }

    /// Returns the type descriptor for a registered type.
    pub fn of<T: Element>(py: Python) -> &Self {
        T::get_dtype(py)
    }

    fn from_npy_type(py: Python, npy_type: NPY_TYPES) -> &Self {
        unsafe {
            let descr = PY_ARRAY_API.PyArray_DescrFromType(npy_type as i32);
            py.from_owned_ptr(descr as _)
        }
    }

    pub(crate) fn get_typenum(&self) -> std::os::raw::c_int {
        unsafe { *self.as_dtype_ptr() }.type_num
    }
}

/// Represents numpy data type.
///
/// This is an incomplete counterpart of
/// [Enumerated Types](https://numpy.org/doc/stable/reference/c-api/dtype.html#enumerated-types)
/// in numpy C-API.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum DataType {
    Bool,
    Int8,
    Int16,
    Int32,
    Int64,
    Uint8,
    Uint16,
    Uint32,
    Uint64,
    Float32,
    Float64,
    Complex32,
    Complex64,
    Object,
}

impl DataType {
    /// Construct `DataType` from
    /// [Enumerated Types](https://numpy.org/doc/stable/reference/c-api/dtype.html#enumerated-types).
    pub fn from_typenum(typenum: c_int) -> Option<Self> {
        Some(match typenum {
            x if x == NPY_TYPES::NPY_BOOL as i32 => DataType::Bool,
            x if x == NPY_TYPES::NPY_BYTE as i32 => DataType::Int8,
            x if x == NPY_TYPES::NPY_SHORT as i32 => DataType::Int16,
            x if x == NPY_TYPES::NPY_INT as i32 => DataType::Int32,
            x if x == NPY_TYPES::NPY_LONG as i32 => return DataType::from_clong(false),
            x if x == NPY_TYPES::NPY_LONGLONG as i32 => DataType::Int64,
            x if x == NPY_TYPES::NPY_UBYTE as i32 => DataType::Uint8,
            x if x == NPY_TYPES::NPY_USHORT as i32 => DataType::Uint16,
            x if x == NPY_TYPES::NPY_UINT as i32 => DataType::Uint32,
            x if x == NPY_TYPES::NPY_ULONG as i32 => return DataType::from_clong(true),
            x if x == NPY_TYPES::NPY_ULONGLONG as i32 => DataType::Uint64,
            x if x == NPY_TYPES::NPY_FLOAT as i32 => DataType::Float32,
            x if x == NPY_TYPES::NPY_DOUBLE as i32 => DataType::Float64,
            x if x == NPY_TYPES::NPY_CFLOAT as i32 => DataType::Complex32,
            x if x == NPY_TYPES::NPY_CDOUBLE as i32 => DataType::Complex64,
            x if x == NPY_TYPES::NPY_OBJECT as i32 => DataType::Object,
            _ => return None,
        })
    }

    /// Convert `self` into
    /// [Enumerated Types](https://numpy.org/doc/stable/reference/c-api/dtype.html#enumerated-types).
    pub fn into_ctype(self) -> NPY_TYPES {
        match self {
            DataType::Bool => NPY_TYPES::NPY_BOOL,
            DataType::Int8 => NPY_TYPES::NPY_BYTE,
            DataType::Int16 => NPY_TYPES::NPY_SHORT,
            DataType::Int32 => NPY_TYPES::NPY_INT,
            #[cfg(all(target_pointer_width = "64", not(windows)))]
            DataType::Int64 => NPY_TYPES::NPY_LONG,
            #[cfg(any(target_pointer_width = "32", windows))]
            DataType::Int64 => NPY_TYPES::NPY_LONGLONG,
            DataType::Uint8 => NPY_TYPES::NPY_UBYTE,
            DataType::Uint16 => NPY_TYPES::NPY_USHORT,
            DataType::Uint32 => NPY_TYPES::NPY_UINT,
            DataType::Uint64 => NPY_TYPES::NPY_ULONGLONG,
            DataType::Float32 => NPY_TYPES::NPY_FLOAT,
            DataType::Float64 => NPY_TYPES::NPY_DOUBLE,
            DataType::Complex32 => NPY_TYPES::NPY_CFLOAT,
            DataType::Complex64 => NPY_TYPES::NPY_CDOUBLE,
            DataType::Object => NPY_TYPES::NPY_OBJECT,
        }
    }

    #[inline(always)]
    fn from_clong(is_usize: bool) -> Option<Self> {
        if cfg!(any(target_pointer_width = "32", windows)) {
            Some(if is_usize {
                DataType::Uint32
            } else {
                DataType::Int32
            })
        } else if cfg!(all(target_pointer_width = "64", not(windows))) {
            Some(if is_usize {
                DataType::Uint64
            } else {
                DataType::Int64
            })
        } else {
            None
        }
    }
}

/// Represents that a type can be an element of `PyArray`.
///
/// Currently, only integer/float/complex types are supported.
/// If you come up with a nice implementation for some other types, we're happy to receive your PR :)
/// You may refer to the [numpy document](https://numpy.org/doc/stable/reference/c-api/dtype.html#enumerated-types)
/// for all types that numpy supports.
///
/// # Safety
///
/// A type `T` that implements this trait should be safe when managed in numpy array,
/// thus implementing this trait is marked unsafe.
/// This means that all data types except for `DataType::Object` are assumed to be trivially copyable.
/// Furthermore, it is assumed that for `DataType::Object` the elements are pointers into the Python heap
/// and that the corresponding `Clone` implemenation will never panic as it only increases the reference count.
///
/// # Custom element types
///
/// You can implement this trait to manage arrays of custom element types, but they still need to be stored
/// on Python's heap using PyO3's [Py](pyo3::Py) type.
///
/// ```
/// use numpy::{ndarray::Array2, DataType, Element, PyArray, PyArrayDescr, ToPyArray};
/// use pyo3::{pyclass, Py, Python};
///
/// #[pyclass]
/// pub struct CustomElement;
///
/// // The transparent wrapper is necessary as one cannot implement
/// // a foreign trait (`Element`) on a foreign type (`Py`) directly.
/// #[derive(Clone)]
/// #[repr(transparent)]
/// pub struct Wrapper(pub Py<CustomElement>);
///
/// unsafe impl Element for Wrapper {
///     const DATA_TYPE: DataType = DataType::Object;
///
///     fn is_same_type(dtype: &PyArrayDescr) -> bool {
///         dtype.get_datatype() == Some(DataType::Object)
///     }
///
///     fn get_dtype(py: Python) -> &PyArrayDescr {
///         PyArrayDescr::object(py)
///     }
/// }
///
/// Python::with_gil(|py| {
///     let array = Array2::<Wrapper>::from_shape_fn((2, 3), |(_i, _j)| {
///         Wrapper(Py::new(py, CustomElement).unwrap())
///     });
///
///     let _array: &PyArray<Wrapper, _> = array.to_pyarray(py);
/// });
/// ```
pub unsafe trait Element: Clone + Send {
    /// `DataType` corresponding to this type.
    const DATA_TYPE: DataType;

    /// Returns if the give `dtype` is convertible to `Self` in Rust.
    fn is_same_type(dtype: &PyArrayDescr) -> bool;

    /// Create `dtype`.
    fn get_dtype(py: Python) -> &PyArrayDescr;
}

macro_rules! impl_num_element {
    ($t:ty, $npy_dat_t:ident $(,$npy_types: ident)+) => {
        unsafe impl Element for $t {
            const DATA_TYPE: DataType = DataType::$npy_dat_t;
            fn is_same_type(dtype: &PyArrayDescr) -> bool {
                $(dtype.get_typenum() == NPY_TYPES::$npy_types as i32 ||)+ false
            }
            fn get_dtype(py: Python) -> &PyArrayDescr {
                PyArrayDescr::from_npy_type(py, DataType::$npy_dat_t.into_ctype())
            }
        }
    };
}

impl_num_element!(bool, Bool, NPY_BOOL);
impl_num_element!(i8, Int8, NPY_BYTE);
impl_num_element!(i16, Int16, NPY_SHORT);
impl_num_element!(u8, Uint8, NPY_UBYTE);
impl_num_element!(u16, Uint16, NPY_USHORT);
impl_num_element!(f32, Float32, NPY_FLOAT);
impl_num_element!(f64, Float64, NPY_DOUBLE);
impl_num_element!(c32, Complex32, NPY_CFLOAT);
impl_num_element!(c64, Complex64, NPY_CDOUBLE);

cfg_if! {
    if #[cfg(all(target_pointer_width = "64", windows))] {
            impl_num_element!(usize, Uint64, NPY_ULONGLONG);
    } else if #[cfg(all(target_pointer_width = "64", not(windows)))] {
            impl_num_element!(usize, Uint64, NPY_ULONG, NPY_ULONGLONG);
    } else if #[cfg(all(target_pointer_width = "32", windows))] {
            impl_num_element!(usize, Uint32, NPY_UINT, NPY_ULONG);
    } else if #[cfg(all(target_pointer_width = "32", not(windows)))] {
            impl_num_element!(usize, Uint32, NPY_UINT);
    }
}
cfg_if! {
    if #[cfg(any(target_pointer_width = "32", windows))] {
        impl_num_element!(i32, Int32, NPY_INT, NPY_LONG);
        impl_num_element!(u32, Uint32, NPY_UINT, NPY_ULONG);
        impl_num_element!(i64, Int64, NPY_LONGLONG);
        impl_num_element!(u64, Uint64, NPY_ULONGLONG);
    } else if #[cfg(all(target_pointer_width = "64", not(windows)))] {
        impl_num_element!(i32, Int32, NPY_INT);
        impl_num_element!(u32, Uint32, NPY_UINT);
        impl_num_element!(i64, Int64, NPY_LONG, NPY_LONGLONG);
        impl_num_element!(u64, Uint64, NPY_ULONG, NPY_ULONGLONG);
    }
}

unsafe impl Element for PyObject {
    const DATA_TYPE: DataType = DataType::Object;
    fn is_same_type(dtype: &PyArrayDescr) -> bool {
        dtype.get_typenum() == NPY_TYPES::NPY_OBJECT as i32
    }
    fn get_dtype(py: Python) -> &PyArrayDescr {
        PyArrayDescr::object(py)
    }
}
<commit_msg>Add tests for dtype names (currently failing)<commit_after>use crate::npyffi::{NpyTypes, PyArray_Descr, NPY_TYPES, PY_ARRAY_API};
use cfg_if::cfg_if;
use pyo3::{ffi, prelude::*, pyobject_native_type_core, types::PyType, AsPyPointer, PyNativeType};
use std::os::raw::c_int;

pub use num_complex::Complex32 as c32;
pub use num_complex::Complex64 as c64;

/// Binding of [`numpy.dtype`](https://numpy.org/doc/stable/reference/generated/numpy.dtype.html).
///
/// # Example
/// ```
/// use pyo3::types::IntoPyDict;
/// pyo3::Python::with_gil(|py| {
///     let locals = [("np", numpy::get_array_module(py).unwrap())].into_py_dict(py);
///     let dtype: &numpy::PyArrayDescr = py
///         .eval("np.array([1, 2, 3.0]).dtype", Some(locals), None)
///         .unwrap()
///         .downcast()
///         .unwrap();
///     assert_eq!(dtype.get_datatype().unwrap(), numpy::DataType::Float64);
/// });
/// ```
pub struct PyArrayDescr(PyAny);

pyobject_native_type_core!(
    PyArrayDescr,
    *PY_ARRAY_API.get_type_object(NpyTypes::PyArrayDescr_Type),
    #module=Some("numpy"),
    #checkfunction=arraydescr_check
);

unsafe fn arraydescr_check(op: *mut ffi::PyObject) -> c_int {
    ffi::PyObject_TypeCheck(
        op,
        PY_ARRAY_API.get_type_object(NpyTypes::PyArrayDescr_Type),
    )
}

impl PyArrayDescr {
    /// Returns `self` as `*mut PyArray_Descr`.
    pub fn as_dtype_ptr(&self) -> *mut PyArray_Descr {
        self.as_ptr() as _
    }

    /// Returns `self` as `*mut PyArray_Descr` while increasing the reference count.
    ///
    /// Useful in cases where the descriptor is stolen by the API.
    pub fn into_dtype_ptr(&self) -> *mut PyArray_Descr {
        self.into_ptr() as _
    }

    /// Returns the internal `PyType` that this `dtype` holds.
    ///
    /// # Example
    /// ```
    /// pyo3::Python::with_gil(|py| {
    ///    let array = numpy::PyArray::from_vec(py, vec![0.0, 1.0, 2.0f64]);
    ///    let dtype = array.dtype();
    ///    assert_eq!(dtype.get_type().name().unwrap().to_string(), "float64");
    /// });
    /// ```
    pub fn get_type(&self) -> &PyType {
        let dtype_type_ptr = unsafe { *self.as_dtype_ptr() }.typeobj;
        unsafe { PyType::from_type_ptr(self.py(), dtype_type_ptr) }
    }

    /// Returns the data type as `DataType` enum.
    pub fn get_datatype(&self) -> Option<DataType> {
        DataType::from_typenum(self.get_typenum())
    }

    /// Shortcut for creating a descriptor of 'object' type.
    pub fn object(py: Python) -> &Self {
        Self::from_npy_type(py, NPY_TYPES::NPY_OBJECT)
    }

    /// Returns the type descriptor for a registered type.
    pub fn of<T: Element>(py: Python) -> &Self {
        T::get_dtype(py)
    }

    fn from_npy_type(py: Python, npy_type: NPY_TYPES) -> &Self {
        unsafe {
            let descr = PY_ARRAY_API.PyArray_DescrFromType(npy_type as i32);
            py.from_owned_ptr(descr as _)
        }
    }

    pub(crate) fn get_typenum(&self) -> std::os::raw::c_int {
        unsafe { *self.as_dtype_ptr() }.type_num
    }
}

/// Represents numpy data type.
///
/// This is an incomplete counterpart of
/// [Enumerated Types](https://numpy.org/doc/stable/reference/c-api/dtype.html#enumerated-types)
/// in numpy C-API.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum DataType {
    Bool,
    Int8,
    Int16,
    Int32,
    Int64,
    Uint8,
    Uint16,
    Uint32,
    Uint64,
    Float32,
    Float64,
    Complex32,
    Complex64,
    Object,
}

impl DataType {
    /// Construct `DataType` from
    /// [Enumerated Types](https://numpy.org/doc/stable/reference/c-api/dtype.html#enumerated-types).
    pub fn from_typenum(typenum: c_int) -> Option<Self> {
        Some(match typenum {
            x if x == NPY_TYPES::NPY_BOOL as i32 => DataType::Bool,
            x if x == NPY_TYPES::NPY_BYTE as i32 => DataType::Int8,
            x if x == NPY_TYPES::NPY_SHORT as i32 => DataType::Int16,
            x if x == NPY_TYPES::NPY_INT as i32 => DataType::Int32,
            x if x == NPY_TYPES::NPY_LONG as i32 => return DataType::from_clong(false),
            x if x == NPY_TYPES::NPY_LONGLONG as i32 => DataType::Int64,
            x if x == NPY_TYPES::NPY_UBYTE as i32 => DataType::Uint8,
            x if x == NPY_TYPES::NPY_USHORT as i32 => DataType::Uint16,
            x if x == NPY_TYPES::NPY_UINT as i32 => DataType::Uint32,
            x if x == NPY_TYPES::NPY_ULONG as i32 => return DataType::from_clong(true),
            x if x == NPY_TYPES::NPY_ULONGLONG as i32 => DataType::Uint64,
            x if x == NPY_TYPES::NPY_FLOAT as i32 => DataType::Float32,
            x if x == NPY_TYPES::NPY_DOUBLE as i32 => DataType::Float64,
            x if x == NPY_TYPES::NPY_CFLOAT as i32 => DataType::Complex32,
            x if x == NPY_TYPES::NPY_CDOUBLE as i32 => DataType::Complex64,
            x if x == NPY_TYPES::NPY_OBJECT as i32 => DataType::Object,
            _ => return None,
        })
    }

    /// Convert `self` into
    /// [Enumerated Types](https://numpy.org/doc/stable/reference/c-api/dtype.html#enumerated-types).
    pub fn into_ctype(self) -> NPY_TYPES {
        match self {
            DataType::Bool => NPY_TYPES::NPY_BOOL,
            DataType::Int8 => NPY_TYPES::NPY_BYTE,
            DataType::Int16 => NPY_TYPES::NPY_SHORT,
            DataType::Int32 => NPY_TYPES::NPY_INT,
            #[cfg(all(target_pointer_width = "64", not(windows)))]
            DataType::Int64 => NPY_TYPES::NPY_LONG,
            #[cfg(any(target_pointer_width = "32", windows))]
            DataType::Int64 => NPY_TYPES::NPY_LONGLONG,
            DataType::Uint8 => NPY_TYPES::NPY_UBYTE,
            DataType::Uint16 => NPY_TYPES::NPY_USHORT,
            DataType::Uint32 => NPY_TYPES::NPY_UINT,
            DataType::Uint64 => NPY_TYPES::NPY_ULONGLONG,
            DataType::Float32 => NPY_TYPES::NPY_FLOAT,
            DataType::Float64 => NPY_TYPES::NPY_DOUBLE,
            DataType::Complex32 => NPY_TYPES::NPY_CFLOAT,
            DataType::Complex64 => NPY_TYPES::NPY_CDOUBLE,
            DataType::Object => NPY_TYPES::NPY_OBJECT,
        }
    }

    #[inline(always)]
    fn from_clong(is_usize: bool) -> Option<Self> {
        if cfg!(any(target_pointer_width = "32", windows)) {
            Some(if is_usize {
                DataType::Uint32
            } else {
                DataType::Int32
            })
        } else if cfg!(all(target_pointer_width = "64", not(windows))) {
            Some(if is_usize {
                DataType::Uint64
            } else {
                DataType::Int64
            })
        } else {
            None
        }
    }
}

/// Represents that a type can be an element of `PyArray`.
///
/// Currently, only integer/float/complex types are supported.
/// If you come up with a nice implementation for some other types, we're happy to receive your PR :)
/// You may refer to the [numpy document](https://numpy.org/doc/stable/reference/c-api/dtype.html#enumerated-types)
/// for all types that numpy supports.
///
/// # Safety
///
/// A type `T` that implements this trait should be safe when managed in numpy array,
/// thus implementing this trait is marked unsafe.
/// This means that all data types except for `DataType::Object` are assumed to be trivially copyable.
/// Furthermore, it is assumed that for `DataType::Object` the elements are pointers into the Python heap
/// and that the corresponding `Clone` implemenation will never panic as it only increases the reference count.
///
/// # Custom element types
///
/// You can implement this trait to manage arrays of custom element types, but they still need to be stored
/// on Python's heap using PyO3's [Py](pyo3::Py) type.
///
/// ```
/// use numpy::{ndarray::Array2, DataType, Element, PyArray, PyArrayDescr, ToPyArray};
/// use pyo3::{pyclass, Py, Python};
///
/// #[pyclass]
/// pub struct CustomElement;
///
/// // The transparent wrapper is necessary as one cannot implement
/// // a foreign trait (`Element`) on a foreign type (`Py`) directly.
/// #[derive(Clone)]
/// #[repr(transparent)]
/// pub struct Wrapper(pub Py<CustomElement>);
///
/// unsafe impl Element for Wrapper {
///     const DATA_TYPE: DataType = DataType::Object;
///
///     fn is_same_type(dtype: &PyArrayDescr) -> bool {
///         dtype.get_datatype() == Some(DataType::Object)
///     }
///
///     fn get_dtype(py: Python) -> &PyArrayDescr {
///         PyArrayDescr::object(py)
///     }
/// }
///
/// Python::with_gil(|py| {
///     let array = Array2::<Wrapper>::from_shape_fn((2, 3), |(_i, _j)| {
///         Wrapper(Py::new(py, CustomElement).unwrap())
///     });
///
///     let _array: &PyArray<Wrapper, _> = array.to_pyarray(py);
/// });
/// ```
pub unsafe trait Element: Clone + Send {
    /// `DataType` corresponding to this type.
    const DATA_TYPE: DataType;

    /// Returns if the give `dtype` is convertible to `Self` in Rust.
    fn is_same_type(dtype: &PyArrayDescr) -> bool;

    /// Create `dtype`.
    fn get_dtype(py: Python) -> &PyArrayDescr;
}

macro_rules! impl_num_element {
    ($t:ty, $npy_dat_t:ident $(,$npy_types: ident)+) => {
        unsafe impl Element for $t {
            const DATA_TYPE: DataType = DataType::$npy_dat_t;
            fn is_same_type(dtype: &PyArrayDescr) -> bool {
                $(dtype.get_typenum() == NPY_TYPES::$npy_types as i32 ||)+ false
            }
            fn get_dtype(py: Python) -> &PyArrayDescr {
                PyArrayDescr::from_npy_type(py, DataType::$npy_dat_t.into_ctype())
            }
        }
    };
}

impl_num_element!(bool, Bool, NPY_BOOL);
impl_num_element!(i8, Int8, NPY_BYTE);
impl_num_element!(i16, Int16, NPY_SHORT);
impl_num_element!(u8, Uint8, NPY_UBYTE);
impl_num_element!(u16, Uint16, NPY_USHORT);
impl_num_element!(f32, Float32, NPY_FLOAT);
impl_num_element!(f64, Float64, NPY_DOUBLE);
impl_num_element!(c32, Complex32, NPY_CFLOAT);
impl_num_element!(c64, Complex64, NPY_CDOUBLE);

cfg_if! {
    if #[cfg(all(target_pointer_width = "64", windows))] {
            impl_num_element!(usize, Uint64, NPY_ULONGLONG);
    } else if #[cfg(all(target_pointer_width = "64", not(windows)))] {
            impl_num_element!(usize, Uint64, NPY_ULONG, NPY_ULONGLONG);
    } else if #[cfg(all(target_pointer_width = "32", windows))] {
            impl_num_element!(usize, Uint32, NPY_UINT, NPY_ULONG);
    } else if #[cfg(all(target_pointer_width = "32", not(windows)))] {
            impl_num_element!(usize, Uint32, NPY_UINT);
    }
}
cfg_if! {
    if #[cfg(any(target_pointer_width = "32", windows))] {
        impl_num_element!(i32, Int32, NPY_INT, NPY_LONG);
        impl_num_element!(u32, Uint32, NPY_UINT, NPY_ULONG);
        impl_num_element!(i64, Int64, NPY_LONGLONG);
        impl_num_element!(u64, Uint64, NPY_ULONGLONG);
    } else if #[cfg(all(target_pointer_width = "64", not(windows)))] {
        impl_num_element!(i32, Int32, NPY_INT);
        impl_num_element!(u32, Uint32, NPY_UINT);
        impl_num_element!(i64, Int64, NPY_LONG, NPY_LONGLONG);
        impl_num_element!(u64, Uint64, NPY_ULONG, NPY_ULONGLONG);
    }
}

unsafe impl Element for PyObject {
    const DATA_TYPE: DataType = DataType::Object;
    fn is_same_type(dtype: &PyArrayDescr) -> bool {
        dtype.get_typenum() == NPY_TYPES::NPY_OBJECT as i32
    }
    fn get_dtype(py: Python) -> &PyArrayDescr {
        PyArrayDescr::object(py)
    }
}

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

    use super::{c32, c64, Element, PyArrayDescr};

    #[test]
    fn test_dtype_names() {
        fn type_name<T: Element>(py: pyo3::Python) -> &str {
            PyArrayDescr::of::<T>(py).get_type().name().unwrap()
        }
        pyo3::Python::with_gil(|py| {
            assert_eq!(type_name::<bool>(py), "bool_");
            assert_eq!(type_name::<i8>(py), "int8");
            assert_eq!(type_name::<i16>(py), "int16");
            assert_eq!(type_name::<i32>(py), "int32");
            assert_eq!(type_name::<i64>(py), "int64");
            assert_eq!(type_name::<u8>(py), "uint8");
            assert_eq!(type_name::<u16>(py), "uint16");
            assert_eq!(type_name::<u32>(py), "uint32");
            assert_eq!(type_name::<u64>(py), "uint64");
            assert_eq!(type_name::<f32>(py), "float32");
            assert_eq!(type_name::<f64>(py), "float64");
            assert_eq!(type_name::<c32>(py), "complex64");
            assert_eq!(type_name::<c64>(py), "complex128");
            cfg_if! {
                if #[cfg(target_pointer_width = "64")] {
                    assert_eq!(type_name::<usize>(py), "uint64");
                } else if #[cfg(target_pointer_width = "32")] {
                    assert_eq!(type_name::<usize>(py), "uint32");
                }
            }
        })
    }
}
<|endoftext|>


<commit_before>//! Errors with semantic, crate level meaning.
//!
//! This crate uses [`thiserror`](https://github.com/dtolnay/thiserror) to accomplish error handling.
//!
//! While functions that return `Error` could return errors from other libraries, the errors in
//! `ErrorKind` have special semantic meaning to this crate.

use reqwest;
use serde_json;

/// Errors which have crate specific meanings.
#[derive(Debug, thiserror::Error)]
pub enum Error {
    /// The item does not exist or otherwise cannot be found.
    #[error("Not Found")]
    NotFound,
    /// The reqest's API key is invalid or not authorized to view this resource.
    #[error("Unauthorized")]
    Unauthorized,
    /// An unexpected status code was returned from the API. Please raise a ticket.
    #[error("Unexpected status code: {0}")]
    UnexpectedStatus(reqwest::StatusCode),
    /// The item exists (possibly on another account), the limit on this item has been reached,
    /// or this request is otherwise unprocessable.
    #[error("Unprocessable entity: {0}")]
    UnprocessableEntity(serde_json::Value),
    /// There was a miscellaneous error processing the request. Please look at the documentation of
    /// `reqwest` to learn more about how to handle these errors.
    #[error("{0}")]
    ReqwestError(reqwest::Error),
}

impl From<reqwest::Error> for Error {
    fn from(err: reqwest::Error) -> Self {
        Self::ReqwestError(err)
    }
}<commit_msg>Fix missing newline at EOF<commit_after>//! Errors with semantic, crate level meaning.
//!
//! This crate uses [`thiserror`](https://github.com/dtolnay/thiserror) to accomplish error handling.
//!
//! While functions that return `Error` could return errors from other libraries, the errors in
//! `ErrorKind` have special semantic meaning to this crate.

use reqwest;
use serde_json;

/// Errors which have crate specific meanings.
#[derive(Debug, thiserror::Error)]
pub enum Error {
    /// The item does not exist or otherwise cannot be found.
    #[error("Not Found")]
    NotFound,
    /// The reqest's API key is invalid or not authorized to view this resource.
    #[error("Unauthorized")]
    Unauthorized,
    /// An unexpected status code was returned from the API. Please raise a ticket.
    #[error("Unexpected status code: {0}")]
    UnexpectedStatus(reqwest::StatusCode),
    /// The item exists (possibly on another account), the limit on this item has been reached,
    /// or this request is otherwise unprocessable.
    #[error("Unprocessable entity: {0}")]
    UnprocessableEntity(serde_json::Value),
    /// There was a miscellaneous error processing the request. Please look at the documentation of
    /// `reqwest` to learn more about how to handle these errors.
    #[error("{0}")]
    ReqwestError(reqwest::Error),
}

impl From<reqwest::Error> for Error {
    fn from(err: reqwest::Error) -> Self {
        Self::ReqwestError(err)
    }
}
<|endoftext|>


<commit_before>use url;
use std::error::Error;
use std::fmt;
use r2d2;
cfg_if! {if #[cfg(feature = "with-postgres")]{
    use pg::PostgresError;
}}

cfg_if! {if #[cfg(feature = "with-sqlite")]{
    use sq::SqliteError;
}}

#[derive(Debug)]
pub enum ConnectError {
    NoSuchPoolConnection,
    ParseError(ParseError),
    UnsupportedDb(String),
    R2d2Error(r2d2::Error),
}

/// TODO: use error_chain i guess?
impl Error for ConnectError {
    fn description(&self) -> &str {
        "short desc"
    }
    fn cause(&self) -> Option<&Error> {
        None
    }
}

impl fmt::Display for ConnectError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

#[derive(Debug)]
pub enum ParseError {
    DbUrlParseError(url::ParseError),
}

#[derive(Debug)]
pub enum PlatformError {
    #[cfg(feature = "with-postgres")] PostgresError(PostgresError),
    #[cfg(feature = "with-sqlite")] SqliteError(SqliteError),
}

#[cfg(feature = "with-postgres")]
impl From<PostgresError> for PlatformError {
    fn from(e: PostgresError) -> Self {
        PlatformError::PostgresError(e)
    }
}

#[cfg(feature = "with-postgres")]
impl From<PostgresError> for DbError {
    fn from(e: PostgresError) -> Self {
        DbError::PlatformError(PlatformError::from(e))
    }
}

#[derive(Debug)]
pub enum DbError {
    DataError(DataError),
    PlatformError(PlatformError),
    ConvertError(ConvertError),
    ConnectError(ConnectError), //agnostic connection error
}

#[cfg(feature = "with-postgres")]
impl From<PlatformError> for DbError {
    fn from(e: PlatformError) -> Self {
        DbError::PlatformError(e)
    }
}

#[derive(Debug)]
pub enum ConvertError {
    UnknownDataType,
    UnsupportedDataType(String),
}

#[derive(Debug)]
pub enum DataError {
    ZeroRecordReturned,
    MoreThan1RecordReturned,
}
<commit_msg>Add SqlInjectAttempt as DbError<commit_after>use url;
use std::error::Error;
use std::fmt;
use r2d2;
cfg_if! {if #[cfg(feature = "with-postgres")]{
    use pg::PostgresError;
}}

cfg_if! {if #[cfg(feature = "with-sqlite")]{
    use sq::SqliteError;
}}

#[derive(Debug)]
pub enum ConnectError {
    NoSuchPoolConnection,
    ParseError(ParseError),
    UnsupportedDb(String),
    R2d2Error(r2d2::Error),
}

/// TODO: use error_chain i guess?
impl Error for ConnectError {
    fn description(&self) -> &str {
        "short desc"
    }
    fn cause(&self) -> Option<&Error> {
        None
    }
}

impl fmt::Display for ConnectError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.description())
    }
}

#[derive(Debug)]
pub enum ParseError {
    DbUrlParseError(url::ParseError),
}

#[derive(Debug)]
pub enum PlatformError {
    #[cfg(feature = "with-postgres")] PostgresError(PostgresError),
    #[cfg(feature = "with-sqlite")] SqliteError(SqliteError),
}

#[cfg(feature = "with-postgres")]
impl From<PostgresError> for PlatformError {
    fn from(e: PostgresError) -> Self {
        PlatformError::PostgresError(e)
    }
}

#[cfg(feature = "with-postgres")]
impl From<PostgresError> for DbError {
    fn from(e: PostgresError) -> Self {
        DbError::PlatformError(PlatformError::from(e))
    }
}

#[derive(Debug)]
pub enum DbError {
    SqlInjectionAttempt(String),
    DataError(DataError),
    PlatformError(PlatformError),
    ConvertError(ConvertError),
    ConnectError(ConnectError), //agnostic connection error
}

#[cfg(feature = "with-postgres")]
impl From<PlatformError> for DbError {
    fn from(e: PlatformError) -> Self {
        DbError::PlatformError(e)
    }
}

#[derive(Debug)]
pub enum ConvertError {
    UnknownDataType,
    UnsupportedDataType(String),
}

#[derive(Debug)]
pub enum DataError {
    ZeroRecordReturned,
    MoreThan1RecordReturned,
}
<|endoftext|>


<commit_before>use std::error;
use std::fmt;
use std::io;
use std::num::ParseIntError;

/// The error type for SFEN serialize/deserialize operations.
#[derive(Debug, PartialEq, Eq)]
pub struct SfenError {}

impl fmt::Display for SfenError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "illegal SFEN string")
    }
}

impl error::Error for SfenError {
    fn description(&self) -> &str {
        "illegal SFEN string"
    }

    fn cause(&self) -> Option<&dyn error::Error> {
        None
    }
}

impl From<ParseIntError> for SfenError {
    fn from(_: ParseIntError) -> SfenError {
        SfenError {}
    }
}

impl From<io::Error> for SfenError {
    fn from(_: io::Error) -> SfenError {
        SfenError {}
    }
}

/// Represents an error occurred during making a move.
#[derive(Debug, PartialEq, Eq)]
pub enum MoveError {
    InCheck,
    Nifu,
    Uchifuzume,
    PerpetualCheckWin,
    PerpetualCheckLose,
    EnemysTurn,
    NonMovablePiece,
    Inconsistent(&'static str),
    Repetition,
}

impl fmt::Display for MoveError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            MoveError::InCheck => write!(f, "the king is in check"),
            MoveError::Nifu => write!(f, "nifu detected"),
            MoveError::Uchifuzume => write!(f, "uchifuzume detected"),
            MoveError::PerpetualCheckWin => write!(f, "perpetual check detected"),
            MoveError::PerpetualCheckLose => write!(f, "perpetual check detected"),
            MoveError::EnemysTurn => write!(f, "not your turn"),
            MoveError::NonMovablePiece => write!(f, "the piece can not move anymore"),
            MoveError::Inconsistent(message) => write!(
                f,
                "the move is inconsistent with the current position: {}",
                message
            ),
            MoveError::Repetition => write!(f, "repetition detected"),
        }
    }
}

impl error::Error for MoveError {
    fn description(&self) -> &str {
        match *self {
            MoveError::InCheck => "the king is in check",
            MoveError::Nifu => "nifu detected",
            MoveError::Uchifuzume => "uchifuzume detected",
            MoveError::PerpetualCheckWin => "perpetual check detected",
            MoveError::PerpetualCheckLose => "perpetual check detected",
            MoveError::EnemysTurn => "not your turn",
            MoveError::NonMovablePiece => "the piece can not move anymore",
            MoveError::Inconsistent(message) => {
                "the move is inconsistent with the current position:"
            } // TODO include message
            MoveError::Repetition => "repetition detected",
        }
    }

    fn cause(&self) -> Option<&dyn error::Error> {
        match *self {
            _ => None,
        }
    }
}
<commit_msg>fix: rename an unused variable<commit_after>use std::error;
use std::fmt;
use std::io;
use std::num::ParseIntError;

/// The error type for SFEN serialize/deserialize operations.
#[derive(Debug, PartialEq, Eq)]
pub struct SfenError {}

impl fmt::Display for SfenError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "illegal SFEN string")
    }
}

impl error::Error for SfenError {
    fn description(&self) -> &str {
        "illegal SFEN string"
    }

    fn cause(&self) -> Option<&dyn error::Error> {
        None
    }
}

impl From<ParseIntError> for SfenError {
    fn from(_: ParseIntError) -> SfenError {
        SfenError {}
    }
}

impl From<io::Error> for SfenError {
    fn from(_: io::Error) -> SfenError {
        SfenError {}
    }
}

/// Represents an error occurred during making a move.
#[derive(Debug, PartialEq, Eq)]
pub enum MoveError {
    InCheck,
    Nifu,
    Uchifuzume,
    PerpetualCheckWin,
    PerpetualCheckLose,
    EnemysTurn,
    NonMovablePiece,
    Inconsistent(&'static str),
    Repetition,
}

impl fmt::Display for MoveError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            MoveError::InCheck => write!(f, "the king is in check"),
            MoveError::Nifu => write!(f, "nifu detected"),
            MoveError::Uchifuzume => write!(f, "uchifuzume detected"),
            MoveError::PerpetualCheckWin => write!(f, "perpetual check detected"),
            MoveError::PerpetualCheckLose => write!(f, "perpetual check detected"),
            MoveError::EnemysTurn => write!(f, "not your turn"),
            MoveError::NonMovablePiece => write!(f, "the piece can not move anymore"),
            MoveError::Inconsistent(message) => write!(
                f,
                "the move is inconsistent with the current position: {}",
                message
            ),
            MoveError::Repetition => write!(f, "repetition detected"),
        }
    }
}

impl error::Error for MoveError {
    fn description(&self) -> &str {
        match *self {
            MoveError::InCheck => "the king is in check",
            MoveError::Nifu => "nifu detected",
            MoveError::Uchifuzume => "uchifuzume detected",
            MoveError::PerpetualCheckWin => "perpetual check detected",
            MoveError::PerpetualCheckLose => "perpetual check detected",
            MoveError::EnemysTurn => "not your turn",
            MoveError::NonMovablePiece => "the piece can not move anymore",
            MoveError::Inconsistent(_) => "the move is inconsistent with the current position",
            MoveError::Repetition => "repetition detected",
        }
    }

    fn cause(&self) -> Option<&dyn error::Error> {
        match *self {
            _ => None,
        }
    }
}
<|endoftext|>


<commit_before>macro_rules! callback(
    (
        mod $mod_name:ident {
            $extfun_ty:ty ( $($extarg_id:ident : $extarg_ty:ty),+ )
                => $cbfun_ty:ty ( $($args:expr),+ )
        }
    ) => (
        mod $mod_name {
            /**
             * A key for setting and retrieving the callback from task-
             * local storage
             */
            fn tls_key(_: @$cbfun_ty) {}

            /**
             * Stores the callback in task-local storage and then calls
             * `f` with  with `extfun` as the argument.
             */
            pub fn set_callback(cbfun: $cbfun_ty, f: &fn($extfun_ty) ) {
                unsafe {
                    task::local_data::local_data_set(tls_key, @cbfun);
                    f(extfun);
                }
            }

            /**
             * An external function that invokes the callback currently stored
             * in task-local storage, if it exists.
             */
            pub extern fn extfun( $( $extarg_id : $extarg_ty ),+ ) {
                unsafe {
                    do task::local_data::local_data_get(tls_key).map |&f| {
                        (*f)( $($args),+ );
                    };
                }
            }
        }
    )
)

// Error Callback
pub callback!(
    mod error {
        ::api::GLFWerrorfun(err: libc::c_int,
                            format: *libc::c_char)
            => ::ErrorFun(err, str::raw::from_c_str(format))
    }
)

// Monitor Callback
pub callback!(
    mod monitor {
        ::api::GLFWmonitorfun(monitor: *::api::GLFWmonitor,
                              event: libc::c_int)
            => ::MonitorFun(&::Monitor(monitor), event)
    }
)

// Window Position Callback
pub callback!(
    mod windowpos {
        ::api::GLFWwindowposfun(window: *::api::GLFWwindow,
                                x: libc::c_int,
                                y: libc::c_int)
            => ::WindowPosFun(&::Window(window),
                               x as int, y as int)
    }
)

// Window Size Callback
pub callback!(
    mod windowsize {
        ::api::GLFWwindowsizefun(window: *::api::GLFWwindow,
                                 width: libc::c_int,
                                 height: libc::c_int)
            => ::WindowSizeFun(&::Window(window),
                               width as int, height as int)
    }
)

// Window Close Callback
pub callback!(
    mod windowclose {
        ::api::GLFWwindowclosefun(window: *::api::GLFWwindow)
            => ::WindowCloseFun(&::Window(window))
    }
)

// Window Refresh Callback
pub callback!(
    mod windowrefresh {
        ::api::GLFWwindowrefreshfun(window: *::api::GLFWwindow)
            => ::WindowRefreshFun(&::Window(window))
    }
)

// Window Focus Callback
pub callback!(
    mod windowfocus {
        ::api::GLFWwindowfocusfun(window: *::api::GLFWwindow,
                                  activated: libc::c_int)
            => ::WindowFocusFun(&::Window(window), activated as bool)
    }
)

// Window Iconify Callback
pub callback!(
    mod windowiconify {
        ::api::GLFWwindowiconifyfun(window: *::api::GLFWwindow,
                                    iconified: libc::c_int)
            => ::WindowIconifyFun(&::Window(window), iconified as bool)
    }
)

// Key Callback
pub callback!(
    mod key {
        ::api::GLFWkeyfun(window: *::api::GLFWwindow,
                          key: libc::c_int,
                          action: libc::c_int)
            => ::KeyFun(&::Window(window), key, action)
    }
)

// Character Callback
pub callback!(
    mod char {
        ::api::GLFWcharfun(window: *::api::GLFWwindow,
                           character: libc::c_uint)
            => ::CharFun(&::Window(window),
                         // TODO: tempory fix for the lack of a bounds check
                         // on X11 and Win32 in GLFW
                         if character == -1 { '0' }
                         else { character as char })
    }
)

// Mouse Button Callback
pub callback!(
    mod mousebutton {
        ::api::GLFWmousebuttonfun(window: *::api::GLFWwindow,
                                  button: libc::c_int,
                                  action: libc::c_int)
            => ::MouseButtonFun(&::Window(window), button, action)
    }
)

// Cursor Position Callback
pub callback!(
    mod cursorpos {
        ::api::GLFWcursorposfun(window: *::api::GLFWwindow,
                                x: libc::c_int, y: libc::c_int)
            => ::CursorPosFun(&::Window(window), x as int, y as int)
    }
)

// Cursor Enter Callback
pub callback!(
    mod cursorenter {
        ::api::GLFWcursorenterfun(window: *::api::GLFWwindow,
                                  entered: libc::c_int)
            => ::CursorEnterFun(&::Window(window), entered as bool)
    }
)

// Scroll Callback
pub callback!(
    mod scroll {
        ::api::GLFWscrollfun(window: *::api::GLFWwindow,
                             x: libc::c_double, y: libc::c_double)
            => ::ScrollFun(&::Window(window), x as f64, y as f64)
    }
)
<commit_msg>Remove temporary fix for X11 and Win32 crash<commit_after>macro_rules! callback(
    (
        mod $mod_name:ident {
            $extfun_ty:ty ( $($extarg_id:ident : $extarg_ty:ty),+ )
                => $cbfun_ty:ty ( $($args:expr),+ )
        }
    ) => (
        mod $mod_name {
            /**
             * A key for setting and retrieving the callback from task-
             * local storage
             */
            fn tls_key(_: @$cbfun_ty) {}

            /**
             * Stores the callback in task-local storage and then calls
             * `f` with  with `extfun` as the argument.
             */
            pub fn set_callback(cbfun: $cbfun_ty, f: &fn($extfun_ty) ) {
                unsafe {
                    task::local_data::local_data_set(tls_key, @cbfun);
                    f(extfun);
                }
            }

            /**
             * An external function that invokes the callback currently stored
             * in task-local storage, if it exists.
             */
            pub extern fn extfun( $( $extarg_id : $extarg_ty ),+ ) {
                unsafe {
                    do task::local_data::local_data_get(tls_key).map |&f| {
                        (*f)( $($args),+ );
                    };
                }
            }
        }
    )
)

// Error Callback
pub callback!(
    mod error {
        ::api::GLFWerrorfun(err: libc::c_int,
                            format: *libc::c_char)
            => ::ErrorFun(err, str::raw::from_c_str(format))
    }
)

// Monitor Callback
pub callback!(
    mod monitor {
        ::api::GLFWmonitorfun(monitor: *::api::GLFWmonitor,
                              event: libc::c_int)
            => ::MonitorFun(&::Monitor(monitor), event)
    }
)

// Window Position Callback
pub callback!(
    mod windowpos {
        ::api::GLFWwindowposfun(window: *::api::GLFWwindow,
                                x: libc::c_int,
                                y: libc::c_int)
            => ::WindowPosFun(&::Window(window),
                               x as int, y as int)
    }
)

// Window Size Callback
pub callback!(
    mod windowsize {
        ::api::GLFWwindowsizefun(window: *::api::GLFWwindow,
                                 width: libc::c_int,
                                 height: libc::c_int)
            => ::WindowSizeFun(&::Window(window),
                               width as int, height as int)
    }
)

// Window Close Callback
pub callback!(
    mod windowclose {
        ::api::GLFWwindowclosefun(window: *::api::GLFWwindow)
            => ::WindowCloseFun(&::Window(window))
    }
)

// Window Refresh Callback
pub callback!(
    mod windowrefresh {
        ::api::GLFWwindowrefreshfun(window: *::api::GLFWwindow)
            => ::WindowRefreshFun(&::Window(window))
    }
)

// Window Focus Callback
pub callback!(
    mod windowfocus {
        ::api::GLFWwindowfocusfun(window: *::api::GLFWwindow,
                                  activated: libc::c_int)
            => ::WindowFocusFun(&::Window(window), activated as bool)
    }
)

// Window Iconify Callback
pub callback!(
    mod windowiconify {
        ::api::GLFWwindowiconifyfun(window: *::api::GLFWwindow,
                                    iconified: libc::c_int)
            => ::WindowIconifyFun(&::Window(window), iconified as bool)
    }
)

// Key Callback
pub callback!(
    mod key {
        ::api::GLFWkeyfun(window: *::api::GLFWwindow,
                          key: libc::c_int,
                          action: libc::c_int)
            => ::KeyFun(&::Window(window), key, action)
    }
)

// Character Callback
pub callback!(
    mod char {
        ::api::GLFWcharfun(window: *::api::GLFWwindow,
                           character: libc::c_uint)
            => ::CharFun(&::Window(window), character as char)
    }
)

// Mouse Button Callback
pub callback!(
    mod mousebutton {
        ::api::GLFWmousebuttonfun(window: *::api::GLFWwindow,
                                  button: libc::c_int,
                                  action: libc::c_int)
            => ::MouseButtonFun(&::Window(window), button, action)
    }
)

// Cursor Position Callback
pub callback!(
    mod cursorpos {
        ::api::GLFWcursorposfun(window: *::api::GLFWwindow,
                                x: libc::c_int, y: libc::c_int)
            => ::CursorPosFun(&::Window(window), x as int, y as int)
    }
)

// Cursor Enter Callback
pub callback!(
    mod cursorenter {
        ::api::GLFWcursorenterfun(window: *::api::GLFWwindow,
                                  entered: libc::c_int)
            => ::CursorEnterFun(&::Window(window), entered as bool)
    }
)

// Scroll Callback
pub callback!(
    mod scroll {
        ::api::GLFWscrollfun(window: *::api::GLFWwindow,
                             x: libc::c_double, y: libc::c_double)
            => ::ScrollFun(&::Window(window), x as f64, y as f64)
    }
)
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::HashSet;

use serde_json;
use failure::Context;

use errors::prelude::*;
use services::ledger::merkletree::merkletree::MerkleTree;
use services::pool::merkle_tree_factory;
use services::pool::rust_base58::{FromBase58, ToBase58};
use services::pool::types::{CatchupReq, Message};

pub enum CatchupProgress {
    ShouldBeStarted(
        Vec<u8>, //target_mt_root
        usize, //target_mt_size
        MerkleTree,
    ),
    NotNeeded(MerkleTree),
    Restart(MerkleTree),
    InProgress,
}

pub fn build_catchup_req(merkle: &MerkleTree, target_mt_size: usize) -> IndyResult<Option<(String, String)>> {
    let txns_cnt = target_mt_size - merkle.count();

    if txns_cnt <= 0 {
        warn!("No transactions to catch up!");
        return Ok(None);
    }
    let seq_no_start = merkle.count() + 1;
    let seq_no_end = target_mt_size;

    let cr = CatchupReq {
        ledgerId: 0,
        seqNoStart: seq_no_start.clone(),
        seqNoEnd: seq_no_end.clone(),
        catchupTill: target_mt_size,
    };

    let req_id = format!("{}{}", seq_no_start, seq_no_end);

    let req_json = serde_json::to_string(&Message::CatchupReq(cr))
        .to_indy(IndyErrorKind::InvalidState, "Cannot serialize CatchupRequest")?;

    trace!("catchup_req msg: {:?}", req_json);
    Ok(Some((req_id, req_json)))
}

pub fn check_nodes_responses_on_status(nodes_votes: &HashMap<(String, usize, Option<Vec<String>>), HashSet<String>>,
                                       merkle_tree: &MerkleTree,
                                       node_cnt: usize,
                                       f: usize,
                                       pool_name: &str) -> IndyResult<CatchupProgress> {
    if let Some((most_popular_vote, votes_cnt)) = nodes_votes.iter().map(|(key, val)| (key, val.len())).max_by_key(|entry| entry.1) {
        let is_consensus_reached = votes_cnt == node_cnt - f;
        if is_consensus_reached {
            if most_popular_vote.0.eq("timeout") {
                return Err(err_msg(IndyErrorKind::PoolTimeout, "Pool timeout"));
            }

            return _try_to_catch_up(most_popular_vote, merkle_tree).or_else(|err| {
                if merkle_tree_factory::drop_cache(pool_name).is_ok() {
                    let merkle_tree = merkle_tree_factory::create(pool_name)?;
                    _try_to_catch_up(most_popular_vote, &merkle_tree)
                } else {
                    Err(err)
                }
            });
        } else {
            let reps_cnt: usize = nodes_votes.values().map(|set| set.len()).sum();
            let positive_votes_cnt = votes_cnt + (node_cnt - reps_cnt);
            let is_consensus_reachable = positive_votes_cnt < node_cnt - f;
            if is_consensus_reachable {
                if merkle_tree_factory::drop_cache(pool_name).is_ok() {
                    let merkle_tree = merkle_tree_factory::create(pool_name)?;
                    return Ok(CatchupProgress::Restart(merkle_tree))
                } else {
                    //TODO: maybe we should change the error, but it was made to escape changing of ErrorCode returned to client
                    return Err(err_msg(IndyErrorKind::PoolTimeout, "No consensus possible"));
                }
            }
        }
    }
    Ok(CatchupProgress::InProgress)
}

fn _try_to_catch_up(ledger_status: &(String, usize, Option<Vec<String>>), merkle_tree: &MerkleTree) -> IndyResult<CatchupProgress> {
    let &(ref target_mt_root, target_mt_size, ref hashes) = ledger_status;
    let cur_mt_size = merkle_tree.count();
    let cur_mt_hash = merkle_tree.root_hash().to_base58();

    if target_mt_size == cur_mt_size {
        if cur_mt_hash.eq(target_mt_root) {
            return Ok(CatchupProgress::NotNeeded(merkle_tree.clone()));
        } else {
            return Err(err_msg(IndyErrorKind::InvalidState,
                               "Ledger merkle tree is not acceptable for current tree."));
        }
    } else if target_mt_size > cur_mt_size {
        let target_mt_root = target_mt_root
            .from_base58()
            .map_err(|err| Context::new(err))
            .to_indy(IndyErrorKind::InvalidStructure, "Can't parse target MerkleTree hash from nodes responses")?; // FIXME: review kind

        match hashes {
            &None => (),
            &Some(ref hashes) => check_cons_proofs(merkle_tree, hashes, &target_mt_root, target_mt_size)?,
        };

        return Ok(CatchupProgress::ShouldBeStarted(target_mt_root, target_mt_size, merkle_tree.clone()));
    } else {
        return Err(err_msg(IndyErrorKind::InvalidState, "Local merkle tree greater than mt from ledger"));
    }
}

pub fn check_cons_proofs(mt: &MerkleTree, cons_proofs: &Vec<String>, target_mt_root: &Vec<u8>, target_mt_size: usize) -> IndyResult<()> {
    let mut bytes_proofs: Vec<Vec<u8>> = Vec::new();

    for cons_proof in cons_proofs {
        let cons_proof: &String = cons_proof;

        bytes_proofs.push(
            cons_proof
                .from_base58()
                .map_err(|err| Context::new(err))
                .to_indy(IndyErrorKind::InvalidStructure, "Can't decode node consistency proof")? // FIXME: review kind
        );
    }

    if !mt.consistency_proof(target_mt_root, target_mt_size, &bytes_proofs)? {
        return Err(err_msg(IndyErrorKind::InvalidState, "Consistency proof verification failed")); // FIXME: review kind
    }

    Ok(())
}<commit_msg>Restart catchup in case of Timout was most popular vote<commit_after>use std::collections::HashMap;
use std::collections::HashSet;

use serde_json;
use failure::Context;

use errors::prelude::*;
use services::ledger::merkletree::merkletree::MerkleTree;
use services::pool::merkle_tree_factory;
use services::pool::rust_base58::{FromBase58, ToBase58};
use services::pool::types::{CatchupReq, Message};

pub enum CatchupProgress {
    ShouldBeStarted(
        Vec<u8>, //target_mt_root
        usize, //target_mt_size
        MerkleTree,
    ),
    NotNeeded(MerkleTree),
    Restart(MerkleTree),
    InProgress,
}

pub fn build_catchup_req(merkle: &MerkleTree, target_mt_size: usize) -> IndyResult<Option<(String, String)>> {
    let txns_cnt = target_mt_size - merkle.count();

    if txns_cnt <= 0 {
        warn!("No transactions to catch up!");
        return Ok(None);
    }
    let seq_no_start = merkle.count() + 1;
    let seq_no_end = target_mt_size;

    let cr = CatchupReq {
        ledgerId: 0,
        seqNoStart: seq_no_start.clone(),
        seqNoEnd: seq_no_end.clone(),
        catchupTill: target_mt_size,
    };

    let req_id = format!("{}{}", seq_no_start, seq_no_end);

    let req_json = serde_json::to_string(&Message::CatchupReq(cr))
        .to_indy(IndyErrorKind::InvalidState, "Cannot serialize CatchupRequest")?;

    trace!("catchup_req msg: {:?}", req_json);
    Ok(Some((req_id, req_json)))
}

pub fn check_nodes_responses_on_status(nodes_votes: &HashMap<(String, usize, Option<Vec<String>>), HashSet<String>>,
                                       merkle_tree: &MerkleTree,
                                       node_cnt: usize,
                                       f: usize,
                                       pool_name: &str) -> IndyResult<CatchupProgress> {
    if let Some((most_popular_vote, votes_cnt)) = nodes_votes.iter().map(|(key, val)| (key, val.len())).max_by_key(|entry| entry.1) {
        let is_consensus_reached = votes_cnt == node_cnt - f;
        if is_consensus_reached {
            if most_popular_vote.0.eq("timeout") {
                return _try_to_restart_catch_up(pool_name, err_msg(IndyErrorKind::PoolTimeout, "Pool timeout"))
            }

            return _try_to_catch_up(most_popular_vote, merkle_tree).or_else(|err| {
                if merkle_tree_factory::drop_cache(pool_name).is_ok() {
                    let merkle_tree = merkle_tree_factory::create(pool_name)?;
                    _try_to_catch_up(most_popular_vote, &merkle_tree)
                } else {
                    Err(err)
                }
            });
        } else {
            let reps_cnt: usize = nodes_votes.values().map(HashSet::len).sum();
            let positive_votes_cnt = votes_cnt + (node_cnt - reps_cnt);
            let is_consensus_reachable = positive_votes_cnt < node_cnt - f;
            if is_consensus_reachable {
               return  _try_to_restart_catch_up(pool_name, err_msg(IndyErrorKind::PoolTimeout, "No consensus possible"))
            }
        }
    }
    Ok(CatchupProgress::InProgress)
}

fn _try_to_restart_catch_up(pool_name: &str, err: IndyError) -> IndyResult<CatchupProgress>{
    if merkle_tree_factory::drop_cache(pool_name).is_ok() {
        let merkle_tree = merkle_tree_factory::create(pool_name)?;
        return Ok(CatchupProgress::Restart(merkle_tree))
    } else {
        //TODO: maybe we should change the error, but it was made to escape changing of ErrorCode returned to client
        return Err(err);
    }
}

fn _try_to_catch_up(ledger_status: &(String, usize, Option<Vec<String>>), merkle_tree: &MerkleTree) -> IndyResult<CatchupProgress> {
    let &(ref target_mt_root, target_mt_size, ref hashes) = ledger_status;
    let cur_mt_size = merkle_tree.count();
    let cur_mt_hash = merkle_tree.root_hash().to_base58();

    if target_mt_size == cur_mt_size {
        if cur_mt_hash.eq(target_mt_root) {
            return Ok(CatchupProgress::NotNeeded(merkle_tree.clone()));
        } else {
            return Err(err_msg(IndyErrorKind::InvalidState,
                               "Ledger merkle tree is not acceptable for current tree."));
        }
    } else if target_mt_size > cur_mt_size {
        let target_mt_root = target_mt_root
            .from_base58()
            .map_err(|err| Context::new(err))
            .to_indy(IndyErrorKind::InvalidStructure, "Can't parse target MerkleTree hash from nodes responses")?; // FIXME: review kind

        match hashes {
            &None => (),
            &Some(ref hashes) => check_cons_proofs(merkle_tree, hashes, &target_mt_root, target_mt_size)?,
        };

        return Ok(CatchupProgress::ShouldBeStarted(target_mt_root, target_mt_size, merkle_tree.clone()));
    } else {
        return Err(err_msg(IndyErrorKind::InvalidState, "Local merkle tree greater than mt from ledger"));
    }
}

pub fn check_cons_proofs(mt: &MerkleTree, cons_proofs: &Vec<String>, target_mt_root: &Vec<u8>, target_mt_size: usize) -> IndyResult<()> {
    let mut bytes_proofs: Vec<Vec<u8>> = Vec::new();

    for cons_proof in cons_proofs {
        let cons_proof: &String = cons_proof;

        bytes_proofs.push(
            cons_proof
                .from_base58()
                .map_err(|err| Context::new(err))
                .to_indy(IndyErrorKind::InvalidStructure, "Can't decode node consistency proof")? // FIXME: review kind
        );
    }

    if !mt.consistency_proof(target_mt_root, target_mt_size, &bytes_proofs)? {
        return Err(err_msg(IndyErrorKind::InvalidState, "Consistency proof verification failed")); // FIXME: review kind
    }

    Ok(())
}<|endoftext|>


<commit_before>#![feature(dynamic_lib)]
#![feature(path_relative_from)]

extern crate libc;
extern crate errno;

#[macro_use]
extern crate lazy_static;
lazy_static! {
    static ref DELAY_FDS: Mutex<HashSet<c_int>> = Mutex::new(HashSet::new());
    static ref ERR_FDS: Mutex<HashSet<c_int>> = Mutex::new(HashSet::new());
}

macro_rules! get_libc_func(
    ($destination_t:ty, $funcname:expr) =>
        (
            {
                use std::dynamic_lib::DynamicLibrary;
                use std::mem::transmute;
                use std::path::Path;

                unsafe {
                    let libc_dl = match DynamicLibrary::open(Some(Path::new("libc.so.6"))) {
                        Ok(libc) => libc,
                        Err(error) => panic!("Couldn't open libc: '{}'", error),
                    };

                    match libc_dl.symbol::<c_void>($funcname) {
                        Ok(open_func) => transmute::<* mut c_void, $destination_t>(open_func),
                        Err(error) => panic!("Couldn't '{}'", error),
                }
            }
        })
);

use errno::{Errno, set_errno};
use std::sync::Mutex;

use std::collections::hash_set::HashSet;

use libc::{c_char, c_int, c_void};

type OpenFunc = fn(* const c_char, c_int, libc::mode_t) -> c_int;
use libc::types::os::arch::posix88::ssize_t;
type ReadFunc = fn(fd: c_int, buf: * mut c_void, nbytes: c_int) -> ssize_t;
type WriteFunc = ReadFunc;
type CloseFunc = fn(fd: c_int) -> c_int;

use std::env;

fn get_delay_amount_ms() -> u32 {
    let default_delay_amount_ms = 200;

    match env::var("LIBFAULTINJ_DELAY_MS") {
        Ok(p) => match p.parse::<u32>() {
            Ok(i) => i,
            Err(_) => default_delay_amount_ms,
        },
        Err(_) => default_delay_amount_ms,
    }
}

use std::path::Path;

macro_rules! matchesPath(
        ($filename: expr, $env_name: expr) =>
    {
        match env::var($env_name) {
            Ok(p) => {
                let filename_path = Path::new(&$filename);
                let delay_path_match = (filename_path.relative_from(Path::new(&p))) != None;
                let filename_match = filename_path == Path::new(&p);

                delay_path_match || filename_match
            }
            Err(_) => false
        }
    });

#[no_mangle]
pub extern "C" fn open(filename_: *const c_char, flags: c_int, mode: libc::mode_t) -> c_int {
    let filename: String = unsafe {
        std::ffi::CStr::from_ptr(filename_).to_string_lossy().into_owned()
    };
    let open_func = get_libc_func!(OpenFunc, "open");
    let fd: c_int = open_func(filename_, flags, mode);

    if matchesPath!(filename, "LIBFAULTINJ_DELAY_PATH") {
        DELAY_FDS.lock().unwrap().insert(fd);
    }

    fd
}

#[no_mangle]
pub extern "C" fn read(fd: c_int, buf: *mut c_void, nbytes: c_int) -> ssize_t {
    use std::thread;
    let read_func = get_libc_func!(ReadFunc, "read");

    let delay_match = DELAY_FDS.lock().unwrap().contains(&fd);
    let err_match = ERR_FDS.lock().unwrap().contains(&fd);

    let ret: ssize_t = read_func(fd, buf, nbytes);

    if delay_match {
        thread::sleep_ms(get_delay_amount_ms());
    }
    if err_match {
        use libc::consts::os::posix88::EIO;
        set_errno(Errno(EIO));

        return -1
    }

    ret
}

#[no_mangle]
pub extern "C" fn write(fd: c_int, buf: *mut c_void, nbytes: c_int) -> ssize_t {
    let write_func = get_libc_func!(WriteFunc, "write");

    let matches = DELAY_FDS.lock().unwrap().contains(&fd);

    let ret: ssize_t = write_func(fd, buf, nbytes);

    if matches {
        use libc::consts::os::posix88::EIO;
        set_errno(Errno(EIO));

        return -1
    }

    ret
}

#[no_mangle]
pub extern "C" fn close(fd: c_int) -> c_int {
    let close_func = get_libc_func!(CloseFunc, "close");

    let ret: c_int = close_func(fd);

    let mut fds = DELAY_FDS.lock().unwrap();
    if fds.contains(&fd) {
        fds.remove(&fd);
    }

    ret
}
<commit_msg>Fixed deadlock<commit_after>#![feature(dynamic_lib)]
#![feature(path_relative_from)]

extern crate libc;
extern crate errno;

#[macro_use]
extern crate lazy_static;
lazy_static! {
    static ref DELAY_FDS: RwLock<HashSet<c_int>> = RwLock::new(HashSet::new());
    static ref ERR_FDS: RwLock<HashSet<c_int>> = RwLock::new(HashSet::new());
}

macro_rules! get_libc_func(
    ($destination_t:ty, $funcname:expr) =>
        (
            {
                use std::dynamic_lib::DynamicLibrary;
                use std::mem::transmute;
                use std::path::Path;

                let system_c_library: &str = "libc.so.6";

                unsafe {
                    let libc_dl = match DynamicLibrary::open(Some(Path::new(system_c_library))) {
                        Ok(libc) => libc,
                        Err(error) => panic!("Couldn't open libc: '{}'", error),
                    };

                    match libc_dl.symbol::<c_void>($funcname) {
                        Ok(open_func) => transmute::<* mut c_void, $destination_t>(open_func),
                        Err(error) => panic!("Couldn't '{}'", error),
                }
            }
        })
);

use errno::{Errno, set_errno};
use std::sync::Mutex;
use std::sync::RwLock;

use std::collections::hash_set::HashSet;

use libc::{c_char, c_int, c_void};

type OpenFunc = fn(* const c_char, c_int, libc::mode_t) -> c_int;
use libc::types::os::arch::posix88::ssize_t;
type ReadFunc = fn(fd: c_int, buf: * mut c_void, nbytes: c_int) -> ssize_t;
type WriteFunc = ReadFunc;
type CloseFunc = fn(fd: c_int) -> c_int;

use std::env;

fn get_delay_amount_ms() -> u32 {
    let default_delay_amount_ms = 200;

    match env::var("LIBFAULTINJ_DELAY_MS") {
        Ok(p) => match p.parse::<u32>() {
            Ok(i) => i,
            Err(_) => default_delay_amount_ms,
        },
        Err(_) => default_delay_amount_ms,
    }
}

use std::path::Path;

macro_rules! matchesPath(
        ($filename: expr, $env_name: expr) =>
    {
        match env::var($env_name) {
            Ok(p) => {
                let filename_path = Path::new(&$filename);
                let delay_path_match = (filename_path.relative_from(Path::new(&p))) != None;
                let filename_match = filename_path == Path::new(&p);

                delay_path_match || filename_match
            }
            Err(_) => false
        }
    });

fn initialize_sets()
{
    let fd: c_int = 0;
    DELAY_FDS.read().unwrap().contains(&fd);
    ERR_FDS.read().unwrap().contains(&fd);
}

#[no_mangle]
pub extern "C" fn open(filename_: *const c_char, flags: c_int, mode: libc::mode_t) -> c_int {
    let filename: String = unsafe {
        std::ffi::CStr::from_ptr(filename_).to_string_lossy().into_owned()
    };
    let open_func = get_libc_func!(OpenFunc, "open");
    let fd: c_int = open_func(filename_, flags, mode);

    initialize_sets();

    if matchesPath!(filename, "LIBFAULTINJ_DELAY_PATH") {
        DELAY_FDS.write().unwrap().insert(fd);
    }

    fd
}

#[no_mangle]
pub extern "C" fn read(fd: c_int, buf: *mut c_void, nbytes: c_int) -> ssize_t {
    use std::thread;
    let read_func = get_libc_func!(ReadFunc, "read");

    let delay_match = DELAY_FDS.read().unwrap().contains(&fd);
    let err_match = ERR_FDS.read().unwrap().contains(&fd);

    let ret: ssize_t = read_func(fd, buf, nbytes);

    if delay_match {
        thread::sleep_ms(get_delay_amount_ms());
    }
    if err_match {
        use libc::consts::os::posix88::EIO;
        set_errno(Errno(EIO));

        return -1
    }

    ret
}

#[no_mangle]
pub extern "C" fn write(fd: c_int, buf: *mut c_void, nbytes: c_int) -> ssize_t {
    let write_func = get_libc_func!(WriteFunc, "write");

    let matches = DELAY_FDS.read().unwrap().contains(&fd);

    let ret: ssize_t = write_func(fd, buf, nbytes);

    if matches {
        use libc::consts::os::posix88::EIO;
        set_errno(Errno(EIO));

        return -1
    }

    ret
}

#[no_mangle]
pub extern "C" fn close(fd: c_int) -> c_int {
    let close_func = get_libc_func!(CloseFunc, "close");

    let ret: c_int = close_func(fd);

    let mut err_fds = ERR_FDS.write().unwrap();
    if err_fds.contains(&fd) {
        err_fds.remove(&fd);
    }

    let mut delay_fds = DELAY_FDS.write().unwrap();
    if delay_fds.contains(&fd) {
        delay_fds.remove(&fd);
    }

    ret
}
<|endoftext|>


<commit_before>use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign};

// The field size.
const P: u128 = (1 << 127) - 1;

// A finite field element.
//
// It is consistent iff 0 <= self.0 <= P.
// Note that this implies that the zero element has two internal representations.
#[derive(Clone, Copy, Default, Debug)]
pub struct Fp(u128);

#[inline]
fn as_limbs(x: u128) -> (u64, u64) {
    ((x >> 64) as u64, x as u64)
}

trait Reduce: Sized {
    fn reduce_once(self) -> u128;

    #[inline]
    fn reduce_once_assert(self) -> u128 {
        let red: u128 = self.reduce_once();
        debug_assert!(0 <= red && red <= P);
        red
    }
}

impl Reduce for u128 {
    #[inline]
    fn reduce_once(self) -> u128 {
        (self & P) + (self >> 127)
    }
}

impl Reduce for (u128, u128) {
    #[inline]
    fn reduce_once(self) -> u128 {
        let (h, l) = self;
        // (h, l) >> 127;
        let shift = (h << 1) | (l >> 127);
        (l & P) + shift
    }
}

impl Fp {
    #[inline]
    pub fn new(x: u128) -> Fp {
        Fp(x.reduce_once_assert())
    }

    #[inline]
    pub fn prime() -> u128 {
        P
    }
}

impl From<u128> for Fp {
    #[inline]
    fn from(x: u128) -> Self {
        Fp::new(x)
    }
}

impl From<Fp> for u128 {
    #[inline]
    fn from(x: Fp) -> u128 {
        let red = x.0.reduce_once_assert();
        if red == P { 0 } else { red }
    }
}

impl Add for Fp {
    type Output = Self;
    #[inline]
    fn add(self, other: Self) -> Self {
        Fp((self.0 + other.0).reduce_once_assert())
    }
}

impl AddAssign for Fp {
    #[inline]
    fn add_assign(&mut self, other: Self) {
        *self = *self + other
    }
}

impl Sub for Fp {
    type Output = Self;
    #[inline]
    fn sub(self, other: Self) -> Self {
        Fp((self.0 + P - other.0).reduce_once_assert())
    }
}

impl SubAssign for Fp {
    #[inline]
    fn sub_assign(&mut self, other: Self) {
        *self = *self - other
    }
}

impl Mul for Fp {
    type Output = Self;
    #[inline]
    fn mul(self, other: Self) -> Self {
        let (sh, sl) = as_limbs(self.0);
        let (oh, ol) = as_limbs(other.0);

        // (64 bits * 63 bits) + (64 bits * 63 bits) = 128 bits
        let m: u128 = (sh as u128 * ol as u128) + (oh as u128 * sl as u128);
        let (mh, ml) = as_limbs(m);

        // (64 bits * 64 bits) + 128 bits = 129 bits
        let (rl, carry) = (sl as u128 * ol as u128).overflowing_add((ml as u128) << 64);

        // (63 bits * 63 bits) + 64 bits + 1 bit = 127 bits
        let rh: u128 = (sh as u128 * oh as u128) + (mh as u128) + (carry as u128);

        Fp((rh, rl).reduce_once().reduce_once_assert())
    }
}

impl MulAssign for Fp {
    #[inline]
    fn mul_assign(&mut self, other: Self) {
        *self = *self * other
    }
}

impl PartialEq for Fp {
    fn eq(&self, other: &Self) -> bool {
        u128::from(*self) == u128::from(*other)
    }
}

impl Eq for Fp {}

mod tests {
    use super::*;

    #[test]
    fn add() {
        assert_eq!(Fp(7) + Fp(5), Fp(12));
        assert_eq!(Fp(P - 2) + Fp(5), Fp(3));
        assert_eq!(
            Fp(75661398932549814984099328258351945610) + Fp(154440289138086217180118920884960981429),
            Fp(59960504610166800432530945427428821312)
        );
    }

    #[test]
    fn sub() {
        assert_eq!(Fp(7) - Fp(5), Fp(2));
        assert_eq!(Fp(4) - Fp(8), Fp(P - 4));
    }

    #[test]
    fn mul() {
        assert_eq!(Fp(4) * Fp(3), Fp(12));
        assert_eq!(Fp(P) * Fp(291298091), Fp(0));
        assert_eq!(
            Fp(14766549069271113692204649107775507741) * Fp(153613967287097206589234951623852979690),
            Fp(113548737858505840193892055835373785352)
        );
        // Two reductions are necessary for the following example.
        assert_eq!(
            Fp(75661398932549814984099328258351945610) * Fp(154440289138086217180118920884960981429),
            Fp(109146875586984049909139102289297416971)
        );
    }

    #[test]
    fn eq() {
        assert_eq!(Fp(0), Fp(P));
        assert!(Fp(17) != Fp(4));
        assert!(Fp(0) != Fp(4));
        assert!(Fp(P) != Fp(17));
    }

    #[test]
    fn assign() {
        let mut a = Fp(17);

        a += Fp(3);
        assert_eq!(a, Fp(20));

        a -= Fp(5);
        assert_eq!(a, Fp(15));

        a *= Fp(2);
        assert_eq!(a, Fp(30));
    }
}
<commit_msg>Implement unary negation in finite field<commit_after>use std::ops::{Neg, Add, AddAssign, Sub, SubAssign, Mul, MulAssign};

// The field size.
const P: u128 = (1 << 127) - 1;

// A finite field element.
//
// It is consistent iff 0 <= self.0 <= P.
// Note that this implies that the zero element has two internal representations.
#[derive(Clone, Copy, Default, Debug)]
pub struct Fp(u128);

#[inline]
fn as_limbs(x: u128) -> (u64, u64) {
    ((x >> 64) as u64, x as u64)
}

trait Reduce: Sized {
    fn reduce_once(self) -> u128;

    #[inline]
    fn reduce_once_assert(self) -> u128 {
        let red: u128 = self.reduce_once();
        debug_assert!(0 <= red && red <= P);
        red
    }
}

impl Reduce for u128 {
    #[inline]
    fn reduce_once(self) -> u128 {
        (self & P) + (self >> 127)
    }
}

impl Reduce for (u128, u128) {
    #[inline]
    fn reduce_once(self) -> u128 {
        let (h, l) = self;
        // (h, l) >> 127;
        let shift = (h << 1) | (l >> 127);
        (l & P) + shift
    }
}

impl Fp {
    #[inline]
    pub fn new(x: u128) -> Fp {
        Fp(x.reduce_once_assert())
    }

    #[inline]
    pub fn prime() -> u128 {
        P
    }
}

impl From<u128> for Fp {
    #[inline]
    fn from(x: u128) -> Self {
        Fp::new(x)
    }
}

impl From<Fp> for u128 {
    #[inline]
    fn from(x: Fp) -> u128 {
        let red = x.0.reduce_once_assert();
        if red == P { 0 } else { red }
    }
}

impl Neg for Fp {
    type Output = Self;
    #[inline]
    fn neg(self) -> Self {
        Fp(P - self.0)
    }
}

impl Add for Fp {
    type Output = Self;
    fn add(self, other: Self) -> Self {
        Fp((self.0 + other.0).reduce_once_assert())
    }
}

impl AddAssign for Fp {
    #[inline]
    fn add_assign(&mut self, other: Self) {
        *self = *self + other
    }
}

impl Sub for Fp {
    type Output = Self;
    #[inline]
    fn sub(self, other: Self) -> Self {
        self + (-other)
    }
}

impl SubAssign for Fp {
    #[inline]
    fn sub_assign(&mut self, other: Self) {
        *self = *self - other
    }
}

impl Mul for Fp {
    type Output = Self;
    #[inline]
    fn mul(self, other: Self) -> Self {
        let (sh, sl) = as_limbs(self.0);
        let (oh, ol) = as_limbs(other.0);

        // (64 bits * 63 bits) + (64 bits * 63 bits) = 128 bits
        let m: u128 = (sh as u128 * ol as u128) + (oh as u128 * sl as u128);
        let (mh, ml) = as_limbs(m);

        // (64 bits * 64 bits) + 128 bits = 129 bits
        let (rl, carry) = (sl as u128 * ol as u128).overflowing_add((ml as u128) << 64);

        // (63 bits * 63 bits) + 64 bits + 1 bit = 127 bits
        let rh: u128 = (sh as u128 * oh as u128) + (mh as u128) + (carry as u128);

        Fp((rh, rl).reduce_once().reduce_once_assert())
    }
}

impl MulAssign for Fp {
    #[inline]
    fn mul_assign(&mut self, other: Self) {
        *self = *self * other
    }
}

impl PartialEq for Fp {
    fn eq(&self, other: &Self) -> bool {
        u128::from(*self) == u128::from(*other)
    }
}

impl Eq for Fp {}

mod tests {
    use super::*;

    #[test]
    fn neg() {
        assert_eq!(-Fp(0), Fp(0));
        assert_eq!(-Fp(5), Fp(P - 5));
    }

    #[test]
    fn add() {
        assert_eq!(Fp(7) + Fp(5), Fp(12));
        assert_eq!(Fp(P - 2) + Fp(5), Fp(3));
        assert_eq!(
            Fp(75661398932549814984099328258351945610) + Fp(154440289138086217180118920884960981429),
            Fp(59960504610166800432530945427428821312)
        );
    }

    #[test]
    fn sub() {
        assert_eq!(Fp(7) - Fp(5), Fp(2));
        assert_eq!(Fp(4) - Fp(8), Fp(P - 4));
    }

    #[test]
    fn mul() {
        assert_eq!(Fp(4) * Fp(3), Fp(12));
        assert_eq!(Fp(P) * Fp(291298091), Fp(0));
        assert_eq!(
            Fp(14766549069271113692204649107775507741) * Fp(153613967287097206589234951623852979690),
            Fp(113548737858505840193892055835373785352)
        );
        // Two reductions are necessary for the following example.
        assert_eq!(
            Fp(75661398932549814984099328258351945610) * Fp(154440289138086217180118920884960981429),
            Fp(109146875586984049909139102289297416971)
        );
    }

    #[test]
    fn eq() {
        assert_eq!(Fp(0), Fp(P));
        assert!(Fp(17) != Fp(4));
        assert!(Fp(0) != Fp(4));
        assert!(Fp(P) != Fp(17));
    }

    #[test]
    fn assign() {
        let mut a = Fp(17);

        a += Fp(3);
        assert_eq!(a, Fp(20));

        a -= Fp(5);
        assert_eq!(a, Fp(15));

        a *= Fp(2);
        assert_eq!(a, Fp(30));
    }
}
<|endoftext|>