<commit_before>use std::io::Write;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use super::{Result, MvccErrorKind};

const ENC_GROUP_SIZE: usize = 8;
const ENC_MARKER: u8 = b'\xff';
const ENC_PADDING: [u8; ENC_GROUP_SIZE] = [0; ENC_GROUP_SIZE];

// Refer: https://github.com/facebook/mysql-5.6/wiki/MyRocks-record-format#memcomparable-format
fn encode_bytes(key: &[u8]) -> Vec<u8> {
    let cap = key.len() / (ENC_GROUP_SIZE + 1) * (ENC_GROUP_SIZE + 1);
    let mut encoded = Vec::<u8>::with_capacity(cap);
    let len = key.len();
    let mut index = 0;
    while index <= len {
        let remain = len - index;
        let mut pad: usize = 0;
        if remain > ENC_GROUP_SIZE {
            encoded.write(&key[index..index + ENC_GROUP_SIZE]).unwrap();
        } else {
            pad = ENC_GROUP_SIZE - remain;
            encoded.write(&key[index..]).unwrap();
            encoded.write(&ENC_PADDING[..pad]).unwrap();
        }
        encoded.push(ENC_MARKER - (pad as u8));
        index += ENC_GROUP_SIZE;
    }
    encoded
}

fn decode_bytes(data: &[u8]) -> Result<(Vec<u8>, usize)> {
    let mut key = Vec::<u8>::with_capacity(data.len());
    let mut read: usize = 0;
    for chunk in data.chunks(ENC_GROUP_SIZE + 1) {
        if chunk.len() != ENC_GROUP_SIZE + 1 {
            return MvccErrorKind::KeyLength.as_result();
        }
        read += ENC_GROUP_SIZE + 1;

        let (marker, bytes) = chunk.split_last().unwrap();
        let pad_size = (ENC_MARKER - *marker) as usize;
        if pad_size == 0 {
            key.write(bytes).unwrap();
            continue;
        }
        if pad_size > ENC_GROUP_SIZE {
            return MvccErrorKind::KeyPadding.as_result();
        }
        let (bytes, padding) = bytes.split_at(ENC_GROUP_SIZE - pad_size);
        key.write(bytes).unwrap();
        if padding.iter().any(|x| *x != 0) {
            return MvccErrorKind::KeyPadding.as_result();
        }
        return Ok((key, read));
    }
    MvccErrorKind::KeyLength.as_result()
}

pub fn encode_key(key: &[u8], version: u64) -> Vec<u8> {
    let mut v = encode_bytes(key);
    v.write_u64::<BigEndian>(version).unwrap();
    v
}

pub fn decode_key(data: &[u8]) -> Result<(Vec<u8>, u64)> {
    let (key, read_size) = try!(decode_bytes(data));
    match data[read_size..].as_ref().read_u64::<BigEndian>() {
        Ok(ver) => Ok((key, ver)),
        Err(..) => MvccErrorKind::KeyVersion.as_result(),
    }
}

#[cfg(test)]
mod tests {
    use super::{encode_key, encode_bytes, decode_key, decode_bytes};
    use std::cmp::Ordering;

    #[test]
    fn test_enc_dec_bytes() {
        let pairs = vec![(vec![], vec![0, 0, 0, 0, 0, 0, 0, 0, 247]),
                         (vec![1, 2, 3], vec![1, 2, 3, 0, 0, 0, 0, 0, 250]),
                         (vec![0], vec![0, 0, 0, 0, 0, 0, 0, 0, 248]),
                         (vec![1, 2, 3], vec![1, 2, 3, 0, 0, 0, 0, 0, 250]),
                         (vec![1, 2, 3, 0], vec![1, 2, 3, 0, 0, 0, 0, 0, 251]),
                         (vec![1, 2, 3, 4, 5, 6, 7], vec![1, 2, 3, 4, 5, 6, 7, 0, 254]),
                         (vec![0, 0, 0, 0, 0, 0, 0, 0],
                          vec![0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 247]),
                         (vec![1, 2, 3, 4, 5, 6, 7, 8],
                          vec![1, 2, 3, 4, 5, 6, 7, 8, 255, 0, 0, 0, 0, 0, 0, 0, 0, 247]),
                         (vec![1, 2, 3, 4, 5, 6, 7, 8, 9],
                          vec![1, 2, 3, 4, 5, 6, 7, 8, 255, 9, 0, 0, 0, 0, 0, 0, 0, 248])];

        for (x, y) in pairs {
            assert_eq!(encode_bytes(&x), y);
            let (key, size) = decode_bytes(&y).unwrap();
            assert_eq!(key, x);
            assert_eq!(size, y.len());
        }
    }

    #[test]
    fn test_dec_bytes_fail() {
        let invalid_bytes = vec![vec![1, 2, 3, 4],
                                 vec![0, 0, 0, 0, 0, 0, 0, 247],
                                 vec![0, 0, 0, 0, 0, 0, 0, 0, 246],
                                 vec![0, 0, 0, 0, 0, 0, 0, 1, 247],
                                 vec![1, 2, 3, 4, 5, 6, 7, 8, 0],
                                 vec![1, 2, 3, 4, 5, 6, 7, 8, 255, 1],
                                 vec![1, 2, 3, 4, 5, 6, 7, 8, 255, 1, 2, 3, 4, 5, 6, 7, 8],
                                 vec![1, 2, 3, 4, 5, 6, 7, 8, 255, 1, 2, 3, 4, 5, 6, 7, 8, 255],
                                 vec![1, 2, 3, 4, 5, 6, 7, 8, 255, 1, 2, 3, 4, 5, 6, 7, 8, 0]];

        for x in invalid_bytes {
            assert!(decode_bytes(&x).is_err());
        }
    }

    #[test]
    fn test_encode_bytes_compare() {
        let pairs: Vec<(&'static [u8], &'static [u8], _)> = vec![(b"", b"\x00", Ordering::Less),
                 (b"\x00", b"\x00", Ordering::Equal),
                 (b"\xFF", b"\x00", Ordering::Greater),
                 (b"\xFF", b"\xFF\x00", Ordering::Less),
                 (b"a", b"b", Ordering::Less),
                 (b"a", b"\x00", Ordering::Greater),
                 (b"\x00", b"\x01", Ordering::Less),
                 (b"\x00\x01", b"\x00\x00", Ordering::Greater),
                 (b"\x00\x00\x00", b"\x00\x00", Ordering::Greater),
                 (b"\x00\x00\x00", b"\x00\x00", Ordering::Greater),
                 (b"\x00\x00\x00\x00\x00\x00\x00\x00",
                  b"\x00\x00\x00\x00\x00\x00\x00\x00\x00",
                  Ordering::Less),
                 (b"\x01\x02\x03\x00", b"\x01\x02\x03", Ordering::Greater),
                 (b"\x01\x03\x03\x04", b"\x01\x03\x03\x05", Ordering::Less),
                 (b"\x01\x02\x03\x04\x05\x06\x07",
                  b"\x01\x02\x03\x04\x05\x06\x07\x08",
                  Ordering::Less),
                 (b"\x01\x02\x03\x04\x05\x06\x07\x08\x09",
                  b"\x01\x02\x03\x04\x05\x06\x07\x08",
                  Ordering::Greater),
                 (b"\x01\x02\x03\x04\x05\x06\x07\x08\x00",
                  b"\x01\x02\x03\x04\x05\x06\x07\x08",
                  Ordering::Greater)];

        for (x, y, ord) in pairs {
            assert_eq!(encode_bytes(x).cmp(&encode_bytes(y)), ord);
        }
    }

    #[test]
    fn test_encode_key() {
        let pairs: Vec<(&'static [u8], u64)> = vec![
          (b"abc", 0),
          (b"\x00\x00", 100),
        ];

        for (x, y) in pairs {
            let data = encode_key(x, y);
            let (k, ver) = decode_key(&data).unwrap();
            assert_eq!((x, y), (&k as &[u8], ver));
        }
    }

    #[test]
    fn test_key_compare() {
        let a1 = encode_key(b"A", 1);
        let a2 = encode_key(b"A", 2);
        let b1 = encode_key(b"B", 1);
        assert!(a2 > a1);
        assert!(a2 < b1);
    }

    use test::Bencher;

    #[bench]
    fn bench_encode(b: &mut Bencher) {
        let key = [b'x'; 20];
        b.iter(|| encode_bytes(&key));
    }

    #[bench]
    fn bench_decode(b: &mut Bencher) {
        let key = [b'x'; 20];
        let encoded = encode_bytes(&key);
        b.iter(|| decode_bytes(&encoded));
    }
}
<commit_msg>*: address comment<commit_after>use std::io::Write;
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use super::{Result, MvccErrorKind};

const ENC_GROUP_SIZE: usize = 8;
const ENC_MARKER: u8 = b'\xff';
const ENC_PADDING: [u8; ENC_GROUP_SIZE] = [0; ENC_GROUP_SIZE];

// Refer: https://github.com/facebook/mysql-5.6/wiki/MyRocks-record-format#memcomparable-format
fn encode_bytes(key: &[u8]) -> Vec<u8> {
    let cap = key.len() / (ENC_GROUP_SIZE + 1) * (ENC_GROUP_SIZE + 1);
    let mut encoded = Vec::<u8>::with_capacity(cap);
    let len = key.len();
    let mut index = 0;
    while index <= len {
        let remain = len - index;
        let mut pad: usize = 0;
        if remain > ENC_GROUP_SIZE {
            encoded.write(&key[index..index + ENC_GROUP_SIZE]).unwrap();
        } else {
            pad = ENC_GROUP_SIZE - remain;
            encoded.write(&key[index..]).unwrap();
            encoded.write(&ENC_PADDING[..pad]).unwrap();
        }
        encoded.push(ENC_MARKER - (pad as u8));
        index += ENC_GROUP_SIZE;
    }
    encoded
}

fn decode_bytes(data: &[u8]) -> Result<(Vec<u8>, usize)> {
    let mut key = Vec::<u8>::with_capacity(data.len());
    let mut read: usize = 0;
    for chunk in data.chunks(ENC_GROUP_SIZE + 1) {
        if chunk.len() != ENC_GROUP_SIZE + 1 {
            return MvccErrorKind::KeyLength.as_result();
        }
        read += ENC_GROUP_SIZE + 1;

        let (marker, bytes) = chunk.split_last().unwrap();
        let pad_size = (ENC_MARKER - *marker) as usize;
        if pad_size == 0 {
            key.write(bytes).unwrap();
            continue;
        }
        if pad_size > ENC_GROUP_SIZE {
            return MvccErrorKind::KeyPadding.as_result();
        }
        let (bytes, padding) = bytes.split_at(ENC_GROUP_SIZE - pad_size);
        key.write(bytes).unwrap();
        if padding.iter().any(|x| *x != 0) {
            return MvccErrorKind::KeyPadding.as_result();
        }
        return Ok((key, read));
    }
    MvccErrorKind::KeyLength.as_result()
}

pub fn encode_key(key: &[u8], version: u64) -> Vec<u8> {
    let mut v = encode_bytes(key);
    v.write_u64::<BigEndian>(version).unwrap();
    v
}

pub fn decode_key(data: &[u8]) -> Result<(Vec<u8>, u64)> {
    let (key, read_size) = try!(decode_bytes(data));
    match data[read_size..].as_ref().read_u64::<BigEndian>() {
        Ok(ver) => Ok((key, ver)),
        Err(..) => MvccErrorKind::KeyVersion.as_result(),
    }
}

#[cfg(test)]
mod tests {
    use super::{encode_key, encode_bytes, decode_key, decode_bytes};
    use std::cmp::Ordering;

    #[test]
    fn test_enc_dec_bytes() {
        let pairs = vec![(vec![], vec![0, 0, 0, 0, 0, 0, 0, 0, 247]),
                         (vec![1, 2, 3], vec![1, 2, 3, 0, 0, 0, 0, 0, 250]),
                         (vec![0], vec![0, 0, 0, 0, 0, 0, 0, 0, 248]),
                         (vec![1, 2, 3], vec![1, 2, 3, 0, 0, 0, 0, 0, 250]),
                         (vec![1, 2, 3, 0], vec![1, 2, 3, 0, 0, 0, 0, 0, 251]),
                         (vec![1, 2, 3, 4, 5, 6, 7], vec![1, 2, 3, 4, 5, 6, 7, 0, 254]),

                         (vec![0, 0, 0, 0, 0, 0, 0, 0],
                          vec![0, 0, 0, 0, 0, 0, 0, 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 247]),

                         (vec![1, 2, 3, 4, 5, 6, 7, 8],
                          vec![1, 2, 3, 4, 5, 6, 7, 8, 255, 0, 0, 0, 0, 0, 0, 0, 0, 247]),

                         (vec![1, 2, 3, 4, 5, 6, 7, 8, 9],
                          vec![1, 2, 3, 4, 5, 6, 7, 8, 255, 9, 0, 0, 0, 0, 0, 0, 0, 248])];

        for (x, y) in pairs {
            assert_eq!(encode_bytes(&x), y);
            let (key, size) = decode_bytes(&y).unwrap();
            assert_eq!(key, x);
            assert_eq!(size, y.len());
        }
    }

    #[test]
    fn test_dec_bytes_fail() {
        let invalid_bytes = vec![vec![1, 2, 3, 4],
                                 vec![0, 0, 0, 0, 0, 0, 0, 247],
                                 vec![0, 0, 0, 0, 0, 0, 0, 0, 246],
                                 vec![0, 0, 0, 0, 0, 0, 0, 1, 247],
                                 vec![1, 2, 3, 4, 5, 6, 7, 8, 0],
                                 vec![1, 2, 3, 4, 5, 6, 7, 8, 255, 1],
                                 vec![1, 2, 3, 4, 5, 6, 7, 8, 255, 1, 2, 3, 4, 5, 6, 7, 8],
                                 vec![1, 2, 3, 4, 5, 6, 7, 8, 255, 1, 2, 3, 4, 5, 6, 7, 8, 255],
                                 vec![1, 2, 3, 4, 5, 6, 7, 8, 255, 1, 2, 3, 4, 5, 6, 7, 8, 0]];

        for x in invalid_bytes {
            assert!(decode_bytes(&x).is_err());
        }
    }

    #[test]
    fn test_encode_bytes_compare() {
        let pairs: Vec<(&'static [u8], &'static [u8], _)> = vec![(b"", b"\x00", Ordering::Less),
                 (b"\x00", b"\x00", Ordering::Equal),
                 (b"\xFF", b"\x00", Ordering::Greater),
                 (b"\xFF", b"\xFF\x00", Ordering::Less),
                 (b"a", b"b", Ordering::Less),
                 (b"a", b"\x00", Ordering::Greater),
                 (b"\x00", b"\x01", Ordering::Less),
                 (b"\x00\x01", b"\x00\x00", Ordering::Greater),
                 (b"\x00\x00\x00", b"\x00\x00", Ordering::Greater),
                 (b"\x00\x00\x00", b"\x00\x00", Ordering::Greater),

                 (b"\x00\x00\x00\x00\x00\x00\x00\x00",
                  b"\x00\x00\x00\x00\x00\x00\x00\x00\x00",
                  Ordering::Less),

                 (b"\x01\x02\x03\x00", b"\x01\x02\x03", Ordering::Greater),
                 (b"\x01\x03\x03\x04", b"\x01\x03\x03\x05", Ordering::Less),

                 (b"\x01\x02\x03\x04\x05\x06\x07",
                  b"\x01\x02\x03\x04\x05\x06\x07\x08",
                  Ordering::Less),

                 (b"\x01\x02\x03\x04\x05\x06\x07\x08\x09",
                  b"\x01\x02\x03\x04\x05\x06\x07\x08",
                  Ordering::Greater),

                 (b"\x01\x02\x03\x04\x05\x06\x07\x08\x00",
                  b"\x01\x02\x03\x04\x05\x06\x07\x08",
                  Ordering::Greater)];

        for (x, y, ord) in pairs {
            assert_eq!(encode_bytes(x).cmp(&encode_bytes(y)), ord);
        }
    }

    #[test]
    fn test_encode_key() {
        let pairs: Vec<(&'static [u8], u64)> = vec![
          (b"abc", 0),
          (b"\x00\x00", 100),
        ];

        for (x, y) in pairs {
            let data = encode_key(x, y);
            let (k, ver) = decode_key(&data).unwrap();
            assert_eq!((x, y), (&k as &[u8], ver));
        }
    }

    #[test]
    fn test_key_compare() {
        let a1 = encode_key(b"A", 1);
        let a2 = encode_key(b"A", 2);
        let b1 = encode_key(b"B", 1);
        assert!(a2 > a1);
        assert!(a2 < b1);
    }

    use test::Bencher;

    #[bench]
    fn bench_encode(b: &mut Bencher) {
        let key = [b'x'; 20];
        b.iter(|| encode_bytes(&key));
    }

    #[bench]
    fn bench_decode(b: &mut Bencher) {
        let key = [b'x'; 20];
        let encoded = encode_bytes(&key);
        b.iter(|| decode_bytes(&encoded));
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-stage0
// ignore-stage1

// ignore-emscripten

#![feature(i128_type, test)]

extern crate test;
use test::black_box as b;

fn main() {
    let x: u128 = 0xFFFF_FFFF_FFFF_FFFF__FFFF_FFFF_FFFF_FFFF;
    assert_eq!(0, !x);
    assert_eq!(0, !x);
    let y: u128 = 0xFFFF_FFFF_FFFF_FFFF__FFFF_FFFF_FFFF_FFFE;
    assert_eq!(!1, y);
    assert_eq!(x, y | 1);
    assert_eq!(0xFAFF_0000_FF8F_0000__FFFF_0000_FFFF_FFFE,
               y &
               0xFAFF_0000_FF8F_0000__FFFF_0000_FFFF_FFFF);
    let z: u128 = 0xABCD_EF;
    assert_eq!(z * z, 0x734C_C2F2_A521);
    assert_eq!(z * z * z * z, 0x33EE_0E2A_54E2_59DA_A0E7_8E41);
    assert_eq!(z + z + z + z, 0x2AF3_7BC);
    let k: u128 = 0x1234_5678_9ABC_DEFF_EDCB_A987_6543_210;
    assert_eq!(k + k, 0x2468_ACF1_3579_BDFF_DB97_530E_CA86_420);
    assert_eq!(0, k - k);
    assert_eq!(0x1234_5678_9ABC_DEFF_EDCB_A987_5A86_421, k - z);
    assert_eq!(0x1000_0000_0000_0000_0000_0000_0000_000,
               k - 0x234_5678_9ABC_DEFF_EDCB_A987_6543_210);
    assert_eq!(0x6EF5_DE4C_D3BC_2AAA_3BB4_CC5D_D6EE_8, k / 42);
    assert_eq!(0, k % 42);
    assert_eq!(15, z % 42);
    assert_eq!(0x169D_A8020_CEC18, k % 0x3ACB_FE49_FF24_AC);
    assert_eq!(0x91A2_B3C4_D5E6_F7, k >> 65);
    assert_eq!(0xFDB9_7530_ECA8_6420_0000_0000_0000_0000, k << 65);
    assert!(k > z);
    assert!(y > k);
    assert!(y < x);
    assert_eq!(x as u64, !0);
    assert_eq!(z as u64, 0xABCD_EF);
    assert_eq!(k as u64, 0xFEDC_BA98_7654_3210);
    assert_eq!(k as i128, 0x1234_5678_9ABC_DEFF_EDCB_A987_6543_210);
    assert_eq!((z as f64) as u128, z);
    assert_eq!((z as f32) as u128, z);
    assert_eq!((z as f64 * 16.0) as u128, z * 16);
    assert_eq!((z as f32 * 16.0) as u128, z * 16);
    let l :u128 = 432 << 100;
    assert_eq!((l as f32) as u128, l);
    assert_eq!((l as f64) as u128, l);
    // formatting
    let j: u128 = 1 << 67;
    assert_eq!("147573952589676412928", format!("{}", j));
    assert_eq!("80000000000000000", format!("{:x}", j));
    assert_eq!("20000000000000000000000", format!("{:o}", j));
    assert_eq!("10000000000000000000000000000000000000000000000000000000000000000000",
               format!("{:b}", j));
    assert_eq!("340282366920938463463374607431768211455",
        format!("{}", u128::max_value()));
    assert_eq!("147573952589676412928", format!("{:?}", j));
    // common traits
    assert_eq!(x, b(x.clone()));
    // overflow checks
    assert_eq!((z).checked_mul(z), Some(0x734C_C2F2_A521));
    assert_eq!((k).checked_mul(k), None);
    let l: u128 = b(u128::max_value() - 10);
    let o: u128 = b(17);
    assert_eq!(l.checked_add(b(11)), None);
    assert_eq!(l.checked_sub(l), Some(0));
    assert_eq!(o.checked_sub(b(18)), None);
    assert_eq!(b(1u128).checked_shl(b(127)), Some(1 << 127));
    assert_eq!(o.checked_shl(b(128)), None);
}
<commit_msg>Unignore u128 test for stage 0,1<commit_after>// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-emscripten

#![feature(i128_type, test)]

extern crate test;
use test::black_box as b;

fn main() {
    let x: u128 = 0xFFFF_FFFF_FFFF_FFFF__FFFF_FFFF_FFFF_FFFF;
    assert_eq!(0, !x);
    assert_eq!(0, !x);
    let y: u128 = 0xFFFF_FFFF_FFFF_FFFF__FFFF_FFFF_FFFF_FFFE;
    assert_eq!(!1, y);
    assert_eq!(x, y | 1);
    assert_eq!(0xFAFF_0000_FF8F_0000__FFFF_0000_FFFF_FFFE,
               y &
               0xFAFF_0000_FF8F_0000__FFFF_0000_FFFF_FFFF);
    let z: u128 = 0xABCD_EF;
    assert_eq!(z * z, 0x734C_C2F2_A521);
    assert_eq!(z * z * z * z, 0x33EE_0E2A_54E2_59DA_A0E7_8E41);
    assert_eq!(z + z + z + z, 0x2AF3_7BC);
    let k: u128 = 0x1234_5678_9ABC_DEFF_EDCB_A987_6543_210;
    assert_eq!(k + k, 0x2468_ACF1_3579_BDFF_DB97_530E_CA86_420);
    assert_eq!(0, k - k);
    assert_eq!(0x1234_5678_9ABC_DEFF_EDCB_A987_5A86_421, k - z);
    assert_eq!(0x1000_0000_0000_0000_0000_0000_0000_000,
               k - 0x234_5678_9ABC_DEFF_EDCB_A987_6543_210);
    assert_eq!(0x6EF5_DE4C_D3BC_2AAA_3BB4_CC5D_D6EE_8, k / 42);
    assert_eq!(0, k % 42);
    assert_eq!(15, z % 42);
    assert_eq!(0x169D_A8020_CEC18, k % 0x3ACB_FE49_FF24_AC);
    assert_eq!(0x91A2_B3C4_D5E6_F7, k >> 65);
    assert_eq!(0xFDB9_7530_ECA8_6420_0000_0000_0000_0000, k << 65);
    assert!(k > z);
    assert!(y > k);
    assert!(y < x);
    assert_eq!(x as u64, !0);
    assert_eq!(z as u64, 0xABCD_EF);
    assert_eq!(k as u64, 0xFEDC_BA98_7654_3210);
    assert_eq!(k as i128, 0x1234_5678_9ABC_DEFF_EDCB_A987_6543_210);
    assert_eq!((z as f64) as u128, z);
    assert_eq!((z as f32) as u128, z);
    assert_eq!((z as f64 * 16.0) as u128, z * 16);
    assert_eq!((z as f32 * 16.0) as u128, z * 16);
    let l :u128 = 432 << 100;
    assert_eq!((l as f32) as u128, l);
    assert_eq!((l as f64) as u128, l);
    // formatting
    let j: u128 = 1 << 67;
    assert_eq!("147573952589676412928", format!("{}", j));
    assert_eq!("80000000000000000", format!("{:x}", j));
    assert_eq!("20000000000000000000000", format!("{:o}", j));
    assert_eq!("10000000000000000000000000000000000000000000000000000000000000000000",
               format!("{:b}", j));
    assert_eq!("340282366920938463463374607431768211455",
        format!("{}", u128::max_value()));
    assert_eq!("147573952589676412928", format!("{:?}", j));
    // common traits
    assert_eq!(x, b(x.clone()));
    // overflow checks
    assert_eq!((z).checked_mul(z), Some(0x734C_C2F2_A521));
    assert_eq!((k).checked_mul(k), None);
    let l: u128 = b(u128::max_value() - 10);
    let o: u128 = b(17);
    assert_eq!(l.checked_add(b(11)), None);
    assert_eq!(l.checked_sub(l), Some(0));
    assert_eq!(o.checked_sub(b(18)), None);
    assert_eq!(b(1u128).checked_shl(b(127)), Some(1 << 127));
    assert_eq!(o.checked_shl(b(128)), None);
}
<|endoftext|>


<commit_before>extern crate url;

use page::Page;
use self::url::Url;

type ErrorMsg = String;
type UrlResult = Result<String, ErrorMsg>;

fn parse_github_url(user: &str, repo: &str, branch: &String, page: &Page) -> String {
    match page {
        &Page::Open => format!("https://github.com/{}/{}/tree/{}", user, repo, branch),
        &Page::Diff {ref lhs, ref rhs} => format!("https://github.com/{}/{}/compare/{}...{}", user, repo, lhs, rhs),
        &Page::Commit {ref hash} => format!("https://github.com/{}/{}/commit/{}", user, repo, hash),
        &Page::FileOrDir {ref relative_path, ref hash} => format!("https://github.com/{}/{}/blob/{}/{}", user, repo, hash, relative_path),
    }
}

fn parse_bitbucket_url(user: &str, repo: &str, branch: &String, page: &Page) -> UrlResult {
    match page {
        &Page::Open => Ok(format!("https://bitbucket.org/{}/{}/branch/{}", user, repo, branch)),
        &Page::Diff {..} => Err("BitBucket does not support diff between commits (see https://bitbucket.org/site/master/issues/4779/ability-to-diff-between-any-two-commits)".to_string()),
        &Page::Commit {ref hash} => Ok(format!("https://bitbucket.org/{}/{}/commits/{}", user, repo, hash)),
        &Page::FileOrDir {ref relative_path, ref hash} => Ok(format!("https://bitbucket.org/{}/{}/src/{}/{}", user, repo, hash, relative_path)),
    }
}

// Note: Parse '/user/repo.git' or '/user/repo' or 'user/repo' into 'user' and 'repo'
fn user_and_repo_from_path<'a>(path: &'a str) -> Result<(&'a str, &'a str), ErrorMsg> {
    let mut split = path.split('/').skip_while(|s| s.is_empty());
    let user = split.next().ok_or(format!("Can't detect user name from path {}", path))?;
    let mut repo = split.next().ok_or(format!("Can't detect repository name from path {}", path))?;
    if repo.ends_with(".git") {
        // Slice '.git' from 'repo.git'
        repo = &repo[0 .. repo.len() - 4];
    }
    Ok((user, repo))
}

// Known URLs
//
// GitHub:
//  https://github.com/user/repo.git
//  git@github.com:user/repo.git (-> ssh://git@github.com:22/user/repo.git)
pub fn parse_url(repo: &String, branch: &String, page: &Page) -> UrlResult {
    let url = Url::parse(repo).map_err(|e| format!("{}", e))?;
    let path = url.path();
    let (user, repo) = user_and_repo_from_path(path)?;
    let host = url.host_str().ok_or(format!("Failed to parse host from {}", repo))?;
    match host {
        "github.com" => Ok(parse_github_url(user, repo, branch, page)),
        "bitbucket.org" => parse_bitbucket_url(user, repo, branch, page),
        _ => Err(format!("Unknown hosting service for URL {}", repo)),
    }
}
<commit_msg>support GitHub Enterprise<commit_after>extern crate url;

use page::Page;
use self::url::Url;

type ErrorMsg = String;
type UrlResult = Result<String, ErrorMsg>;

fn parse_github_url(user: &str, repo: &str, branch: &String, page: &Page) -> String {
    match page {
        &Page::Open => format!("https://github.com/{}/{}/tree/{}", user, repo, branch),
        &Page::Diff {ref lhs, ref rhs} => format!("https://github.com/{}/{}/compare/{}...{}", user, repo, lhs, rhs),
        &Page::Commit {ref hash} => format!("https://github.com/{}/{}/commit/{}", user, repo, hash),
        &Page::FileOrDir {ref relative_path, ref hash} => format!("https://github.com/{}/{}/blob/{}/{}", user, repo, hash, relative_path),
    }
}

fn parse_bitbucket_url(user: &str, repo: &str, branch: &String, page: &Page) -> UrlResult {
    match page {
        &Page::Open => Ok(format!("https://bitbucket.org/{}/{}/branch/{}", user, repo, branch)),
        &Page::Diff {..} => Err("BitBucket does not support diff between commits (see https://bitbucket.org/site/master/issues/4779/ability-to-diff-between-any-two-commits)".to_string()),
        &Page::Commit {ref hash} => Ok(format!("https://bitbucket.org/{}/{}/commits/{}", user, repo, hash)),
        &Page::FileOrDir {ref relative_path, ref hash} => Ok(format!("https://bitbucket.org/{}/{}/src/{}/{}", user, repo, hash, relative_path)),
    }
}

fn parse_github_enterprise_url(host: &str, user: &str, repo: &str, branch: &String, page: &Page) -> String {
    match page {
        &Page::Open => format!("https://{}/{}/{}/tree/{}", host, user, repo, branch),
        &Page::Diff {ref lhs, ref rhs} => format!("https://{}/{}/{}/compare/{}...{}", host, user, repo, lhs, rhs),
        &Page::Commit {ref hash} => format!("https://{}/{}/{}/commit/{}", host, user, repo, hash),
        &Page::FileOrDir {ref relative_path, ref hash} => format!("https://{}/{}/{}/blob/{}/{}", host, user, repo, hash, relative_path),
    }
}

// Note: Parse '/user/repo.git' or '/user/repo' or 'user/repo' into 'user' and 'repo'
fn user_and_repo_from_path<'a>(path: &'a str) -> Result<(&'a str, &'a str), ErrorMsg> {
    let mut split = path.split('/').skip_while(|s| s.is_empty());
    let user = split.next().ok_or(format!("Can't detect user name from path {}", path))?;
    let mut repo = split.next().ok_or(format!("Can't detect repository name from path {}", path))?;
    if repo.ends_with(".git") {
        // Slice '.git' from 'repo.git'
        repo = &repo[0 .. repo.len() - 4];
    }
    Ok((user, repo))
}

// Known URLs
//
// GitHub:
//  https://github.com/user/repo.git
//  git@github.com:user/repo.git (-> ssh://git@github.com:22/user/repo.git)
pub fn parse_url(repo: &String, branch: &String, page: &Page) -> UrlResult {
    let url = Url::parse(repo).map_err(|e| format!("{}", e))?;
    let path = url.path();
    let (user, repo_name) = user_and_repo_from_path(path)?;
    let host = url.host_str().ok_or(format!("Failed to parse host from {}", repo))?;
    match host {
        "github.com" => Ok(parse_github_url(user, repo_name, branch, page)),
        "bitbucket.org" => parse_bitbucket_url(user, repo_name, branch, page),
        host => if host.starts_with("github.") {
            Ok(parse_github_enterprise_url(host, user, repo_name, branch, page))
        } else {
            Err(format!("Unknown hosting service for URL {}", repo))
        },
    }
}
<|endoftext|>


<commit_before>#![allow(non_snake_case)]

#[deriving(Decodable, Show)]
pub struct Node {
    Node: String,
    Address: String,
}

#[deriving(Decodable, Show)]
pub struct Service {
    ID: String,
    Service: String,
    Tags: Vec<String>,
    Port: int,
}
<commit_msg>change service field from private to pub<commit_after>#![allow(non_snake_case)]

#[deriving(Decodable, Show)]
pub struct Node {
    Node: String,
    Address: String,
}

#[deriving(Decodable, Show)]
pub struct Service {
    ID: String,
    pub Service: String,
    pub Tags: Vec<String>,
    pub Port: int,
}
<|endoftext|>


<commit_before>use std::time::{SystemTime, UNIX_EPOCH};

#[macro_use]
pub mod util;

pub mod asset;
pub mod crypto;
pub mod tx;

pub mod blockchain;
pub mod constants;
pub mod net;
pub mod script;
pub mod serializer;

pub fn init() -> Result<(), ()> {
    sodiumoxide::init()
}

pub fn get_epoch_ms() -> u64 {
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .as_millis() as u64
}

pub mod prelude {
    pub use super::asset::{self, Asset, AssetError, AssetErrorKind};
    pub use super::blockchain::{
        index::IndexStatus, verify, AddressInfo, Block, Blockchain, Properties, SignedBlock,
    };
    pub use super::crypto::{
        KeyPair, PrivateKey, PublicKey, ScriptHash, SigPair, Wif, WifError, WifErrorKind,
    };
    pub use super::net::{self, MsgRequest, MsgResponse};
    pub use super::script::{self, OpFrame, Script, ScriptEngine};
    pub use super::tx::{
        MintTx, OwnerTx, RewardTx, SignTx, TransferTx, Tx, TxId, TxPool, TxPrecompData, TxType,
        TxVariant,
    };
}
<commit_msg>Remove util declaration from lib<commit_after>use std::time::{SystemTime, UNIX_EPOCH};

pub mod asset;
pub mod crypto;
pub mod tx;

pub mod blockchain;
pub mod constants;
pub mod net;
pub mod script;
pub mod serializer;

pub fn init() -> Result<(), ()> {
    sodiumoxide::init()
}

pub fn get_epoch_ms() -> u64 {
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .as_millis() as u64
}

pub mod prelude {
    pub use super::asset::{self, Asset, AssetError, AssetErrorKind};
    pub use super::blockchain::{
        index::IndexStatus, verify, AddressInfo, Block, Blockchain, Properties, SignedBlock,
    };
    pub use super::crypto::{
        KeyPair, PrivateKey, PublicKey, ScriptHash, SigPair, Wif, WifError, WifErrorKind,
    };
    pub use super::net::{self, MsgRequest, MsgResponse};
    pub use super::script::{self, OpFrame, Script, ScriptEngine};
    pub use super::tx::{
        MintTx, OwnerTx, RewardTx, SignTx, TransferTx, Tx, TxId, TxPool, TxPrecompData, TxType,
        TxVariant,
    };
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::ErrorKind::UnexpectedEof;

#[cfg(feature = "zstd")]
use zstd::block::decompress;

use super::Pio;

use super::*;

pub(crate) trait LogReader {
    fn read_segment_header(&self, id: LogID) -> std::io::Result<SegmentHeader>;

    fn read_segment_trailer(
        &self,
        id: LogID,
    ) -> std::io::Result<SegmentTrailer>;

    fn read_message_header(&self, id: LogID) -> std::io::Result<MessageHeader>;

    fn read_message(
        &self,
        id: LogID,
        segment_len: usize,
        use_compression: bool,
    ) -> std::io::Result<LogRead>;
}

#[cfg(unix)]
impl LogReader for File {
    fn read_segment_header(
        &self,
        lid: LogID,
    ) -> std::io::Result<SegmentHeader> {
        trace!("reading segment header at {}", lid);

        let mut seg_header_buf = [0u8; SEG_HEADER_LEN];
        self.pread_exact(&mut seg_header_buf, lid)?;

        Ok(seg_header_buf.into())
    }

    fn read_segment_trailer(
        &self,
        lid: LogID,
    ) -> std::io::Result<SegmentTrailer> {
        trace!("reading segment trailer at {}", lid);

        let mut seg_trailer_buf = [0u8; SEG_TRAILER_LEN];
        self.pread_exact(&mut seg_trailer_buf, lid)?;

        Ok(seg_trailer_buf.into())
    }

    fn read_message_header(
        &self,
        lid: LogID,
    ) -> std::io::Result<MessageHeader> {
        let mut msg_header_buf = [0u8; MSG_HEADER_LEN];
        self.pread_exact(&mut msg_header_buf, lid)?;

        Ok(msg_header_buf.into())
    }

    /// read a buffer from the disk
    fn read_message(
        &self,
        lid: LogID,
        segment_len: usize,
        _use_compression: bool,
    ) -> std::io::Result<LogRead> {
        let _measure = Measure::new(&M.read);
        let seg_start = lid / segment_len as LogID * segment_len as LogID;
        trace!("reading message from segment: {} at lid: {}", seg_start, lid);
        assert!(seg_start + MSG_HEADER_LEN as LogID <= lid);

        let ceiling = seg_start + segment_len as LogID -
            SEG_TRAILER_LEN as LogID;

        assert!(lid + MSG_HEADER_LEN as LogID <= ceiling);

        let header = self.read_message_header(lid)?;

        let max_possible_len = (ceiling - lid - MSG_HEADER_LEN as LogID) as
            usize;
        if header.len > max_possible_len {
            error!(
                "log read invalid message length, {} should be <= {}",
                header.len,
                max_possible_len
            );
            trace!("read a corrupted message of len {}", header.len);
            return Ok(LogRead::Corrupted(header.len));
        }

        let mut len = header.len;
        if !header.successful_flush {
            len = MSG_HEADER_LEN;
            // skip to next record, which starts with 1
            while len <= max_possible_len {
                let mut byte = [0u8; 1];
                if let Err(e) = self.pread_exact(
                    &mut byte,
                    lid + len as LogID,
                )
                {
                    if e.kind() == UnexpectedEof {
                        // we've hit the end of the file
                        break;
                    }
                    panic!("{:?}", e);
                }
                if byte[0] != 1 {
                    len += 1;
                } else {
                    break;
                }
            }
        }

        if !header.successful_flush {
            trace!("read zeroes of len {}", len);
            return Ok(LogRead::Zeroed(len));
        }

        let mut buf = Vec::with_capacity(len);
        unsafe {
            buf.set_len(len);
        }
        self.pread_exact(&mut buf, lid + MSG_HEADER_LEN as LogID)?;

        let checksum = crc16_arr(&buf);
        if checksum != header.crc16 {
            trace!("read a message with a bad checksum of len {}", len);
            return Ok(LogRead::Corrupted(len));
        }

        #[cfg(feature = "zstd")]
        let res = {
            if _use_compression {
                let _measure = Measure::new(&M.decompress);
                Ok(LogRead::Flush(
                    header.lsn,
                    decompress(&*buf, segment_len).unwrap(),
                    len,
                ))
            } else {
                Ok(LogRead::Flush(header.lsn, buf, len))
            }
        };

        #[cfg(not(feature = "zstd"))]
        let res = Ok(LogRead::Flush(header.lsn, buf, len));

        trace!("read a successful flushed message");
        res
    }
}
<commit_msg>fix bug in the validation of reads on segments<commit_after>use std::fs::File;
use std::io::ErrorKind::UnexpectedEof;

#[cfg(feature = "zstd")]
use zstd::block::decompress;

use super::Pio;

use super::*;

pub(crate) trait LogReader {
    fn read_segment_header(&self, id: LogID) -> std::io::Result<SegmentHeader>;

    fn read_segment_trailer(
        &self,
        id: LogID,
    ) -> std::io::Result<SegmentTrailer>;

    fn read_message_header(&self, id: LogID) -> std::io::Result<MessageHeader>;

    fn read_message(
        &self,
        id: LogID,
        segment_len: usize,
        use_compression: bool,
    ) -> std::io::Result<LogRead>;
}

#[cfg(unix)]
impl LogReader for File {
    fn read_segment_header(
        &self,
        lid: LogID,
    ) -> std::io::Result<SegmentHeader> {
        trace!("reading segment header at {}", lid);

        let mut seg_header_buf = [0u8; SEG_HEADER_LEN];
        self.pread_exact(&mut seg_header_buf, lid)?;

        Ok(seg_header_buf.into())
    }

    fn read_segment_trailer(
        &self,
        lid: LogID,
    ) -> std::io::Result<SegmentTrailer> {
        trace!("reading segment trailer at {}", lid);

        let mut seg_trailer_buf = [0u8; SEG_TRAILER_LEN];
        self.pread_exact(&mut seg_trailer_buf, lid)?;

        Ok(seg_trailer_buf.into())
    }

    fn read_message_header(
        &self,
        lid: LogID,
    ) -> std::io::Result<MessageHeader> {
        let mut msg_header_buf = [0u8; MSG_HEADER_LEN];
        self.pread_exact(&mut msg_header_buf, lid)?;

        Ok(msg_header_buf.into())
    }

    /// read a buffer from the disk
    fn read_message(
        &self,
        lid: LogID,
        segment_len: usize,
        _use_compression: bool,
    ) -> std::io::Result<LogRead> {
        let _measure = Measure::new(&M.read);
        let seg_start = lid / segment_len as LogID * segment_len as LogID;
        trace!("reading message from segment: {} at lid: {}", seg_start, lid);
        assert!(seg_start + SEG_HEADER_LEN as LogID <= lid);

        let ceiling = seg_start + segment_len as LogID -
            SEG_TRAILER_LEN as LogID;

        assert!(lid + MSG_HEADER_LEN as LogID <= ceiling);

        let header = self.read_message_header(lid)?;

        let max_possible_len = (ceiling - lid - MSG_HEADER_LEN as LogID) as
            usize;
        if header.len > max_possible_len {
            error!(
                "log read invalid message length, {} should be <= {}",
                header.len,
                max_possible_len
            );
            trace!("read a corrupted message of len {}", header.len);
            return Ok(LogRead::Corrupted(header.len));
        }

        let mut len = header.len;
        if !header.successful_flush {
            len = MSG_HEADER_LEN;
            // skip to next record, which starts with 1
            while len <= max_possible_len {
                let mut byte = [0u8; 1];
                if let Err(e) = self.pread_exact(
                    &mut byte,
                    lid + len as LogID,
                )
                {
                    if e.kind() == UnexpectedEof {
                        // we've hit the end of the file
                        break;
                    }
                    panic!("{:?}", e);
                }
                if byte[0] != 1 {
                    len += 1;
                } else {
                    break;
                }
            }
        }

        if !header.successful_flush {
            trace!("read zeroes of len {}", len);
            return Ok(LogRead::Zeroed(len));
        }

        let mut buf = Vec::with_capacity(len);
        unsafe {
            buf.set_len(len);
        }
        self.pread_exact(&mut buf, lid + MSG_HEADER_LEN as LogID)?;

        let checksum = crc16_arr(&buf);
        if checksum != header.crc16 {
            trace!("read a message with a bad checksum of len {}", len);
            return Ok(LogRead::Corrupted(len));
        }

        #[cfg(feature = "zstd")]
        let res = {
            if _use_compression {
                let _measure = Measure::new(&M.decompress);
                Ok(LogRead::Flush(
                    header.lsn,
                    decompress(&*buf, segment_len).unwrap(),
                    len,
                ))
            } else {
                Ok(LogRead::Flush(header.lsn, buf, len))
            }
        };

        #[cfg(not(feature = "zstd"))]
        let res = Ok(LogRead::Flush(header.lsn, buf, len));

        trace!("read a successful flushed message");
        res
    }
}
<|endoftext|>


<commit_before>extern crate gtk;
extern crate glib;
extern crate gstreamer as gst;

#[cfg(any(feature = "profiling-listener", feature = "profiling-tracker"))]
use chrono::Utc;

use std::rc::Rc;
use std::cell::RefCell;

use std::path::PathBuf;

use std::sync::mpsc::{channel, Receiver};

use gtk::prelude::*;

use media::{Context, ContextMessage};
use media::ContextMessage::*;

use super::{AudioController, DoubleWaveformBuffer, InfoController, VideoController};

pub struct MainController {
    window: gtk::ApplicationWindow,
    header_bar: gtk::HeaderBar,
    play_pause_btn: gtk::ToolButton,

    video_ctrl: VideoController,
    info_ctrl: InfoController,
    audio_ctrl: AudioController,

    context: Option<Context>,
    seeking: bool,

    this_opt: Option<Rc<RefCell<MainController>>>,
    keep_going: bool,
    listener_src: Option<glib::SourceId>,
    tracker_src: Option<glib::SourceId>,
}

impl MainController {
    pub fn new(builder: gtk::Builder) -> Rc<RefCell<Self>> {
        let this = Rc::new(RefCell::new(MainController {
            window: builder.get_object("application-window").unwrap(),
            header_bar: builder.get_object("header-bar").unwrap(),
            play_pause_btn: builder.get_object("play_pause-toolbutton").unwrap(),

            video_ctrl: VideoController::new(&builder),
            info_ctrl: InfoController::new(&builder),
            audio_ctrl: AudioController::new(&builder),

            context: None,
            seeking: false,

            this_opt: None,
            keep_going: true,
            listener_src: None,
            tracker_src: None,
        }));

        {
            let mut this_mut = this.borrow_mut();

            let this_rc = Rc::clone(&this);
            this_mut.this_opt = Some(this_rc);

            this_mut.window.connect_delete_event(|_, _| {
                gtk::main_quit();
                Inhibit(false)
            });
            this_mut.window.set_titlebar(&this_mut.header_bar);

            let this_rc = Rc::clone(&this);
            this_mut.play_pause_btn.connect_clicked(move |_| {
                this_rc.borrow_mut().play_pause();
            });

            this_mut.video_ctrl.register_callbacks(&this);
            this_mut.info_ctrl.register_callbacks(&this);
            this_mut.audio_ctrl.register_callbacks(&this);
        }

        let open_btn: gtk::Button = builder.get_object("open-btn").unwrap();
        let this_rc = Rc::clone(&this);
        open_btn.connect_clicked(move |_| {
            this_rc.borrow_mut().select_media();
        });

        this
    }

    pub fn show_all(&self) {
        self.window.show_all();
    }

    fn play_pause(&mut self) {
        let context =
            match self.context.take() {
                Some(context) => context,
                None => {
                    self.select_media();
                    return;
                },
            };

        match context.get_state() {
            gst::State::Paused => {
                self.register_tracker(17); // 60 Hz
                self.play_pause_btn.set_icon_name("media-playback-pause");
                context.play().unwrap();
            }
            gst::State::Playing => {
                context.pause().unwrap();
                self.play_pause_btn.set_icon_name("media-playback-start");
                self.remove_tracker();
            },
            state => println!("Can't play/pause in state {:?}", state),
        };

        self.context = Some(context);
    }

    fn stop(&mut self) {
        if let Some(context) = self.context.as_mut() {
            context.stop();
        };

        // remove callbacks in order to avoid conflict on borrowing of self
        self.remove_listener();
        self.remove_tracker();

        self.audio_ctrl.cleanup();

        self.play_pause_btn.set_icon_name("media-playback-start");
    }

    pub fn seek(&mut self, position: u64) {
        self.seeking = true;
        self.audio_ctrl.seeking();
        self.context.as_ref()
            .expect("No context found while seeking in media")
            .seek(position);
    }

    fn select_media(&mut self) {
        self.stop();

        let file_dlg = gtk::FileChooserDialog::new(
            Some("Open a media file"),
            Some(&self.window),
            gtk::FileChooserAction::Open,
        );
        // Note: couldn't find equivalents for STOCK_OK
        file_dlg.add_button("Open", gtk::ResponseType::Ok.into());

        if file_dlg.run() == gtk::ResponseType::Ok.into() {
            self.open_media(file_dlg.get_filename().unwrap());
        }

        file_dlg.close();
    }

    fn remove_listener(&mut self) {
        if let Some(source_id) = self.listener_src.take() {
            glib::source_remove(source_id);
        }
    }

    fn register_listener(&mut self,
        timeout: u32,
        ui_rx: Receiver<ContextMessage>,
    ) {
        let this_rc = Rc::clone(self.this_opt.as_ref().unwrap());

        self.listener_src = Some(gtk::timeout_add(timeout, move || {
            let mut keep_going = true;

            for message in ui_rx.try_iter() {
                match message {
                    AsyncDone => {
                        let mut this_mut = this_rc.borrow_mut();
                        let position = this_mut.context.as_mut()
                            .expect("No context in listener while getting position")
                            .get_position();
                        this_mut.info_ctrl.seek(position);
                        this_mut.seeking = false;
                    },
                    InitDone => {
                        let mut this_mut = this_rc.borrow_mut();

                        let context = this_mut.context.take()
                            .expect("MainController: InitDone but no context available");

                        this_mut.header_bar.set_subtitle(
                            Some(context.file_name.as_str())
                        );

                        this_mut.info_ctrl.new_media(&context);
                        this_mut.video_ctrl.new_media(&context);
                        this_mut.audio_ctrl.new_media(&context);

                        this_mut.context = Some(context);
                    },
                    Eos => {
                        let this = this_rc.borrow_mut();

                        this.audio_ctrl.tic();
                        this.play_pause_btn.set_icon_name("media-playback-start");
                    },
                    FailedToOpenMedia => {
                        eprintln!("ERROR: failed to open media");

                        let mut this_mut = this_rc.borrow_mut();

                        this_mut.context = None;
                        this_mut.keep_going = false;
                        keep_going = false;
                    },
                };

                if !keep_going { break; }
            }

            if !keep_going {
                let mut this_mut = this_rc.borrow_mut();
                this_mut.listener_src = None;
                this_mut.tracker_src = None;
            }

            glib::Continue(keep_going)
        }));
    }

    fn remove_tracker(&mut self) {
        if let Some(source_id) = self.tracker_src.take() {
            glib::source_remove(source_id);
        }
    }

    fn register_tracker(&mut self, timeout: u32) {
        let this_rc = Rc::clone(self.this_opt.as_ref().unwrap());

        self.tracker_src = Some(gtk::timeout_add(timeout, move || {
            #[cfg(feature = "profiling-tracker")]
            let start = Utc::now();

            let mut this_mut = this_rc.borrow_mut();

            #[cfg(feature = "profiling-tracker")]
            let before_tic = Utc::now();

            if !this_mut.seeking {
                let position = this_mut.context.as_mut()
                    .expect("No context in tracker while getting position")
                    .get_position();
                this_mut.info_ctrl.tic(position);
            }

            this_mut.audio_ctrl.tic();

            #[cfg(feature = "profiling-tracker")]
            let end = Utc::now();

            #[cfg(feature = "profiling-tracker")]
            println!("tracker,{},{},{},{},{}",
                start.time().format("%H:%M:%S%.6f"),
                before_tic.time().format("%H:%M:%S%.6f"),
                end.time().format("%H:%M:%S%.6f"),
                position,
            );

            glib::Continue(this_mut.keep_going)
        }));
    }

    fn open_media(&mut self, filepath: PathBuf) {
        assert_eq!(self.listener_src, None);

        self.info_ctrl.cleanup();
        self.audio_ctrl.cleanup();
        self.header_bar.set_subtitle("");

        let (ctx_tx, ui_rx) = channel();

        self.seeking = false;
        self.keep_going = true;
        self.register_listener(250, ui_rx);

        match Context::new(
            filepath,
            5_000_000_000,
            DoubleWaveformBuffer::new(&self.audio_ctrl.waveform_buffer_mtx),
            self.video_ctrl.video_box.clone(),
            ctx_tx
        ) {
            Ok(context) => {
                self.context = Some(context);
            },
            Err(error) => eprintln!("Error opening media: {}", error),
        };
    }
}
<commit_msg>Fix profiling (#24)<commit_after>extern crate gtk;
extern crate glib;
extern crate gstreamer as gst;

#[cfg(any(feature = "profiling-listener", feature = "profiling-tracker"))]
use chrono::Utc;

use std::rc::Rc;
use std::cell::RefCell;

use std::path::PathBuf;

use std::sync::mpsc::{channel, Receiver};

use gtk::prelude::*;

use media::{Context, ContextMessage};
use media::ContextMessage::*;

use super::{AudioController, DoubleWaveformBuffer, InfoController, VideoController};

pub struct MainController {
    window: gtk::ApplicationWindow,
    header_bar: gtk::HeaderBar,
    play_pause_btn: gtk::ToolButton,

    video_ctrl: VideoController,
    info_ctrl: InfoController,
    audio_ctrl: AudioController,

    context: Option<Context>,
    seeking: bool,

    this_opt: Option<Rc<RefCell<MainController>>>,
    keep_going: bool,
    listener_src: Option<glib::SourceId>,
    tracker_src: Option<glib::SourceId>,
}

impl MainController {
    pub fn new(builder: gtk::Builder) -> Rc<RefCell<Self>> {
        let this = Rc::new(RefCell::new(MainController {
            window: builder.get_object("application-window").unwrap(),
            header_bar: builder.get_object("header-bar").unwrap(),
            play_pause_btn: builder.get_object("play_pause-toolbutton").unwrap(),

            video_ctrl: VideoController::new(&builder),
            info_ctrl: InfoController::new(&builder),
            audio_ctrl: AudioController::new(&builder),

            context: None,
            seeking: false,

            this_opt: None,
            keep_going: true,
            listener_src: None,
            tracker_src: None,
        }));

        {
            let mut this_mut = this.borrow_mut();

            let this_rc = Rc::clone(&this);
            this_mut.this_opt = Some(this_rc);

            this_mut.window.connect_delete_event(|_, _| {
                gtk::main_quit();
                Inhibit(false)
            });
            this_mut.window.set_titlebar(&this_mut.header_bar);

            let this_rc = Rc::clone(&this);
            this_mut.play_pause_btn.connect_clicked(move |_| {
                this_rc.borrow_mut().play_pause();
            });

            this_mut.video_ctrl.register_callbacks(&this);
            this_mut.info_ctrl.register_callbacks(&this);
            this_mut.audio_ctrl.register_callbacks(&this);
        }

        let open_btn: gtk::Button = builder.get_object("open-btn").unwrap();
        let this_rc = Rc::clone(&this);
        open_btn.connect_clicked(move |_| {
            this_rc.borrow_mut().select_media();
        });

        this
    }

    pub fn show_all(&self) {
        self.window.show_all();
    }

    fn play_pause(&mut self) {
        let context =
            match self.context.take() {
                Some(context) => context,
                None => {
                    self.select_media();
                    return;
                },
            };

        match context.get_state() {
            gst::State::Paused => {
                self.register_tracker(17); // 60 Hz
                self.play_pause_btn.set_icon_name("media-playback-pause");
                context.play().unwrap();
            }
            gst::State::Playing => {
                context.pause().unwrap();
                self.play_pause_btn.set_icon_name("media-playback-start");
                self.remove_tracker();
            },
            state => println!("Can't play/pause in state {:?}", state),
        };

        self.context = Some(context);
    }

    fn stop(&mut self) {
        if let Some(context) = self.context.as_mut() {
            context.stop();
        };

        // remove callbacks in order to avoid conflict on borrowing of self
        self.remove_listener();
        self.remove_tracker();

        self.audio_ctrl.cleanup();

        self.play_pause_btn.set_icon_name("media-playback-start");
    }

    pub fn seek(&mut self, position: u64) {
        self.seeking = true;
        self.audio_ctrl.seeking();
        self.context.as_ref()
            .expect("No context found while seeking in media")
            .seek(position);
    }

    fn select_media(&mut self) {
        self.stop();

        let file_dlg = gtk::FileChooserDialog::new(
            Some("Open a media file"),
            Some(&self.window),
            gtk::FileChooserAction::Open,
        );
        // Note: couldn't find equivalents for STOCK_OK
        file_dlg.add_button("Open", gtk::ResponseType::Ok.into());

        if file_dlg.run() == gtk::ResponseType::Ok.into() {
            self.open_media(file_dlg.get_filename().unwrap());
        }

        file_dlg.close();
    }

    fn remove_listener(&mut self) {
        if let Some(source_id) = self.listener_src.take() {
            glib::source_remove(source_id);
        }
    }

    fn register_listener(&mut self,
        timeout: u32,
        ui_rx: Receiver<ContextMessage>,
    ) {
        let this_rc = Rc::clone(self.this_opt.as_ref().unwrap());

        self.listener_src = Some(gtk::timeout_add(timeout, move || {
            let mut keep_going = true;

            for message in ui_rx.try_iter() {
                match message {
                    AsyncDone => {
                        let mut this_mut = this_rc.borrow_mut();
                        let position = this_mut.context.as_mut()
                            .expect("No context in listener while getting position")
                            .get_position();
                        this_mut.info_ctrl.seek(position);
                        this_mut.seeking = false;
                    },
                    InitDone => {
                        let mut this_mut = this_rc.borrow_mut();

                        let context = this_mut.context.take()
                            .expect("MainController: InitDone but no context available");

                        this_mut.header_bar.set_subtitle(
                            Some(context.file_name.as_str())
                        );

                        this_mut.info_ctrl.new_media(&context);
                        this_mut.video_ctrl.new_media(&context);
                        this_mut.audio_ctrl.new_media(&context);

                        this_mut.context = Some(context);
                    },
                    Eos => {
                        let this = this_rc.borrow_mut();

                        this.audio_ctrl.tic();
                        this.play_pause_btn.set_icon_name("media-playback-start");
                    },
                    FailedToOpenMedia => {
                        eprintln!("ERROR: failed to open media");

                        let mut this_mut = this_rc.borrow_mut();

                        this_mut.context = None;
                        this_mut.keep_going = false;
                        keep_going = false;
                    },
                };

                if !keep_going { break; }
            }

            if !keep_going {
                let mut this_mut = this_rc.borrow_mut();
                this_mut.listener_src = None;
                this_mut.tracker_src = None;
            }

            glib::Continue(keep_going)
        }));
    }

    fn remove_tracker(&mut self) {
        if let Some(source_id) = self.tracker_src.take() {
            glib::source_remove(source_id);
        }
    }

    fn register_tracker(&mut self, timeout: u32) {
        let this_rc = Rc::clone(self.this_opt.as_ref().unwrap());

        self.tracker_src = Some(gtk::timeout_add(timeout, move || {
            #[cfg(feature = "profiling-tracker")]
            let start = Utc::now();

            let mut this_mut = this_rc.borrow_mut();

            #[cfg(feature = "profiling-tracker")]
            let before_tic = Utc::now();

            if !this_mut.seeking {
                let position = this_mut.context.as_mut()
                    .expect("No context in tracker while getting position")
                    .get_position();
                this_mut.info_ctrl.tic(position);
            }

            this_mut.audio_ctrl.tic();

            #[cfg(feature = "profiling-tracker")]
            let end = Utc::now();

            #[cfg(feature = "profiling-tracker")]
            println!("tracker,{},{},{},{}",
                start.time().format("%H:%M:%S%.6f"),
                before_tic.time().format("%H:%M:%S%.6f"),
                end.time().format("%H:%M:%S%.6f"),
                position,
            );

            glib::Continue(this_mut.keep_going)
        }));
    }

    fn open_media(&mut self, filepath: PathBuf) {
        assert_eq!(self.listener_src, None);

        self.info_ctrl.cleanup();
        self.audio_ctrl.cleanup();
        self.header_bar.set_subtitle("");

        let (ctx_tx, ui_rx) = channel();

        self.seeking = false;
        self.keep_going = true;
        self.register_listener(250, ui_rx);

        match Context::new(
            filepath,
            5_000_000_000,
            DoubleWaveformBuffer::new(&self.audio_ctrl.waveform_buffer_mtx),
            self.video_ctrl.video_box.clone(),
            ctx_tx
        ) {
            Ok(context) => {
                self.context = Some(context);
            },
            Err(error) => eprintln!("Error opening media: {}", error),
        };
    }
}
<|endoftext|>


<commit_before>macro_rules! platforms {
    ($($($platform:expr);* => $module:ident),*) => {
        $(
            #[cfg(any(test, $(target_os = $platform),*))]
            #[cfg_attr(not(any($(target_os = $platform),*)), allow(dead_code))]
            mod $module;

            #[cfg(any($(target_os = $platform),*))]
            pub use self::$module::*;

            #[cfg(any($(target_os = $platform),*))]
            pub const ENOATTR: ::libc::c_int = ::libc::ENOATTR;
        )*

        #[cfg(any(test, all(feature = "unsupported", not(any($($(target_os = $platform),*),*)))))]
        #[cfg_attr(any($($(target_os = $platform),*),*), allow(dead_code))]
        mod unsupported;

        #[cfg(all(feature = "unsupported", not(any($($(target_os = $platform),*),*))))]
        pub use self::unsupported::*;
        #[cfg(all(feature = "unsupported", not(any($($(target_os = $platform),*),*))))]
        pub const ENOATTR: ::libc::c_int = 0;

        /// A constant indicating whether or not the target platform is supported.
        ///
        /// To make programmer's lives easier, this library builds on all platforms.
        /// However, all function calls on unsupported platforms will return
        /// `io::Error`s.
        ///
        /// Note: If you would like compilation to simply fail on unsupported platforms,
        /// turn of the `unsupported` feature.
        pub const SUPPORTED_PLATFORM: bool = cfg!(any($($(target_os = $platform),*),*));
    }
}

platforms! {
    "linux"; "macos" => linux_macos,
    "freebsd"; "netbsd" => bsd
}
<commit_msg>don't compile everything when testing<commit_after>macro_rules! platforms {
    ($($($platform:expr);* => $module:ident),*) => {
        $(
            #[cfg(any($(target_os = $platform),*))]
            #[cfg_attr(not(any($(target_os = $platform),*)), allow(dead_code))]
            mod $module;

            #[cfg(any($(target_os = $platform),*))]
            pub use self::$module::*;

            #[cfg(any($(target_os = $platform),*))]
            pub const ENOATTR: ::libc::c_int = ::libc::ENOATTR;
        )*

        #[cfg(all(feature = "unsupported", not(any($($(target_os = $platform),*),*))))]
        #[cfg_attr(any($($(target_os = $platform),*),*), allow(dead_code))]
        mod unsupported;

        #[cfg(all(feature = "unsupported", not(any($($(target_os = $platform),*),*))))]
        pub use self::unsupported::*;
        #[cfg(all(feature = "unsupported", not(any($($(target_os = $platform),*),*))))]
        pub const ENOATTR: ::libc::c_int = 0;

        /// A constant indicating whether or not the target platform is supported.
        ///
        /// To make programmer's lives easier, this library builds on all platforms.
        /// However, all function calls on unsupported platforms will return
        /// `io::Error`s.
        ///
        /// Note: If you would like compilation to simply fail on unsupported platforms,
        /// turn of the `unsupported` feature.
        pub const SUPPORTED_PLATFORM: bool = cfg!(any($($(target_os = $platform),*),*));
    }
}

platforms! {
    "linux"; "macos" => linux_macos,
    "freebsd"; "netbsd" => bsd
}
<|endoftext|>


<commit_before>/*
 * Cymbalum, Molecular Simulation in Rust
 * Copyright (C) 2015 Guillaume Fraux
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
*/

use ::types::Vector3D;

/// The Particle type hold basic data about a particle in the system. It is self
/// contained, so that it will be easy to send data between parrallels
/// processes.
#[derive(Clone, Debug)]
pub struct Particle {
    /// Particle name
    name: String,
    /// Particle kind, an index for potentials lookup
    kind: usize,
    /// Particle mass
    mass: f64,
    /// Particle positions
    position: Vector3D,
    /// Particle velocity, if needed
    velocity: Vector3D,
}

impl Particle {
    pub fn new<S: Into<String>>(name: S) -> Particle {
        // TODO: get the mass here
        Particle{name: name.into(),
                 mass: 1.0,
                 kind: usize::max_value(),
                 position: Vector3D::new(0.0, 0.0, 0.0),
                 velocity: Vector3D::new(0.0, 0.0, 0.0)}
    }

    pub fn name<'a>(&'a self) -> &'a str {
        &self.name
    }

    pub fn set_name<S>(&mut self, name: S) where S: Into<String> {
        self.name = name.into();
    }

    pub fn kind(&self) -> usize {
        self.kind
    }

    pub fn set_kind(&mut self, kind: usize) {
        self.kind = kind;
    }

    pub fn mass(&self) -> f64 {
        self.mass
    }
    pub fn set_mass(&mut self, mass: f64) {
        self.mass = mass;
    }

    pub fn position<'a>(&'a self) -> &'a Vector3D {
        &self.position
    }
    pub fn set_position(&mut self, pos: Vector3D) {
        self.position = pos;
    }
    pub fn add_position(&mut self, new_pos: Vector3D) {
        self.position = self.position + new_pos;
    }

    pub fn velocity<'a>(&'a self) -> &'a Vector3D {
        &self.velocity
    }
    pub fn set_velocity(&mut self, vel: Vector3D) {
        self.velocity = vel;
    }
    pub fn add_velocity(&mut self, new_vel: Vector3D) {
        self.velocity = self.velocity + new_vel;
    }
}

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

    #[test]
    fn name() {
        let mut part = Particle::new("O");
        assert_eq!(part.name(), "O");

        part.set_name("H");
        assert_eq!(part.name(), "H");

        let name = "Zn";
        part.set_name(name);
        assert_eq!(part.name(), "Zn");
    }

    #[test]
    fn mass() {
        let mut part = Particle::new("O");
        part.set_mass(16.0);
        assert_eq!(part.mass(), 16.0);
    }

    #[test]
    fn kind() {
        let mut part = Particle::new("O");
        part.set_kind(42);
        assert_eq!(part.kind(), 42);
    }

    #[test]
    fn coordinates() {
        let mut part = Particle::new("O");
        assert_eq!(part.position(), &Vector3D::new(0.0, 0.0, 0.0));

        part.set_position(Vector3D::new(1.0, 2.0, 3.0));
        assert_eq!(part.position(), &Vector3D::new(1.0, 2.0, 3.0));

        part.set_velocity(Vector3D::new(1.0, 2.0, 3.0));
        assert_eq!(part.velocity(), &Vector3D::new(1.0, 2.0, 3.0));
    }
}
<commit_msg>Use PeriodicTable to get the particles mass<commit_after>/*
 * Cymbalum, Molecular Simulation in Rust
 * Copyright (C) 2015 Guillaume Fraux
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/
*/

use ::types::Vector3D;
use super::PeriodicTable;

/// The Particle type hold basic data about a particle in the system. It is self
/// contained, so that it will be easy to send data between parrallels
/// processes.
#[derive(Clone, Debug)]
pub struct Particle {
    /// Particle name
    name: String,
    /// Particle kind, an index for potentials lookup
    kind: usize,
    /// Particle mass
    mass: f64,
    /// Particle positions
    position: Vector3D,
    /// Particle velocity, if needed
    velocity: Vector3D,
}

impl Particle {
    pub fn new<S: Into<String>>(n: S) -> Particle {
        let name = n.into();
        let mass = match PeriodicTable::mass(&*name) {
            Some(val) => val,
            None => panic!("Could not find the mass for the {} particle", name)
        };
        Particle{name: name,
                 mass: mass as f64,
                 kind: usize::max_value(),
                 position: Vector3D::new(0.0, 0.0, 0.0),
                 velocity: Vector3D::new(0.0, 0.0, 0.0)}
    }

    pub fn name<'a>(&'a self) -> &'a str {
        &self.name
    }

    pub fn set_name<S>(&mut self, name: S) where S: Into<String> {
        self.name = name.into();
    }

    pub fn kind(&self) -> usize {
        self.kind
    }

    pub fn set_kind(&mut self, kind: usize) {
        self.kind = kind;
    }

    pub fn mass(&self) -> f64 {
        self.mass
    }
    pub fn set_mass(&mut self, mass: f64) {
        self.mass = mass;
    }

    pub fn position<'a>(&'a self) -> &'a Vector3D {
        &self.position
    }
    pub fn set_position(&mut self, pos: Vector3D) {
        self.position = pos;
    }
    pub fn add_position(&mut self, new_pos: Vector3D) {
        self.position = self.position + new_pos;
    }

    pub fn velocity<'a>(&'a self) -> &'a Vector3D {
        &self.velocity
    }
    pub fn set_velocity(&mut self, vel: Vector3D) {
        self.velocity = vel;
    }
    pub fn add_velocity(&mut self, new_vel: Vector3D) {
        self.velocity = self.velocity + new_vel;
    }
}

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

    #[test]
    fn name() {
        let mut part = Particle::new("O");
        assert_eq!(part.name(), "O");

        part.set_name("H");
        assert_eq!(part.name(), "H");

        let name = "Zn";
        part.set_name(name);
        assert_eq!(part.name(), "Zn");
    }

    #[test]
    fn mass() {
        let mut part = Particle::new("O");
        part.set_mass(16.0);
        assert_eq!(part.mass(), 16.0);
    }

    #[test]
    fn kind() {
        let mut part = Particle::new("O");
        part.set_kind(42);
        assert_eq!(part.kind(), 42);
    }

    #[test]
    fn coordinates() {
        let mut part = Particle::new("O");
        assert_eq!(part.position(), &Vector3D::new(0.0, 0.0, 0.0));

        part.set_position(Vector3D::new(1.0, 2.0, 3.0));
        assert_eq!(part.position(), &Vector3D::new(1.0, 2.0, 3.0));

        part.set_velocity(Vector3D::new(1.0, 2.0, 3.0));
        assert_eq!(part.velocity(), &Vector3D::new(1.0, 2.0, 3.0));
    }
}
<|endoftext|>


<commit_before>// This file is part of the uutils coreutils package.
//
// (c) Jian Zeng <anonymousknight96@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (ToDO) parsemode makedev sysmacros perror IFBLK IFCHR IFIFO

#[macro_use]
extern crate uucore;

use std::ffi::CString;

use clap::{crate_version, App, Arg, ArgMatches};
use libc::{dev_t, mode_t};
use libc::{S_IFBLK, S_IFCHR, S_IFIFO, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR};

use uucore::display::Quotable;
use uucore::InvalidEncodingHandling;

static ABOUT: &str = "Create the special file NAME of the given TYPE.";
static USAGE: &str = "mknod [OPTION]... NAME TYPE [MAJOR MINOR]";
static LONG_HELP: &str = "Mandatory arguments to long options are mandatory for short options too.
-m, --mode=MODE    set file permission bits to MODE, not a=rw - umask
--help     display this help and exit
--version  output version information and exit

Both MAJOR and MINOR must be specified when TYPE is b, c, or u, and they
must be omitted when TYPE is p.  If MAJOR or MINOR begins with 0x or 0X,
it is interpreted as hexadecimal; otherwise, if it begins with 0, as octal;
otherwise, as decimal.  TYPE may be:

b      create a block (buffered) special file
c, u   create a character (unbuffered) special file
p      create a FIFO

NOTE: your shell may have its own version of mknod, which usually supersedes
the version described here.  Please refer to your shell's documentation
for details about the options it supports.
";

const MODE_RW_UGO: mode_t = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;

#[inline(always)]
fn makedev(maj: u64, min: u64) -> dev_t {
    // pick up from <sys/sysmacros.h>
    ((min & 0xff) | ((maj & 0xfff) << 8) | ((min & !0xff) << 12) | ((maj & !0xfff) << 32)) as dev_t
}

#[cfg(windows)]
fn _mknod(file_name: &str, mode: mode_t, dev: dev_t) -> i32 {
    panic!("Unsupported for windows platform")
}

#[cfg(unix)]
fn _mknod(file_name: &str, mode: mode_t, dev: dev_t) -> i32 {
    let c_str = CString::new(file_name).expect("Failed to convert to CString");

    // the user supplied a mode
    let set_umask = mode & MODE_RW_UGO != MODE_RW_UGO;

    unsafe {
        // store prev umask
        let last_umask = if set_umask { libc::umask(0) } else { 0 };

        let errno = libc::mknod(c_str.as_ptr(), mode, dev);

        // set umask back to original value
        if set_umask {
            libc::umask(last_umask);
        }

        if errno == -1 {
            let c_str = CString::new(uucore::execution_phrase().as_bytes())
                .expect("Failed to convert to CString");
            // shows the error from the mknod syscall
            libc::perror(c_str.as_ptr());
        }
        errno
    }
}

#[allow(clippy::cognitive_complexity)]
pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args
        .collect_str(InvalidEncodingHandling::Ignore)
        .accept_any();
    // Linux-specific options, not implemented
    // opts.optflag("Z", "", "set the SELinux security context to default type");
    // opts.optopt("", "context", "like -Z, or if CTX is specified then set the SELinux or SMACK security context to CTX");

    let matches = uu_app().get_matches_from(args);

    let mode = match get_mode(&matches) {
        Ok(mode) => mode,
        Err(err) => {
            show_error!("{}", err);
            return 1;
        }
    };

    let file_name = matches.value_of("name").expect("Missing argument 'NAME'");

    // Only check the first character, to allow mnemonic usage like
    // 'mknod /dev/rst0 character 18 0'.
    let ch = matches
        .value_of("type")
        .expect("Missing argument 'TYPE'")
        .chars()
        .next()
        .expect("Failed to get the first char");

    if ch == 'p' {
        if matches.is_present("major") || matches.is_present("minor") {
            eprintln!("Fifos do not have major and minor device numbers.");
            eprintln!(
                "Try '{} --help' for more information.",
                uucore::execution_phrase()
            );
            1
        } else {
            _mknod(file_name, S_IFIFO | mode, 0)
        }
    } else {
        match (matches.value_of("major"), matches.value_of("minor")) {
            (None, None) | (_, None) | (None, _) => {
                eprintln!("Special files require major and minor device numbers.");
                eprintln!(
                    "Try '{} --help' for more information.",
                    uucore::execution_phrase()
                );
                1
            }
            (Some(major), Some(minor)) => {
                let major = major.parse::<u64>().expect("validated by clap");
                let minor = minor.parse::<u64>().expect("validated by clap");

                let dev = makedev(major, minor);
                if ch == 'b' {
                    // block special file
                    _mknod(file_name, S_IFBLK | mode, dev)
                } else if ch == 'c' || ch == 'u' {
                    // char special file
                    _mknod(file_name, S_IFCHR | mode, dev)
                } else {
                    unreachable!("{} was validated to be only b, c or u", ch);
                }
            }
        }
    }
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(uucore::util_name())
        .version(crate_version!())
        .usage(USAGE)
        .after_help(LONG_HELP)
        .about(ABOUT)
        .arg(
            Arg::with_name("mode")
                .short("m")
                .long("mode")
                .value_name("MODE")
                .help("set file permission bits to MODE, not a=rw - umask"),
        )
        .arg(
            Arg::with_name("name")
                .value_name("NAME")
                .help("name of the new file")
                .required(true)
                .index(1),
        )
        .arg(
            Arg::with_name("type")
                .value_name("TYPE")
                .help("type of the new file (b, c, u or p)")
                .required(true)
                .validator(valid_type)
                .index(2),
        )
        .arg(
            Arg::with_name("major")
                .value_name("MAJOR")
                .help("major file type")
                .validator(valid_u64)
                .index(3),
        )
        .arg(
            Arg::with_name("minor")
                .value_name("MINOR")
                .help("minor file type")
                .validator(valid_u64)
                .index(4),
        )
}

fn get_mode(matches: &ArgMatches) -> Result<mode_t, String> {
    match matches.value_of("mode") {
        None => Ok(MODE_RW_UGO),
        Some(str_mode) => uucore::mode::parse_mode(str_mode)
            .map_err(|e| format!("invalid mode ({})", e))
            .and_then(|mode| {
                if mode > 0o777 {
                    Err("mode must specify only file permission bits".to_string())
                } else {
                    Ok(mode)
                }
            }),
    }
}

fn valid_type(tpe: String) -> Result<(), String> {
    // Only check the first character, to allow mnemonic usage like
    // 'mknod /dev/rst0 character 18 0'.
    tpe.chars()
        .next()
        .ok_or_else(|| "missing device type".to_string())
        .and_then(|first_char| {
            if vec!['b', 'c', 'u', 'p'].contains(&first_char) {
                Ok(())
            } else {
                Err(format!("invalid device type {}", tpe.quote()))
            }
        })
}

fn valid_u64(num: String) -> Result<(), String> {
    num.parse::<u64>().map(|_| ()).map_err(|_| num)
}
<commit_msg>mknod: return UResult from uumain() function<commit_after>// This file is part of the uutils coreutils package.
//
// (c) Jian Zeng <anonymousknight96@gmail.com>
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore (ToDO) parsemode makedev sysmacros perror IFBLK IFCHR IFIFO

use std::ffi::CString;

use clap::{crate_version, App, Arg, ArgMatches};
use libc::{dev_t, mode_t};
use libc::{S_IFBLK, S_IFCHR, S_IFIFO, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR};

use uucore::display::Quotable;
use uucore::error::{set_exit_code, UResult, USimpleError, UUsageError};
use uucore::InvalidEncodingHandling;

static ABOUT: &str = "Create the special file NAME of the given TYPE.";
static USAGE: &str = "mknod [OPTION]... NAME TYPE [MAJOR MINOR]";
static LONG_HELP: &str = "Mandatory arguments to long options are mandatory for short options too.
-m, --mode=MODE    set file permission bits to MODE, not a=rw - umask
--help     display this help and exit
--version  output version information and exit

Both MAJOR and MINOR must be specified when TYPE is b, c, or u, and they
must be omitted when TYPE is p.  If MAJOR or MINOR begins with 0x or 0X,
it is interpreted as hexadecimal; otherwise, if it begins with 0, as octal;
otherwise, as decimal.  TYPE may be:

b      create a block (buffered) special file
c, u   create a character (unbuffered) special file
p      create a FIFO

NOTE: your shell may have its own version of mknod, which usually supersedes
the version described here.  Please refer to your shell's documentation
for details about the options it supports.
";

const MODE_RW_UGO: mode_t = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;

#[inline(always)]
fn makedev(maj: u64, min: u64) -> dev_t {
    // pick up from <sys/sysmacros.h>
    ((min & 0xff) | ((maj & 0xfff) << 8) | ((min & !0xff) << 12) | ((maj & !0xfff) << 32)) as dev_t
}

#[cfg(windows)]
fn _mknod(file_name: &str, mode: mode_t, dev: dev_t) -> i32 {
    panic!("Unsupported for windows platform")
}

#[cfg(unix)]
fn _mknod(file_name: &str, mode: mode_t, dev: dev_t) -> i32 {
    let c_str = CString::new(file_name).expect("Failed to convert to CString");

    // the user supplied a mode
    let set_umask = mode & MODE_RW_UGO != MODE_RW_UGO;

    unsafe {
        // store prev umask
        let last_umask = if set_umask { libc::umask(0) } else { 0 };

        let errno = libc::mknod(c_str.as_ptr(), mode, dev);

        // set umask back to original value
        if set_umask {
            libc::umask(last_umask);
        }

        if errno == -1 {
            let c_str = CString::new(uucore::execution_phrase().as_bytes())
                .expect("Failed to convert to CString");
            // shows the error from the mknod syscall
            libc::perror(c_str.as_ptr());
        }
        errno
    }
}

#[uucore_procs::gen_uumain]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
    let args = args
        .collect_str(InvalidEncodingHandling::Ignore)
        .accept_any();
    // Linux-specific options, not implemented
    // opts.optflag("Z", "", "set the SELinux security context to default type");
    // opts.optopt("", "context", "like -Z, or if CTX is specified then set the SELinux or SMACK security context to CTX");

    let matches = uu_app().get_matches_from(args);

    let mode = get_mode(&matches).map_err(|e| USimpleError::new(1, e))?;

    let file_name = matches.value_of("name").expect("Missing argument 'NAME'");

    // Only check the first character, to allow mnemonic usage like
    // 'mknod /dev/rst0 character 18 0'.
    let ch = matches
        .value_of("type")
        .expect("Missing argument 'TYPE'")
        .chars()
        .next()
        .expect("Failed to get the first char");

    if ch == 'p' {
        if matches.is_present("major") || matches.is_present("minor") {
            Err(UUsageError::new(
                1,
                "Fifos do not have major and minor device numbers.",
            ))
        } else {
            let exit_code = _mknod(file_name, S_IFIFO | mode, 0);
            set_exit_code(exit_code);
            Ok(())
        }
    } else {
        match (matches.value_of("major"), matches.value_of("minor")) {
            (None, None) | (_, None) | (None, _) => {
                return Err(UUsageError::new(
                    1,
                    "Special files require major and minor device numbers.",
                ));
            }
            (Some(major), Some(minor)) => {
                let major = major.parse::<u64>().expect("validated by clap");
                let minor = minor.parse::<u64>().expect("validated by clap");

                let dev = makedev(major, minor);
                let exit_code = if ch == 'b' {
                    // block special file
                    _mknod(file_name, S_IFBLK | mode, dev)
                } else if ch == 'c' || ch == 'u' {
                    // char special file
                    _mknod(file_name, S_IFCHR | mode, dev)
                } else {
                    unreachable!("{} was validated to be only b, c or u", ch);
                };
                set_exit_code(exit_code);
                Ok(())
            }
        }
    }
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(uucore::util_name())
        .version(crate_version!())
        .usage(USAGE)
        .after_help(LONG_HELP)
        .about(ABOUT)
        .arg(
            Arg::with_name("mode")
                .short("m")
                .long("mode")
                .value_name("MODE")
                .help("set file permission bits to MODE, not a=rw - umask"),
        )
        .arg(
            Arg::with_name("name")
                .value_name("NAME")
                .help("name of the new file")
                .required(true)
                .index(1),
        )
        .arg(
            Arg::with_name("type")
                .value_name("TYPE")
                .help("type of the new file (b, c, u or p)")
                .required(true)
                .validator(valid_type)
                .index(2),
        )
        .arg(
            Arg::with_name("major")
                .value_name("MAJOR")
                .help("major file type")
                .validator(valid_u64)
                .index(3),
        )
        .arg(
            Arg::with_name("minor")
                .value_name("MINOR")
                .help("minor file type")
                .validator(valid_u64)
                .index(4),
        )
}

fn get_mode(matches: &ArgMatches) -> Result<mode_t, String> {
    match matches.value_of("mode") {
        None => Ok(MODE_RW_UGO),
        Some(str_mode) => uucore::mode::parse_mode(str_mode)
            .map_err(|e| format!("invalid mode ({})", e))
            .and_then(|mode| {
                if mode > 0o777 {
                    Err("mode must specify only file permission bits".to_string())
                } else {
                    Ok(mode)
                }
            }),
    }
}

fn valid_type(tpe: String) -> Result<(), String> {
    // Only check the first character, to allow mnemonic usage like
    // 'mknod /dev/rst0 character 18 0'.
    tpe.chars()
        .next()
        .ok_or_else(|| "missing device type".to_string())
        .and_then(|first_char| {
            if vec!['b', 'c', 'u', 'p'].contains(&first_char) {
                Ok(())
            } else {
                Err(format!("invalid device type {}", tpe.quote()))
            }
        })
}

fn valid_u64(num: String) -> Result<(), String> {
    num.parse::<u64>().map(|_| ()).map_err(|_| num)
}
<|endoftext|>