<commit_before>//! Ogg vorbis decoder.

// Future work: permit compile-time selection of the default vorbis plugin:
// Xiph.org libvorbisfile, or rust-vorbis.
// #[cfg(libvorbis = "xiph")]
// use xiph_vorbis;
// #[cfg(libvorbis = "rust")]
// use rust_vorbis;

extern crate vorbisfile;

use super::{Source, SourceResult};
use super::SourceResult::{Buffer, StreamError, EndOfStream};
use self::vorbisfile::OVResult;

/// Ogg Vorbis decoder.
pub struct VorbisStream<R> {
    src: vorbisfile::VorbisFile<R>,
}

impl<R: Reader> VorbisStream<R> {
    /// Open a new decoder.
    pub fn open(reader: R) -> OVResult<VorbisStream<R>> {
        Ok(VorbisStream {
            src: try!(vorbisfile::VorbisFile::new(reader))
        })
    }
}

// The native result type for vorbis is a C float. ov_read() postprocesses into
// integer samples, which we're equally capable of doing.
impl<R: Reader> Source for VorbisStream<R> {
    type Output = f32;

    fn next<'a>(&'a mut self) -> SourceResult<'a, f32> {
        // TODO report sample rate
        match self.src.decode() {
            Ok(b) => Buffer(b),
            // ??? => SampleRate(...),
            Err(vorbisfile::OVError::EndOfStream) => EndOfStream,
            Err(e) => StreamError(format!("vorbisfile decoder: {}", e))
        }
    }
}
<commit_msg>Reader => Read.<commit_after>//! Ogg vorbis decoder.

// Future work: permit compile-time selection of the default vorbis plugin:
// Xiph.org libvorbisfile, or rust-vorbis.
// #[cfg(libvorbis = "xiph")]
// use xiph_vorbis;
// #[cfg(libvorbis = "rust")]
// use rust_vorbis;

extern crate vorbisfile;

use std::io::Read;
use super::{Source, SourceResult};
use super::SourceResult::{Buffer, StreamError, EndOfStream};
use self::vorbisfile::OVResult;

/// Ogg Vorbis decoder.
pub struct VorbisStream<R> {
    src: vorbisfile::VorbisFile<R>,
}

impl<R: Read> VorbisStream<R> {
    /// Open a new decoder.
    pub fn open(reader: R) -> OVResult<VorbisStream<R>> {
        Ok(VorbisStream {
            src: try!(vorbisfile::VorbisFile::new(reader))
        })
    }
}

// The native result type for vorbis is a C float. ov_read() postprocesses into
// integer samples, which we're equally capable of doing.
impl<R: Read> Source for VorbisStream<R> {
    type Output = f32;

    fn next<'a>(&'a mut self) -> SourceResult<'a, f32> {
        // TODO report sample rate
        match self.src.decode() {
            Ok(b) => Buffer(b),
            // ??? => SampleRate(...),
            Err(vorbisfile::OVError::EndOfStream) => EndOfStream,
            Err(e) => StreamError(format!("vorbisfile decoder: {}", e))
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! A definition of `BinaryForm` trait and implementations for common types.

use std::io::{Read, Write};

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use chrono::{DateTime, NaiveDateTime, Utc};
use failure::{self, format_err};
use rust_decimal::Decimal;
use uuid::Uuid;

use super::UniqueHash;
use exonum_crypto::{Hash, PublicKey};

/// A type that can be (de)serialized as a value in the blockchain storage.
///
/// # Examples
///
/// Implementing `BinaryForm` for the type:
///
/// ```
/// use crate::BinaryForm;
/// use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
/// use failure;
/// use std::io::{Read, Write};
///
/// #[derive(Clone)]
/// struct Data {
///     a: i16,
///     b: u32,
/// }
///
/// impl BinaryForm for Data {
///     fn encode(&self, to: &mut impl Write) -> Result<(), failure::Error> {
///         to.write_i16::<LittleEndian>(self.a)?;
///         to.write_u32::<LittleEndian>(self.b)?;
///         Ok(())
///     }
///
///     fn decode(from: &mut impl Read) -> Result<Self, failure::Error> {
///         let a = from.read_i16::<LittleEndian>()?;
///         let b = from.read_u32::<LittleEndian>()?;
///         Ok(Self { a, b })
///     }
/// }
/// # fn main() {}
/// ```
pub trait BinaryForm: Sized {
    fn encode(&self, to: &mut impl Write) -> Result<(), failure::Error>;

    fn decode(from: &mut impl Read) -> Result<Self, failure::Error>;

    fn size_hint(&self) -> Option<usize> {
        Some(std::mem::size_of_val(self))
    }

    fn to_bytes(&self) -> Result<Vec<u8>, failure::Error> {
        let mut buf = self
            .size_hint()
            .map_or_else(Vec::default, Vec::with_capacity);
        self.encode(&mut buf)?;
        Ok(buf)
    }

    fn from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, failure::Error> {
        Self::decode(&mut bytes.as_ref())
    }
}

macro_rules! impl_binary_form_scalar {
    ($type:tt, $write:ident, $read:ident) => {
        impl BinaryForm for $type {
            fn encode(&self, to: &mut impl Write) -> Result<(), failure::Error> {
                use byteorder::WriteBytesExt;
                to.$write(*self).map_err(failure::Error::from)
            }

            fn decode(from: &mut impl Read) -> Result<Self, failure::Error> {
                use byteorder::ReadBytesExt;
                from.$read().map_err(failure::Error::from)
            }
        }

        impl UniqueHash for $type {}
    };
    ($type:tt, $write:ident, $read:ident, $len:expr) => {
        impl BinaryForm for $type {
            fn encode(&self, to: &mut impl Write) -> Result<(), failure::Error> {
                use byteorder::{LittleEndian, WriteBytesExt};
                to.$write::<LittleEndian>(*self)
                    .map_err(failure::Error::from)
            }

            fn decode(from: &mut impl Read) -> Result<Self, failure::Error> {
                use byteorder::{LittleEndian, ReadBytesExt};
                from.$read::<LittleEndian>().map_err(failure::Error::from)
            }

            fn size_hint(&self) -> Option<usize> {
                Some($len)
            }
        }

        impl UniqueHash for $type {}
    };
}

// Unsigned scalar types
impl_binary_form_scalar! { u8,  write_u8,  read_u8 }
impl_binary_form_scalar! { u16, write_u16, read_u16, 2 }
impl_binary_form_scalar! { u32, write_u32, read_u32, 4 }
impl_binary_form_scalar! { u64, write_u64, read_u64, 8 }
// Signed scalar types
impl_binary_form_scalar! { i8,  write_i8,  read_i8 }
impl_binary_form_scalar! { i16, write_i16, read_i16, 2 }
impl_binary_form_scalar! { i32, write_i32, read_i32, 4 }
impl_binary_form_scalar! { i64, write_i64, read_i64, 8 }

/// No-op implementation.
impl BinaryForm for () {
    fn encode(&self, _to: &mut impl Write) -> Result<(), failure::Error> {
        Ok(())
    }

    fn decode(_from: &mut impl Read) -> Result<Self, failure::Error> {
        Ok(())
    }
}

impl UniqueHash for () {}

impl BinaryForm for bool {
    fn encode(&self, to: &mut impl Write) -> Result<(), failure::Error> {
        (*self as u8).encode(to)
    }

    fn decode(from: &mut impl Read) -> Result<Self, failure::Error> {
        let value = u8::decode(from)?;
        match value {
            0 => Ok(false),
            1 => Ok(true),
            other => Err(format_err!("Invalid value for bool: {}", other)),
        }
    }
}

impl UniqueHash for bool {}

impl BinaryForm for Vec<u8> {
    fn encode(&self, to: &mut impl Write) -> Result<(), failure::Error> {
        to.write_all(self.as_ref()).map_err(failure::Error::from)
    }

    fn decode(from: &mut impl Read) -> Result<Self, failure::Error> {
        let mut buf = Self::new();
        from.read_to_end(&mut buf)?;
        Ok(buf)
    }

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

impl UniqueHash for Vec<u8> {}

impl BinaryForm for String {
    fn encode(&self, to: &mut impl Write) -> Result<(), failure::Error> {
        to.write_all(self.as_ref()).map_err(failure::Error::from)
    }

    fn decode(from: &mut impl Read) -> Result<Self, failure::Error> {
        let mut buf = Vec::new();
        from.read_to_end(&mut buf)?;
        Self::from_utf8(buf).map_err(failure::Error::from)
    }

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

impl UniqueHash for String {}

impl BinaryForm for Hash {
    fn encode(&self, to: &mut impl Write) -> Result<(), failure::Error> {
        to.write_all(self.as_ref()).map_err(failure::Error::from)
    }

    fn decode(from: &mut impl Read) -> Result<Self, failure::Error> {
        let mut buf = Vec::new();
        from.read_to_end(&mut buf)?;
        Self::from_slice(buf.as_ref())
            .ok_or_else(|| format_err!("Unable to decode value from bytes"))
    }

    fn size_hint(&self) -> Option<usize> {
        Some(self.as_ref().len())
    }
}

impl BinaryForm for PublicKey {
    fn encode(&self, to: &mut impl Write) -> Result<(), failure::Error> {
        to.write_all(self.as_ref()).map_err(failure::Error::from)
    }

    fn decode(from: &mut impl Read) -> Result<Self, failure::Error> {
        let mut buf = Vec::new();
        from.read_to_end(&mut buf)?;
        Self::from_slice(buf.as_ref())
            .ok_or_else(|| format_err!("Unable to decode value from bytes"))
    }

    fn size_hint(&self) -> Option<usize> {
        Some(self.as_ref().len())
    }
}

impl UniqueHash for PublicKey {}

// FIXME Maybe we should remove this implementations

impl BinaryForm for DateTime<Utc> {
    fn encode(&self, to: &mut impl Write) -> Result<(), failure::Error> {
        to.write_i64::<LittleEndian>(self.timestamp())?;
        to.write_u32::<LittleEndian>(self.timestamp_subsec_nanos())?;
        Ok(())
    }

    fn decode(from: &mut impl Read) -> Result<Self, failure::Error> {
        let secs = from.read_i64::<LittleEndian>()?;
        let nanos = from.read_u32::<LittleEndian>()?;
        Ok(Self::from_utc(
            NaiveDateTime::from_timestamp(secs, nanos),
            Utc,
        ))
    }

    fn size_hint(&self) -> Option<usize> {
        Some(12)
    }
}

impl UniqueHash for DateTime<Utc> {}

impl BinaryForm for Uuid {
    fn encode(&self, to: &mut impl Write) -> Result<(), failure::Error> {
        to.write_all(self.as_bytes()).map_err(failure::Error::from)
    }

    fn decode(from: &mut impl Read) -> Result<Self, failure::Error> {
        let mut buf = Vec::new();
        from.read_to_end(&mut buf)?;
        Self::from_slice(&buf).map_err(failure::Error::from)
    }

    fn size_hint(&self) -> Option<usize> {
        Some(self.as_bytes().len())
    }
}

impl UniqueHash for Uuid {}

impl BinaryForm for Decimal {
    fn encode(&self, to: &mut impl Write) -> Result<(), failure::Error> {
        to.write_all(&self.serialize())
            .map_err(failure::Error::from)
    }

    fn decode(from: &mut impl Read) -> Result<Self, failure::Error> {
        let mut buf: [u8; 16] = [0; 16];
        from.read_exact(&mut buf)?;
        Ok(Self::deserialize(buf))
    }

    fn size_hint(&self) -> Option<usize> {
        Some(16)
    }
}

impl UniqueHash for Decimal {}

#[cfg(test)]
mod tests {
    use std::fmt::Debug;
    use std::str::FromStr;

    use chrono::Duration;

    use super::*;

    fn assert_round_trip_eq<T: BinaryForm + PartialEq + Debug>(values: &[T]) {
        for value in values {
            let bytes = value.to_bytes().unwrap();
            assert_eq!(*value, <T as BinaryForm>::from_bytes(bytes).unwrap());
        }
    }

    macro_rules! impl_test_binary_form_scalar_unsigned {
        ($name:ident, $type:tt) => {
            #[test]
            fn $name() {
                let values = [$type::min_value(), 1, $type::max_value()];
                assert_round_trip_eq(&values);
            }
        };
    }

    macro_rules! impl_test_binary_form_scalar_signed {
        ($name:ident, $type:tt) => {
            #[test]
            fn $name() {
                let values = [$type::min_value(), -1, 0, 1, $type::max_value()];
                assert_round_trip_eq(&values);
            }
        };
    }

    // Impl tests for unsigned scalar types
    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u8,  u8 }
    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u32, u32 }
    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u16, u16 }
    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u64, u64 }

    // Impl tests for signed scalar types
    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i8,  i8 }
    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i16, i16 }
    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i32, i32 }
    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i64, i64 }

    // Tests for the other types

    #[test]
    fn test_binary_form_vec_u8() {
        let values = [vec![], vec![1], vec![1, 2, 3], vec![255; 100]];
        assert_round_trip_eq(&values);
    }

    #[test]
    fn test_binary_form_bool_correct() {
        let values = [true, false];
        assert_round_trip_eq(&values);
    }

    #[test]
    #[should_panic(expected = "Invalid value for bool: 2")]
    fn test_binary_form_bool_incorrect() {
        let bytes = 2.to_bytes().unwrap();
        <bool as BinaryForm>::from_bytes(&bytes).unwrap();
    }

    #[test]
    fn test_binary_form_string() {
        let values: Vec<_> = ["", "e", "2", "hello"]
            .iter()
            .map(|v| v.to_string())
            .collect();
        assert_round_trip_eq(&values);
    }

    #[test]
    fn test_binary_form_datetime() {
        use chrono::TimeZone;

        let times = [
            Utc.timestamp(0, 0),
            Utc.timestamp(13, 23),
            Utc::now(),
            Utc::now() + Duration::seconds(17) + Duration::nanoseconds(15),
            Utc.timestamp(0, 999_999_999),
            Utc.timestamp(0, 1_500_000_000), // leap second
        ];
        assert_round_trip_eq(&times);
    }

    #[test]
    fn test_binary_form_uuid() {
        let values = [
            Uuid::nil(),
            Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap(),
            Uuid::parse_str("0000002a-000c-0005-0c03-0938362b0809").unwrap(),
        ];
        assert_round_trip_eq(&values);
    }

    #[test]
    fn test_binary_form_decimal() {
        let values = [
            Decimal::from_str("3.14").unwrap(),
            Decimal::from_parts(1102470952, 185874565, 1703060790, false, 28),
            Decimal::new(9497628354687268, 12),
            Decimal::from_str("0").unwrap(),
            Decimal::from_str("-0.000000000000000000019").unwrap(),
        ];
        assert_round_trip_eq(&values);
    }
}
<commit_msg>Improve vec perfomance<commit_after>// Copyright 2018 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! A definition of `BinaryForm` trait and implementations for common types.

use std::io::{Read, Write};

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use chrono::{DateTime, NaiveDateTime, Utc};
use failure::{self, format_err};
use rust_decimal::Decimal;
use uuid::Uuid;

use super::UniqueHash;
use exonum_crypto::{Hash, PublicKey};

/// A type that can be (de)serialized as a value in the blockchain storage.
///
/// # Examples
///
/// Implementing `BinaryForm` for the type:
///
/// ```
/// use crate::BinaryForm;
/// use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
/// use failure;
/// use std::io::{Read, Write};
///
/// #[derive(Clone)]
/// struct Data {
///     a: i16,
///     b: u32,
/// }
///
/// impl BinaryForm for Data {
///     fn encode(&self, to: &mut impl Write) -> Result<(), failure::Error> {
///         to.write_i16::<LittleEndian>(self.a)?;
///         to.write_u32::<LittleEndian>(self.b)?;
///         Ok(())
///     }
///
///     fn decode(from: &mut impl Read) -> Result<Self, failure::Error> {
///         let a = from.read_i16::<LittleEndian>()?;
///         let b = from.read_u32::<LittleEndian>()?;
///         Ok(Self { a, b })
///     }
/// }
/// # fn main() {}
/// ```
pub trait BinaryForm: Sized {
    fn encode(&self, to: &mut impl Write) -> Result<(), failure::Error>;

    fn decode(from: &mut impl Read) -> Result<Self, failure::Error>;

    fn size_hint(&self) -> Option<usize> {
        Some(std::mem::size_of_val(self))
    }

    fn to_bytes(&self) -> Result<Vec<u8>, failure::Error> {
        let mut buf = self
            .size_hint()
            .map_or_else(Vec::default, Vec::with_capacity);
        self.encode(&mut buf)?;
        Ok(buf)
    }

    fn from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, failure::Error> {
        Self::decode(&mut bytes.as_ref())
    }
}

macro_rules! impl_binary_form_scalar {
    ($type:tt, $write:ident, $read:ident) => {
        impl BinaryForm for $type {
            fn encode(&self, to: &mut impl Write) -> Result<(), failure::Error> {
                use byteorder::WriteBytesExt;
                to.$write(*self).map_err(failure::Error::from)
            }

            fn decode(from: &mut impl Read) -> Result<Self, failure::Error> {
                use byteorder::ReadBytesExt;
                from.$read().map_err(failure::Error::from)
            }
        }

        impl UniqueHash for $type {}
    };
    ($type:tt, $write:ident, $read:ident, $len:expr) => {
        impl BinaryForm for $type {
            fn encode(&self, to: &mut impl Write) -> Result<(), failure::Error> {
                use byteorder::{LittleEndian, WriteBytesExt};
                to.$write::<LittleEndian>(*self)
                    .map_err(failure::Error::from)
            }

            fn decode(from: &mut impl Read) -> Result<Self, failure::Error> {
                use byteorder::{LittleEndian, ReadBytesExt};
                from.$read::<LittleEndian>().map_err(failure::Error::from)
            }

            fn size_hint(&self) -> Option<usize> {
                Some($len)
            }
        }

        impl UniqueHash for $type {}
    };
}

// Unsigned scalar types
impl_binary_form_scalar! { u8,  write_u8,  read_u8 }
impl_binary_form_scalar! { u16, write_u16, read_u16, 2 }
impl_binary_form_scalar! { u32, write_u32, read_u32, 4 }
impl_binary_form_scalar! { u64, write_u64, read_u64, 8 }
// Signed scalar types
impl_binary_form_scalar! { i8,  write_i8,  read_i8 }
impl_binary_form_scalar! { i16, write_i16, read_i16, 2 }
impl_binary_form_scalar! { i32, write_i32, read_i32, 4 }
impl_binary_form_scalar! { i64, write_i64, read_i64, 8 }

/// No-op implementation.
impl BinaryForm for () {
    fn encode(&self, _to: &mut impl Write) -> Result<(), failure::Error> {
        Ok(())
    }

    fn decode(_from: &mut impl Read) -> Result<Self, failure::Error> {
        Ok(())
    }
}

impl UniqueHash for () {}

impl BinaryForm for bool {
    fn encode(&self, to: &mut impl Write) -> Result<(), failure::Error> {
        (*self as u8).encode(to)
    }

    fn decode(from: &mut impl Read) -> Result<Self, failure::Error> {
        let value = u8::decode(from)?;
        match value {
            0 => Ok(false),
            1 => Ok(true),
            other => Err(format_err!("Invalid value for bool: {}", other)),
        }
    }
}

impl UniqueHash for bool {}

impl BinaryForm for Vec<u8> {
    fn encode(&self, to: &mut impl Write) -> Result<(), failure::Error> {
        to.write_all(self.as_ref()).map_err(failure::Error::from)
    }

    fn decode(from: &mut impl Read) -> Result<Self, failure::Error> {
        let mut buf = Self::new();
        from.read_to_end(&mut buf)?;
        Ok(buf)
    }

    fn to_bytes(&self) -> Result<Vec<u8>, failure::Error> {
        Ok(self.clone())
    }

    fn from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, failure::Error> {
        Ok(bytes.as_ref().to_vec())
    }
}

impl UniqueHash for Vec<u8> {}

impl BinaryForm for String {
    fn encode(&self, to: &mut impl Write) -> Result<(), failure::Error> {
        to.write_all(self.as_ref()).map_err(failure::Error::from)
    }

    fn decode(from: &mut impl Read) -> Result<Self, failure::Error> {
        let mut buf = Vec::new();
        from.read_to_end(&mut buf)?;
        Self::from_utf8(buf).map_err(failure::Error::from)
    }

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

impl UniqueHash for String {}

impl BinaryForm for Hash {
    fn encode(&self, to: &mut impl Write) -> Result<(), failure::Error> {
        to.write_all(self.as_ref()).map_err(failure::Error::from)
    }

    fn decode(from: &mut impl Read) -> Result<Self, failure::Error> {
        let mut buf = Vec::new();
        from.read_to_end(&mut buf)?;
        Self::from_slice(buf.as_ref())
            .ok_or_else(|| format_err!("Unable to decode value from bytes"))
    }

    fn size_hint(&self) -> Option<usize> {
        Some(self.as_ref().len())
    }
}

impl BinaryForm for PublicKey {
    fn encode(&self, to: &mut impl Write) -> Result<(), failure::Error> {
        to.write_all(self.as_ref()).map_err(failure::Error::from)
    }

    fn decode(from: &mut impl Read) -> Result<Self, failure::Error> {
        let mut buf = Vec::new();
        from.read_to_end(&mut buf)?;
        Self::from_slice(buf.as_ref())
            .ok_or_else(|| format_err!("Unable to decode value from bytes"))
    }

    fn size_hint(&self) -> Option<usize> {
        Some(self.as_ref().len())
    }
}

impl UniqueHash for PublicKey {}

// FIXME Maybe we should remove this implementations

impl BinaryForm for DateTime<Utc> {
    fn encode(&self, to: &mut impl Write) -> Result<(), failure::Error> {
        to.write_i64::<LittleEndian>(self.timestamp())?;
        to.write_u32::<LittleEndian>(self.timestamp_subsec_nanos())?;
        Ok(())
    }

    fn decode(from: &mut impl Read) -> Result<Self, failure::Error> {
        let secs = from.read_i64::<LittleEndian>()?;
        let nanos = from.read_u32::<LittleEndian>()?;
        Ok(Self::from_utc(
            NaiveDateTime::from_timestamp(secs, nanos),
            Utc,
        ))
    }

    fn size_hint(&self) -> Option<usize> {
        Some(12)
    }
}

impl UniqueHash for DateTime<Utc> {}

impl BinaryForm for Uuid {
    fn encode(&self, to: &mut impl Write) -> Result<(), failure::Error> {
        to.write_all(self.as_bytes()).map_err(failure::Error::from)
    }

    fn decode(from: &mut impl Read) -> Result<Self, failure::Error> {
        let mut buf = Vec::new();
        from.read_to_end(&mut buf)?;
        Self::from_slice(&buf).map_err(failure::Error::from)
    }

    fn size_hint(&self) -> Option<usize> {
        Some(self.as_bytes().len())
    }
}

impl UniqueHash for Uuid {}

impl BinaryForm for Decimal {
    fn encode(&self, to: &mut impl Write) -> Result<(), failure::Error> {
        to.write_all(&self.serialize())
            .map_err(failure::Error::from)
    }

    fn decode(from: &mut impl Read) -> Result<Self, failure::Error> {
        let mut buf: [u8; 16] = [0; 16];
        from.read_exact(&mut buf)?;
        Ok(Self::deserialize(buf))
    }

    fn size_hint(&self) -> Option<usize> {
        Some(16)
    }
}

impl UniqueHash for Decimal {}

#[cfg(test)]
mod tests {
    use std::fmt::Debug;
    use std::str::FromStr;

    use chrono::Duration;

    use super::*;

    fn assert_round_trip_eq<T: BinaryForm + PartialEq + Debug>(values: &[T]) {
        for value in values {
            let bytes = value.to_bytes().unwrap();
            assert_eq!(*value, <T as BinaryForm>::from_bytes(bytes).unwrap());
        }
    }

    macro_rules! impl_test_binary_form_scalar_unsigned {
        ($name:ident, $type:tt) => {
            #[test]
            fn $name() {
                let values = [$type::min_value(), 1, $type::max_value()];
                assert_round_trip_eq(&values);
            }
        };
    }

    macro_rules! impl_test_binary_form_scalar_signed {
        ($name:ident, $type:tt) => {
            #[test]
            fn $name() {
                let values = [$type::min_value(), -1, 0, 1, $type::max_value()];
                assert_round_trip_eq(&values);
            }
        };
    }

    // Impl tests for unsigned scalar types
    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u8,  u8 }
    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u32, u32 }
    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u16, u16 }
    impl_test_binary_form_scalar_unsigned! { test_binary_form_round_trip_u64, u64 }

    // Impl tests for signed scalar types
    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i8,  i8 }
    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i16, i16 }
    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i32, i32 }
    impl_test_binary_form_scalar_signed! { test_binary_form_round_trip_i64, i64 }

    // Tests for the other types

    #[test]
    fn test_binary_form_vec_u8() {
        let values = [vec![], vec![1], vec![1, 2, 3], vec![255; 100]];
        assert_round_trip_eq(&values);
    }

    #[test]
    fn test_binary_form_bool_correct() {
        let values = [true, false];
        assert_round_trip_eq(&values);
    }

    #[test]
    #[should_panic(expected = "Invalid value for bool: 2")]
    fn test_binary_form_bool_incorrect() {
        let bytes = 2.to_bytes().unwrap();
        <bool as BinaryForm>::from_bytes(&bytes).unwrap();
    }

    #[test]
    fn test_binary_form_string() {
        let values: Vec<_> = ["", "e", "2", "hello"]
            .iter()
            .map(|v| v.to_string())
            .collect();
        assert_round_trip_eq(&values);
    }

    #[test]
    fn test_binary_form_datetime() {
        use chrono::TimeZone;

        let times = [
            Utc.timestamp(0, 0),
            Utc.timestamp(13, 23),
            Utc::now(),
            Utc::now() + Duration::seconds(17) + Duration::nanoseconds(15),
            Utc.timestamp(0, 999_999_999),
            Utc.timestamp(0, 1_500_000_000), // leap second
        ];
        assert_round_trip_eq(&times);
    }

    #[test]
    fn test_binary_form_uuid() {
        let values = [
            Uuid::nil(),
            Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap(),
            Uuid::parse_str("0000002a-000c-0005-0c03-0938362b0809").unwrap(),
        ];
        assert_round_trip_eq(&values);
    }

    #[test]
    fn test_binary_form_decimal() {
        let values = [
            Decimal::from_str("3.14").unwrap(),
            Decimal::from_parts(1102470952, 185874565, 1703060790, false, 28),
            Decimal::new(9497628354687268, 12),
            Decimal::from_str("0").unwrap(),
            Decimal::from_str("-0.000000000000000000019").unwrap(),
        ];
        assert_round_trip_eq(&values);
    }
}
<|endoftext|>


<commit_before>//! Abstractions for page tables and other paging related structures.
//!
//! Page tables translate virtual memory “pages” to physical memory “frames”.

pub use self::frame_alloc::{FrameAllocator, FrameDeallocator};
pub use self::page_table::{PageTable, PageTableFlags};
#[cfg(target_arch = "x86_64")]
pub use self::page::{Page, PageSize, Size4KiB, Size2MiB, Size1GiB};
pub use self::frame::PhysFrame;
pub use self::mapper::{Mapper, RecursivePageTable};

use crate::{PhysAddr, VirtAddr};
use core::fmt;
use core::marker::PhantomData;
use core::ops::{Add, AddAssign, Sub, SubAssign};
use ux::*;

pub mod page;
pub mod frame;
pub mod page_table;
pub mod mapper;
mod frame_alloc;
<commit_msg>Re-export OffsetMapper<commit_after>//! Abstractions for page tables and other paging related structures.
//!
//! Page tables translate virtual memory “pages” to physical memory “frames”.

pub use self::frame_alloc::{FrameAllocator, FrameDeallocator};
pub use self::page_table::{PageTable, PageTableFlags};
#[cfg(target_arch = "x86_64")]
pub use self::page::{Page, PageSize, Size4KiB, Size2MiB, Size1GiB};
pub use self::frame::PhysFrame;
pub use self::mapper::{Mapper, RecursivePageTable, OffsetMapper};

use crate::{PhysAddr, VirtAddr};
use core::fmt;
use core::marker::PhantomData;
use core::ops::{Add, AddAssign, Sub, SubAssign};
use ux::*;

pub mod page;
pub mod frame;
pub mod page_table;
pub mod mapper;
mod frame_alloc;
<|endoftext|>


<commit_before>use backend::Backend;
use provider::error;
use provider::Provider;
use provider::Output;
use libc::{c_char, uint32_t, int64_t};
use std::ffi::CString;
use std::ffi::CStr;

pub struct File<'a> {
    name: &'static str,
    backend: &'a Backend,
    provider: &'a Provider,
}

impl<'a> File<'a> {
    pub fn new(n: &'static str, b: &'a Backend, p: &'a Provider) -> File<'a> {
        File {
            name: n,
            backend: b,
            provider: p,
        }
    }

    pub fn mode(&self) -> Result<u32, error::Error> {
        self.backend
            .handle(self.provider.file.mode(self.name))
            .and_then(Output::to_u32)
    }

    pub fn size(&self) -> Result<i64, error::Error> {
        self.backend
            .handle(self.provider.file.size(self.name))
            .and_then(Output::to_i64)
    }

    pub fn is_file(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_file(self.name))
            .and_then(Output::to_bool)
    }

    pub fn exist(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.exist(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_directory(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_directory(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_block_device(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_block_device(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_character_device(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_character_device(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_pipe(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_pipe(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_socket(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_socket(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_symlink(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_symlink(self.name))
            .and_then(Output::to_bool)
    }

    pub fn contents(&self) -> Result<String, error::Error> {
        self.backend
            .handle(self.provider.file.contents(self.name))
            .and_then(Output::to_string)
    }

    pub fn owner(&self) -> Result<String, error::Error> {
        self.backend
            .handle(self.provider.file.owner(self.name))
            .and_then(Output::to_string)
    }

    pub fn group(&self) -> Result<String, error::Error> {
        self.backend
            .handle(self.provider.file.group(self.name))
            .and_then(Output::to_string)
    }

    pub fn linked_to(&self) -> Result<String, error::Error> {
        self.backend
            .handle(self.provider.file.linked_to(self.name))
            .and_then(Output::to_string)
    }

    pub fn is_readable(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_readable(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_readable_by_owner(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_readable_by_owner(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_readable_by_group(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_readable_by_group(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_readable_by_others(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_readable_by_others(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_readable_by_user(&self, user: &'static str) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_readable_by_user(self.name, user))
            .and_then(Output::to_bool)
    }

    pub fn is_writable(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_writable(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_writable_by_owner(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_writable_by_owner(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_writable_by_group(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_writable_by_group(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_writable_by_others(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_writable_by_others(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_writable_by_user(&self, user: &'static str) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_writable_by_user(self.name, user))
            .and_then(Output::to_bool)
    }

    pub fn md5sum(&self) -> Result<String, error::Error> {
        self.backend
            .handle(self.provider.file.md5sum(self.name))
            .and_then(Output::to_string)
    }

    pub fn sha256sum(&self) -> Result<String, error::Error> {
        self.backend
            .handle(self.provider.file.sha256sum(self.name))
            .and_then(Output::to_string)
    }
}

// Wrapper functions for FFI

#[no_mangle]
pub extern "C" fn resource_file_free(ptr: *mut File) {
    if ptr.is_null() {
        return;
    }
    unsafe {
        Box::from_raw(ptr);
    }
}

#[no_mangle]
pub extern "C" fn resource_file_mode(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    f.mode().unwrap()
}

#[no_mangle]
pub extern "C" fn resource_file_is_file(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_file().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_exist(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.exist().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_directory(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_directory().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_block_device(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_block_device().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_character_device(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_character_device().unwrap() {
        1
    } else {
        0
    }
}

#[no_mangle]
pub extern "C" fn resource_file_is_pipe(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_pipe().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_socket(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_socket().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_symlink(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_symlink().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_contents(ptr: *const File) -> *mut c_char {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };
    let c = f.contents().unwrap();
    CString::new(c).unwrap().into_raw()
}

#[no_mangle]
pub extern "C" fn resource_file_owner(ptr: *const File) -> *mut c_char {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };
    let c = f.owner().unwrap();
    CString::new(c).unwrap().into_raw()
}

#[no_mangle]
pub extern "C" fn resource_file_group(ptr: *const File) -> *mut c_char {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };
    let c = f.group().unwrap();
    CString::new(c).unwrap().into_raw()
}

#[no_mangle]
pub extern "C" fn resource_file_is_readable(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_readable().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_readable_by_owner(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_readable_by_owner().unwrap() {
        1
    } else {
        0
    }
}

#[no_mangle]
pub extern "C" fn resource_file_is_readable_by_group(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_readable_by_group().unwrap() {
        1
    } else {
        0
    }
}

#[no_mangle]
pub extern "C" fn resource_file_is_readable_by_others(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_readable_by_others().unwrap() {
        1
    } else {
        0
    }
}

#[no_mangle]
pub extern "C" fn resource_file_is_readable_by_user(ptr: *const File,
                                                    u: *const c_char)
                                                    -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    let c_str = unsafe {
        assert!(!u.is_null());
        CStr::from_ptr(u)
    };

    let user = c_str.to_str().unwrap();
    if f.is_readable_by_user(user).unwrap() {
        1
    } else {
        0
    }
}

#[no_mangle]
pub extern "C" fn resource_file_is_writable(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_writable().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_writable_by_owner(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_writable_by_owner().unwrap() {
        1
    } else {
        0
    }
}

#[no_mangle]
pub extern "C" fn resource_file_is_writable_by_group(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_writable_by_group().unwrap() {
        1
    } else {
        0
    }
}

#[no_mangle]
pub extern "C" fn resource_file_is_writable_by_others(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_writable_by_others().unwrap() {
        1
    } else {
        0
    }
}

#[no_mangle]
pub extern "C" fn resource_file_is_writable_by_user(ptr: *const File,
                                                    u: *const c_char)
                                                    -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    let c_str = unsafe {
        assert!(!u.is_null());
        CStr::from_ptr(u)
    };

    let user = c_str.to_str().unwrap();
    if f.is_writable_by_user(user).unwrap() {
        1
    } else {
        0
    }
}

#[no_mangle]
pub extern "C" fn resource_file_md5sum(ptr: *const File) -> *mut c_char {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };
    let c = f.md5sum().unwrap();
    CString::new(c).unwrap().into_raw()
}

#[no_mangle]
pub extern "C" fn resource_file_sha256sum(ptr: *const File) -> *mut c_char {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };
    let c = f.sha256sum().unwrap();
    CString::new(c).unwrap().into_raw()
}

#[no_mangle]
pub extern "C" fn resource_file_size(ptr: *const File) -> int64_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    f.size().unwrap()
}
<commit_msg>Add wrapper function for file.linked_to()<commit_after>use backend::Backend;
use provider::error;
use provider::Provider;
use provider::Output;
use libc::{c_char, uint32_t, int64_t};
use std::ffi::CString;
use std::ffi::CStr;

pub struct File<'a> {
    name: &'static str,
    backend: &'a Backend,
    provider: &'a Provider,
}

impl<'a> File<'a> {
    pub fn new(n: &'static str, b: &'a Backend, p: &'a Provider) -> File<'a> {
        File {
            name: n,
            backend: b,
            provider: p,
        }
    }

    pub fn mode(&self) -> Result<u32, error::Error> {
        self.backend
            .handle(self.provider.file.mode(self.name))
            .and_then(Output::to_u32)
    }

    pub fn size(&self) -> Result<i64, error::Error> {
        self.backend
            .handle(self.provider.file.size(self.name))
            .and_then(Output::to_i64)
    }

    pub fn is_file(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_file(self.name))
            .and_then(Output::to_bool)
    }

    pub fn exist(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.exist(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_directory(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_directory(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_block_device(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_block_device(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_character_device(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_character_device(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_pipe(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_pipe(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_socket(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_socket(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_symlink(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_symlink(self.name))
            .and_then(Output::to_bool)
    }

    pub fn contents(&self) -> Result<String, error::Error> {
        self.backend
            .handle(self.provider.file.contents(self.name))
            .and_then(Output::to_string)
    }

    pub fn owner(&self) -> Result<String, error::Error> {
        self.backend
            .handle(self.provider.file.owner(self.name))
            .and_then(Output::to_string)
    }

    pub fn group(&self) -> Result<String, error::Error> {
        self.backend
            .handle(self.provider.file.group(self.name))
            .and_then(Output::to_string)
    }

    pub fn linked_to(&self) -> Result<String, error::Error> {
        self.backend
            .handle(self.provider.file.linked_to(self.name))
            .and_then(Output::to_string)
    }

    pub fn is_readable(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_readable(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_readable_by_owner(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_readable_by_owner(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_readable_by_group(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_readable_by_group(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_readable_by_others(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_readable_by_others(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_readable_by_user(&self, user: &'static str) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_readable_by_user(self.name, user))
            .and_then(Output::to_bool)
    }

    pub fn is_writable(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_writable(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_writable_by_owner(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_writable_by_owner(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_writable_by_group(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_writable_by_group(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_writable_by_others(&self) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_writable_by_others(self.name))
            .and_then(Output::to_bool)
    }

    pub fn is_writable_by_user(&self, user: &'static str) -> Result<bool, error::Error> {
        self.backend
            .handle(self.provider.file.is_writable_by_user(self.name, user))
            .and_then(Output::to_bool)
    }

    pub fn md5sum(&self) -> Result<String, error::Error> {
        self.backend
            .handle(self.provider.file.md5sum(self.name))
            .and_then(Output::to_string)
    }

    pub fn sha256sum(&self) -> Result<String, error::Error> {
        self.backend
            .handle(self.provider.file.sha256sum(self.name))
            .and_then(Output::to_string)
    }
}

// Wrapper functions for FFI

#[no_mangle]
pub extern "C" fn resource_file_free(ptr: *mut File) {
    if ptr.is_null() {
        return;
    }
    unsafe {
        Box::from_raw(ptr);
    }
}

#[no_mangle]
pub extern "C" fn resource_file_mode(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    f.mode().unwrap()
}

#[no_mangle]
pub extern "C" fn resource_file_is_file(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_file().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_exist(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.exist().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_directory(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_directory().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_block_device(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_block_device().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_character_device(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_character_device().unwrap() {
        1
    } else {
        0
    }
}

#[no_mangle]
pub extern "C" fn resource_file_is_pipe(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_pipe().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_socket(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_socket().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_symlink(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_symlink().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_contents(ptr: *const File) -> *mut c_char {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };
    let c = f.contents().unwrap();
    CString::new(c).unwrap().into_raw()
}

#[no_mangle]
pub extern "C" fn resource_file_owner(ptr: *const File) -> *mut c_char {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };
    let c = f.owner().unwrap();
    CString::new(c).unwrap().into_raw()
}

#[no_mangle]
pub extern "C" fn resource_file_group(ptr: *const File) -> *mut c_char {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };
    let c = f.group().unwrap();
    CString::new(c).unwrap().into_raw()
}

#[no_mangle]
pub extern "C" fn resource_file_is_readable(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_readable().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_readable_by_owner(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_readable_by_owner().unwrap() {
        1
    } else {
        0
    }
}

#[no_mangle]
pub extern "C" fn resource_file_is_readable_by_group(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_readable_by_group().unwrap() {
        1
    } else {
        0
    }
}

#[no_mangle]
pub extern "C" fn resource_file_is_readable_by_others(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_readable_by_others().unwrap() {
        1
    } else {
        0
    }
}

#[no_mangle]
pub extern "C" fn resource_file_is_readable_by_user(ptr: *const File,
                                                    u: *const c_char)
                                                    -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    let c_str = unsafe {
        assert!(!u.is_null());
        CStr::from_ptr(u)
    };

    let user = c_str.to_str().unwrap();
    if f.is_readable_by_user(user).unwrap() {
        1
    } else {
        0
    }
}

#[no_mangle]
pub extern "C" fn resource_file_is_writable(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_writable().unwrap() { 1 } else { 0 }
}

#[no_mangle]
pub extern "C" fn resource_file_is_writable_by_owner(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_writable_by_owner().unwrap() {
        1
    } else {
        0
    }
}

#[no_mangle]
pub extern "C" fn resource_file_is_writable_by_group(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_writable_by_group().unwrap() {
        1
    } else {
        0
    }
}

#[no_mangle]
pub extern "C" fn resource_file_is_writable_by_others(ptr: *const File) -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    if f.is_writable_by_others().unwrap() {
        1
    } else {
        0
    }
}

#[no_mangle]
pub extern "C" fn resource_file_is_writable_by_user(ptr: *const File,
                                                    u: *const c_char)
                                                    -> uint32_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    let c_str = unsafe {
        assert!(!u.is_null());
        CStr::from_ptr(u)
    };

    let user = c_str.to_str().unwrap();
    if f.is_writable_by_user(user).unwrap() {
        1
    } else {
        0
    }
}

#[no_mangle]
pub extern "C" fn resource_file_md5sum(ptr: *const File) -> *mut c_char {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };
    let c = f.md5sum().unwrap();
    CString::new(c).unwrap().into_raw()
}

#[no_mangle]
pub extern "C" fn resource_file_sha256sum(ptr: *const File) -> *mut c_char {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };
    let c = f.sha256sum().unwrap();
    CString::new(c).unwrap().into_raw()
}

#[no_mangle]
pub extern "C" fn resource_file_size(ptr: *const File) -> int64_t {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };

    f.size().unwrap()
}

#[no_mangle]
pub extern "C" fn resource_file_linked_to(ptr: *const File) -> *mut c_char {
    let f = unsafe {
        assert!(!ptr.is_null());
        &*ptr
    };
    let c = f.linked_to().unwrap();
    CString::new(c).unwrap().into_raw()
}
<|endoftext|>


<commit_before>// -*- rust -*-

fn main() {
  let int a = 1;
  let int b = 2;
  a ^= b;
  b ^= a;
  a = a ^ b;
  log a;
  log b;
  assert (b == 1);
  assert (a == 2);

  assert (~(0xf0) & 0xff == 0xf);
  assert (0xf0 | 0xf == 0xff);
  assert (0xf << 4 == 0xf0);
  assert (0xf0 >> 4 == 0xf);
  assert (-16 >>> 2 == -4);
  assert (0b1010_1010 | 0b0101_0101 == 0xff);
}

<commit_msg>test: Change bitwise.rs to use ! instead of ~. Should put out burning tinderbox.<commit_after>// -*- rust -*-

fn main() {
  let int a = 1;
  let int b = 2;
  a ^= b;
  b ^= a;
  a = a ^ b;
  log a;
  log b;
  assert (b == 1);
  assert (a == 2);

  assert (!(0xf0) & 0xff == 0xf);
  assert (0xf0 | 0xf == 0xff);
  assert (0xf << 4 == 0xf0);
  assert (0xf0 >> 4 == 0xf);
  assert (-16 >>> 2 == -4);
  assert (0b1010_1010 | 0b0101_0101 == 0xff);
}

<|endoftext|>


<commit_before>extern crate iron;
extern crate mount;
extern crate rand;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate staticfile;

use application::Application;
use application::ApplicationConfiguration;
use iron::method::Method;
use iron::prelude::*;
use iron::status::Status;
use mount::Mount;
use staticfile::Static;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;
use std::time::Duration;

mod application;

static CONFIG_FILE_NAME: &str = "find-reviewer.json";

type SharedApplication = Arc<Mutex<Application>>;

fn main() {
    let configuration = load_configuration();
    let application = SharedApplication::new(Mutex::new(Application::new(configuration)));

    let mut mount = Mount::new();
    mount
        .mount("/find-reviewer", {
            let application = application.clone();
            move |request: &mut Request| Ok(process_request(request, &application))
        })
        .mount("/", Static::new(Path::new("www")));

    thread::spawn(move || loop {
        thread::sleep(Duration::from_secs(1));
        application.lock().unwrap().process_timeouts();
    });

    Iron::new(mount).http("localhost:3000").unwrap();
}

fn load_configuration() -> ApplicationConfiguration {
    let config = File::open(CONFIG_FILE_NAME)
        .map(|open_file| serde_json::from_reader(open_file).expect(&format!("Could not parse {}", CONFIG_FILE_NAME)))
        .unwrap_or_else(|err| {
            println!("Could not read {}: {}\nFile will be created", CONFIG_FILE_NAME, err);
            ApplicationConfiguration::default()
        });

    File::create(CONFIG_FILE_NAME)
        .map(|created_file| {
            serde_json::to_writer_pretty(created_file, &config).expect(&format!("Could not serialize {}", CONFIG_FILE_NAME))
        })
        .unwrap_or_else(|err| println!("Could not write {}: {}", CONFIG_FILE_NAME, err));

    config
}

fn process_request(request: &mut Request, application: &SharedApplication) -> Response {
    if request.method != Method::Post {
        return Response::with((Status::BadRequest, "Must be a POST request"));
    }

    let parsed = match serde_json::from_reader(request.body.by_ref()) {
        Err(message) => return Response::with((Status::BadRequest, format!("JSON error: {}", message))),
        Ok(request) => request,
    };

    let response = application.lock().unwrap().dispatch_request(parsed);

    Response::with((Status::Ok, serde_json::to_string_pretty(&response).unwrap()))
}
<commit_msg>Factor out methods<commit_after>extern crate iron;
extern crate mount;
extern crate rand;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate staticfile;

use application::Application;
use application::ApplicationConfiguration;
use iron::method::Method;
use iron::prelude::*;
use iron::status::Status;
use mount::Mount;
use staticfile::Static;
use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::sync::Arc;
use std::sync::Mutex;
use std::thread;
use std::time::Duration;

mod application;

static CONFIG_FILE_NAME: &str = "find-reviewer.json";

type SharedApplication = Arc<Mutex<Application>>;

fn main() {
    let configuration = load_configuration();
    save_configuration(&configuration);

    let application = SharedApplication::new(Mutex::new(Application::new(configuration)));

    start_timeout_loop(application.clone());
    start_service(application);
}

fn load_configuration() -> ApplicationConfiguration {
    File::open(CONFIG_FILE_NAME)
        .map(|open_file| serde_json::from_reader(open_file).expect(&format!("Could not parse {}", CONFIG_FILE_NAME)))
        .unwrap_or_else(|err| {
            println!("Could not read {}: {}\nFile will be created", CONFIG_FILE_NAME, err);
            ApplicationConfiguration::default()
        })
}

fn save_configuration(configuration: &ApplicationConfiguration) {
    File::create(CONFIG_FILE_NAME)
        .map(|created_file| {
            serde_json::to_writer_pretty(created_file, &configuration).expect(&format!("Could not serialize {}", CONFIG_FILE_NAME))
        })
        .unwrap_or_else(|err| println!("Could not write {}: {}", CONFIG_FILE_NAME, err));
}

fn start_timeout_loop(application: SharedApplication) {
    thread::spawn(move || loop {
        thread::sleep(Duration::from_secs(1));
        application.lock().unwrap().process_timeouts();
    });
}

fn start_service(application: SharedApplication) {
    let mut mount = Mount::new();
    mount
        .mount("/find-reviewer", move |request: &mut Request| Ok(process_request(request, &application)))
        .mount("/", Static::new(Path::new("www")));

    Iron::new(mount).http("localhost:3000").unwrap();
}

fn process_request(request: &mut Request, application: &SharedApplication) -> Response {
    if request.method != Method::Post {
        return Response::with((Status::BadRequest, "Must be a POST request"));
    }

    let parsed = match serde_json::from_reader(request.body.by_ref()) {
        Err(message) => return Response::with((Status::BadRequest, format!("JSON error: {}", message))),
        Ok(request) => request,
    };

    let response = application.lock().unwrap().dispatch_request(parsed);

    Response::with((Status::Ok, serde_json::to_string_pretty(&response).unwrap()))
}
<|endoftext|>


<commit_before>use crate::{
    builtin_functions::BuiltinFunction,
    compiler::{
        hir_to_lir::HirToLir,
        lir::{Instruction, Lir},
    },
    database::Database,
    input::Input,
};
use im::HashMap;
use itertools::Itertools;
use std::fmt::{self, Display, Formatter};

/// A self-contained value. Unlike objects, these are not tied to a running VM,
/// which makes them useful for being sent through channels between multiple
/// reference-counted heaps, for example ones running concurrently logically, on
/// other cores, or on different computers.
///
/// VMs can import these values to turn them into heap-contained,
/// reference-counted objects. They can export objects from the heap into
/// self-contained values.
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum Value {
    Int(u64),
    Text(String),
    Symbol(String),
    Struct(HashMap<Value, Value>),
    Closure(Closure),
    Builtin(BuiltinFunction),
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct Closure {
    pub captured: Vec<Value>,
    pub num_args: usize,
    pub body: Vec<Instruction>,
}

impl Value {
    pub fn nothing() -> Self {
        Value::Symbol("Nothing".to_owned())
    }

    pub fn list(items: Vec<Value>) -> Self {
        let items = items
            .into_iter()
            .enumerate()
            .map(|(index, it)| (Value::Int(index as u64), it))
            .collect();
        Value::Struct(items)
    }

    pub fn try_into_text(self) -> Result<String, Value> {
        match self {
            Value::Text(text) => Ok(text),
            it => Err(it),
        }
    }
}
impl Closure {
    pub fn of_lir(input: Input, lir: Lir) -> Self {
        Closure {
            captured: vec![],
            num_args: 0,
            body: vec![
                Instruction::TraceModuleStarts { input },
                Instruction::CreateClosure {
                    captured: vec![],
                    num_args: 0,
                    body: lir.instructions.clone(),
                },
                Instruction::Call { num_args: 0 },
                Instruction::TraceModuleEnds,
                Instruction::Return,
            ],
        }
    }
    pub fn of_input(db: &Database, input: Input) -> Option<Self> {
        let lir = db.lir(input.clone())?;
        Some(Self::of_lir(input, (*lir).clone()))
    }
}

impl Display for Value {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            Value::Int(int) => write!(f, "{int}"),
            Value::Text(text) => write!(f, "{text:?}"),
            Value::Symbol(symbol) => write!(f, "{symbol}"),
            Value::Struct(entries) => write!(
                f,
                "[ {} ]",
                entries
                    .iter()
                    .map(|(key, value)| format!("{}: {}", key, value))
                    .join(", ")
            ),
            Value::Closure { .. } => write!(f, "{{...}}"),
            Value::Builtin(builtin) => write!(f, "builtin{builtin:?}"),
        }
    }
}

impl From<u64> for Value {
    fn from(value: u64) -> Self {
        Value::Int(value)
    }
}
impl From<String> for Value {
    fn from(value: String) -> Self {
        Value::Text(value)
    }
}
impl From<bool> for Value {
    fn from(it: bool) -> Self {
        Value::Symbol(if it { "True" } else { "False" }.to_string())
    }
}
<commit_msg>Use ellipsis for displaying closure<commit_after>use crate::{
    builtin_functions::BuiltinFunction,
    compiler::{
        hir_to_lir::HirToLir,
        lir::{Instruction, Lir},
    },
    database::Database,
    input::Input,
};
use im::HashMap;
use itertools::Itertools;
use std::fmt::{self, Display, Formatter};

/// A self-contained value. Unlike objects, these are not tied to a running VM,
/// which makes them useful for being sent through channels between multiple
/// reference-counted heaps, for example ones running concurrently logically, on
/// other cores, or on different computers.
///
/// VMs can import these values to turn them into heap-contained,
/// reference-counted objects. They can export objects from the heap into
/// self-contained values.
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub enum Value {
    Int(u64),
    Text(String),
    Symbol(String),
    Struct(HashMap<Value, Value>),
    Closure(Closure),
    Builtin(BuiltinFunction),
}
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct Closure {
    pub captured: Vec<Value>,
    pub num_args: usize,
    pub body: Vec<Instruction>,
}

impl Value {
    pub fn nothing() -> Self {
        Value::Symbol("Nothing".to_owned())
    }

    pub fn list(items: Vec<Value>) -> Self {
        let items = items
            .into_iter()
            .enumerate()
            .map(|(index, it)| (Value::Int(index as u64), it))
            .collect();
        Value::Struct(items)
    }

    pub fn try_into_text(self) -> Result<String, Value> {
        match self {
            Value::Text(text) => Ok(text),
            it => Err(it),
        }
    }
}
impl Closure {
    pub fn of_lir(input: Input, lir: Lir) -> Self {
        Closure {
            captured: vec![],
            num_args: 0,
            body: vec![
                Instruction::TraceModuleStarts { input },
                Instruction::CreateClosure {
                    captured: vec![],
                    num_args: 0,
                    body: lir.instructions.clone(),
                },
                Instruction::Call { num_args: 0 },
                Instruction::TraceModuleEnds,
                Instruction::Return,
            ],
        }
    }
    pub fn of_input(db: &Database, input: Input) -> Option<Self> {
        let lir = db.lir(input.clone())?;
        Some(Self::of_lir(input, (*lir).clone()))
    }
}

impl Display for Value {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        match self {
            Value::Int(int) => write!(f, "{int}"),
            Value::Text(text) => write!(f, "{text:?}"),
            Value::Symbol(symbol) => write!(f, "{symbol}"),
            Value::Struct(entries) => write!(
                f,
                "[ {} ]",
                entries
                    .iter()
                    .map(|(key, value)| format!("{}: {}", key, value))
                    .join(", ")
            ),
            Value::Closure(_) => write!(f, "{{…}}"),
            Value::Builtin(builtin) => write!(f, "builtin{builtin:?}"),
        }
    }
}

impl From<u64> for Value {
    fn from(value: u64) -> Self {
        Value::Int(value)
    }
}
impl From<String> for Value {
    fn from(value: String) -> Self {
        Value::Text(value)
    }
}
impl From<bool> for Value {
    fn from(it: bool) -> Self {
        Value::Symbol(if it { "True" } else { "False" }.to_string())
    }
}
<|endoftext|>


<commit_before>use crate::utils::{last_path_segment, span_lint_and_help};
use rustc_hir::{
    intravisit, Body, Expr, ExprKind, FieldPat, FnDecl, HirId, LocalSource, MatchSource, Mutability, Pat, PatKind,
    QPath, Stmt, StmtKind,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{AdtDef, FieldDef, Ty, TyKind, VariantDef};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for patterns that aren't exact representations of the types
    /// they are applied to.
    ///
    /// To satisfy this lint, you will have to adjust either the expression that is matched
    /// against or the pattern itself, as well as the bindings that are introduced by the
    /// adjusted patterns. For matching you will have to either dereference the expression
    /// with the `*` operator, or amend the patterns to explicitly match against `&<pattern>`
    /// or `&mut <pattern>` depending on the reference mutability. For the bindings you need
    /// to use the inverse. You can leave them as plain bindings if you wish for the value
    /// to be copied, but you must use `ref mut <variable>` or `ref <variable>` to construct
    /// a reference into the matched structure.
    ///
    /// If you are looking for a way to learn about ownership semantics in more detail, it
    /// is recommended to look at IDE options available to you to highlight types, lifetimes
    /// and reference semantics in your code. The available tooling would expose these things
    /// in a general way even outside of the various pattern matching mechanics. Of course
    /// this lint can still be used to highlight areas of interest and ensure a good understanding
    /// of ownership semantics.
    ///
    /// **Why is this bad?** It isn't bad in general. But in some contexts it can be desirable
    /// because it increases ownership hints in the code, and will guard against some changes
    /// in ownership.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// This example shows the basic adjustments necessary to satisfy the lint. Note how
    /// the matched expression is explicitly dereferenced with `*` and the `inner` variable
    /// is bound to a shared borrow via `ref inner`.
    ///
    /// ```rust,ignore
    /// // Bad
    /// let value = &Some(Box::new(23));
    /// match value {
    ///     Some(inner) => println!("{}", inner),
    ///     None => println!("none"),
    /// }
    ///
    /// // Good
    /// let value = &Some(Box::new(23));
    /// match *value {
    ///     Some(ref inner) => println!("{}", inner),
    ///     None => println!("none"),
    /// }
    /// ```
    ///
    /// The following example demonstrates one of the advantages of the more verbose style.
    /// Note how the second version uses `ref mut a` to explicitly declare `a` a shared mutable
    /// borrow, while `b` is simply taken by value. This ensures that the loop body cannot
    /// accidentally modify the wrong part of the structure.
    ///
    /// ```rust,ignore
    /// // Bad
    /// let mut values = vec![(2, 3), (3, 4)];
    /// for (a, b) in &mut values {
    ///     *a += *b;
    /// }
    ///
    /// // Good
    /// let mut values = vec![(2, 3), (3, 4)];
    /// for &mut (ref mut a, b) in &mut values {
    ///     *a += b;
    /// }
    /// ```
    pub PATTERN_TYPE_MISMATCH,
    restriction,
    "type of pattern does not match the expression type"
}

declare_lint_pass!(PatternTypeMismatch => [PATTERN_TYPE_MISMATCH]);

impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch {
    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
        if let StmtKind::Local(ref local) = stmt.kind {
            if let Some(init) = &local.init {
                if let Some(init_ty) = cx.tables().node_type_opt(init.hir_id) {
                    let pat = &local.pat;
                    if in_external_macro(cx.sess(), pat.span) {
                        return;
                    }
                    let deref_possible = match local.source {
                        LocalSource::Normal => DerefPossible::Possible,
                        _ => DerefPossible::Impossible,
                    };
                    apply_lint(cx, pat, init_ty, deref_possible);
                }
            }
        }
    }

    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        if let ExprKind::Match(ref expr, arms, source) = expr.kind {
            match source {
                MatchSource::Normal | MatchSource::IfLetDesugar { .. } | MatchSource::WhileLetDesugar => {
                    if let Some(expr_ty) = cx.tables().node_type_opt(expr.hir_id) {
                        'pattern_checks: for arm in arms {
                            let pat = &arm.pat;
                            if in_external_macro(cx.sess(), pat.span) {
                                continue 'pattern_checks;
                            }
                            if apply_lint(cx, pat, expr_ty, DerefPossible::Possible) {
                                break 'pattern_checks;
                            }
                        }
                    }
                },
                _ => (),
            }
        }
    }

    fn check_fn(
        &mut self,
        cx: &LateContext<'tcx>,
        _: intravisit::FnKind<'tcx>,
        _: &'tcx FnDecl<'_>,
        body: &'tcx Body<'_>,
        _: Span,
        hir_id: HirId,
    ) {
        if let Some(fn_sig) = cx.tables().liberated_fn_sigs().get(hir_id) {
            for (param, ty) in body.params.iter().zip(fn_sig.inputs().iter()) {
                apply_lint(cx, &param.pat, ty, DerefPossible::Impossible);
            }
        }
    }
}

#[derive(Debug, Clone, Copy)]
enum DerefPossible {
    Possible,
    Impossible,
}

fn apply_lint<'tcx>(
    cx: &LateContext<'tcx>,
    pat: &Pat<'_>,
    expr_ty: Ty<'tcx>,
    deref_possible: DerefPossible,
) -> bool {
    let maybe_mismatch = find_first_mismatch(cx, pat, expr_ty, Level::Top);
    if let Some((span, mutability, level)) = maybe_mismatch {
        span_lint_and_help(
            cx,
            PATTERN_TYPE_MISMATCH,
            span,
            "type of pattern does not match the expression type",
            None,
            &format!(
                "{}explicitly match against a `{}` pattern and adjust the enclosed variable bindings",
                match (deref_possible, level) {
                    (DerefPossible::Possible, Level::Top) => "use `*` to dereference the match expression or ",
                    _ => "",
                },
                match mutability {
                    Mutability::Mut => "&mut _",
                    Mutability::Not => "&_",
                },
            ),
        );
        true
    } else {
        false
    }
}

#[derive(Debug, Copy, Clone)]
enum Level {
    Top,
    Lower,
}

#[allow(rustc::usage_of_ty_tykind)]
fn find_first_mismatch<'tcx>(
    cx: &LateContext<'tcx>,
    pat: &Pat<'_>,
    ty: Ty<'tcx>,
    level: Level,
) -> Option<(Span, Mutability, Level)> {
    if let PatKind::Ref(ref sub_pat, _) = pat.kind {
        if let TyKind::Ref(_, sub_ty, _) = ty.kind {
            return find_first_mismatch(cx, sub_pat, sub_ty, Level::Lower);
        }
    }

    if let TyKind::Ref(_, _, mutability) = ty.kind {
        if is_non_ref_pattern(&pat.kind) {
            return Some((pat.span, mutability, level));
        }
    }

    if let PatKind::Struct(ref qpath, ref field_pats, _) = pat.kind {
        if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind {
            if let Some(variant) = get_variant(adt_def, qpath) {
                let field_defs = &variant.fields;
                return find_first_mismatch_in_struct(cx, field_pats, field_defs, substs_ref);
            }
        }
    }

    if let PatKind::TupleStruct(ref qpath, ref pats, _) = pat.kind {
        if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind {
            if let Some(variant) = get_variant(adt_def, qpath) {
                let field_defs = &variant.fields;
                let ty_iter = field_defs.iter().map(|field_def| field_def.ty(cx.tcx, substs_ref));
                return find_first_mismatch_in_tuple(cx, pats, ty_iter);
            }
        }
    }

    if let PatKind::Tuple(ref pats, _) = pat.kind {
        if let TyKind::Tuple(..) = ty.kind {
            return find_first_mismatch_in_tuple(cx, pats, ty.tuple_fields());
        }
    }

    if let PatKind::Or(sub_pats) = pat.kind {
        for pat in sub_pats {
            let maybe_mismatch = find_first_mismatch(cx, pat, ty, level);
            if let Some(mismatch) = maybe_mismatch {
                return Some(mismatch);
            }
        }
    }

    None
}

fn get_variant<'a>(adt_def: &'a AdtDef, qpath: &QPath<'_>) -> Option<&'a VariantDef> {
    if adt_def.is_struct() {
        if let Some(variant) = adt_def.variants.iter().next() {
            return Some(variant);
        }
    }

    if adt_def.is_enum() {
        let pat_ident = last_path_segment(qpath).ident;
        for variant in &adt_def.variants {
            if variant.ident == pat_ident {
                return Some(variant);
            }
        }
    }

    None
}

fn find_first_mismatch_in_tuple<'tcx, I>(
    cx: &LateContext<'tcx>,
    pats: &[&Pat<'_>],
    ty_iter_src: I,
) -> Option<(Span, Mutability, Level)>
where
    I: IntoIterator<Item = Ty<'tcx>>,
{
    let mut field_tys = ty_iter_src.into_iter();
    'fields: for pat in pats {
        let field_ty = if let Some(ty) = field_tys.next() {
            ty
        } else {
            break 'fields;
        };

        let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower);
        if let Some(mismatch) = maybe_mismatch {
            return Some(mismatch);
        }
    }

    None
}

fn find_first_mismatch_in_struct<'tcx>(
    cx: &LateContext<'tcx>,
    field_pats: &[FieldPat<'_>],
    field_defs: &[FieldDef],
    substs_ref: SubstsRef<'tcx>,
) -> Option<(Span, Mutability, Level)> {
    for field_pat in field_pats {
        'definitions: for field_def in field_defs {
            if field_pat.ident == field_def.ident {
                let field_ty = field_def.ty(cx.tcx, substs_ref);
                let pat = &field_pat.pat;
                let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower);
                if let Some(mismatch) = maybe_mismatch {
                    return Some(mismatch);
                }
                break 'definitions;
            }
        }
    }

    None
}

fn is_non_ref_pattern(pat_kind: &PatKind<'_>) -> bool {
    match pat_kind {
        PatKind::Struct(..) | PatKind::Tuple(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => true,
        PatKind::Or(sub_pats) => sub_pats.iter().any(|pat| is_non_ref_pattern(&pat.kind)),
        _ => false,
    }
}
<commit_msg>fmt fix<commit_after>use crate::utils::{last_path_segment, span_lint_and_help};
use rustc_hir::{
    intravisit, Body, Expr, ExprKind, FieldPat, FnDecl, HirId, LocalSource, MatchSource, Mutability, Pat, PatKind,
    QPath, Stmt, StmtKind,
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{AdtDef, FieldDef, Ty, TyKind, VariantDef};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::source_map::Span;

declare_clippy_lint! {
    /// **What it does:** Checks for patterns that aren't exact representations of the types
    /// they are applied to.
    ///
    /// To satisfy this lint, you will have to adjust either the expression that is matched
    /// against or the pattern itself, as well as the bindings that are introduced by the
    /// adjusted patterns. For matching you will have to either dereference the expression
    /// with the `*` operator, or amend the patterns to explicitly match against `&<pattern>`
    /// or `&mut <pattern>` depending on the reference mutability. For the bindings you need
    /// to use the inverse. You can leave them as plain bindings if you wish for the value
    /// to be copied, but you must use `ref mut <variable>` or `ref <variable>` to construct
    /// a reference into the matched structure.
    ///
    /// If you are looking for a way to learn about ownership semantics in more detail, it
    /// is recommended to look at IDE options available to you to highlight types, lifetimes
    /// and reference semantics in your code. The available tooling would expose these things
    /// in a general way even outside of the various pattern matching mechanics. Of course
    /// this lint can still be used to highlight areas of interest and ensure a good understanding
    /// of ownership semantics.
    ///
    /// **Why is this bad?** It isn't bad in general. But in some contexts it can be desirable
    /// because it increases ownership hints in the code, and will guard against some changes
    /// in ownership.
    ///
    /// **Known problems:** None.
    ///
    /// **Example:**
    ///
    /// This example shows the basic adjustments necessary to satisfy the lint. Note how
    /// the matched expression is explicitly dereferenced with `*` and the `inner` variable
    /// is bound to a shared borrow via `ref inner`.
    ///
    /// ```rust,ignore
    /// // Bad
    /// let value = &Some(Box::new(23));
    /// match value {
    ///     Some(inner) => println!("{}", inner),
    ///     None => println!("none"),
    /// }
    ///
    /// // Good
    /// let value = &Some(Box::new(23));
    /// match *value {
    ///     Some(ref inner) => println!("{}", inner),
    ///     None => println!("none"),
    /// }
    /// ```
    ///
    /// The following example demonstrates one of the advantages of the more verbose style.
    /// Note how the second version uses `ref mut a` to explicitly declare `a` a shared mutable
    /// borrow, while `b` is simply taken by value. This ensures that the loop body cannot
    /// accidentally modify the wrong part of the structure.
    ///
    /// ```rust,ignore
    /// // Bad
    /// let mut values = vec![(2, 3), (3, 4)];
    /// for (a, b) in &mut values {
    ///     *a += *b;
    /// }
    ///
    /// // Good
    /// let mut values = vec![(2, 3), (3, 4)];
    /// for &mut (ref mut a, b) in &mut values {
    ///     *a += b;
    /// }
    /// ```
    pub PATTERN_TYPE_MISMATCH,
    restriction,
    "type of pattern does not match the expression type"
}

declare_lint_pass!(PatternTypeMismatch => [PATTERN_TYPE_MISMATCH]);

impl<'tcx> LateLintPass<'tcx> for PatternTypeMismatch {
    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
        if let StmtKind::Local(ref local) = stmt.kind {
            if let Some(init) = &local.init {
                if let Some(init_ty) = cx.tables().node_type_opt(init.hir_id) {
                    let pat = &local.pat;
                    if in_external_macro(cx.sess(), pat.span) {
                        return;
                    }
                    let deref_possible = match local.source {
                        LocalSource::Normal => DerefPossible::Possible,
                        _ => DerefPossible::Impossible,
                    };
                    apply_lint(cx, pat, init_ty, deref_possible);
                }
            }
        }
    }

    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
        if let ExprKind::Match(ref expr, arms, source) = expr.kind {
            match source {
                MatchSource::Normal | MatchSource::IfLetDesugar { .. } | MatchSource::WhileLetDesugar => {
                    if let Some(expr_ty) = cx.tables().node_type_opt(expr.hir_id) {
                        'pattern_checks: for arm in arms {
                            let pat = &arm.pat;
                            if in_external_macro(cx.sess(), pat.span) {
                                continue 'pattern_checks;
                            }
                            if apply_lint(cx, pat, expr_ty, DerefPossible::Possible) {
                                break 'pattern_checks;
                            }
                        }
                    }
                },
                _ => (),
            }
        }
    }

    fn check_fn(
        &mut self,
        cx: &LateContext<'tcx>,
        _: intravisit::FnKind<'tcx>,
        _: &'tcx FnDecl<'_>,
        body: &'tcx Body<'_>,
        _: Span,
        hir_id: HirId,
    ) {
        if let Some(fn_sig) = cx.tables().liberated_fn_sigs().get(hir_id) {
            for (param, ty) in body.params.iter().zip(fn_sig.inputs().iter()) {
                apply_lint(cx, &param.pat, ty, DerefPossible::Impossible);
            }
        }
    }
}

#[derive(Debug, Clone, Copy)]
enum DerefPossible {
    Possible,
    Impossible,
}

fn apply_lint<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, expr_ty: Ty<'tcx>, deref_possible: DerefPossible) -> bool {
    let maybe_mismatch = find_first_mismatch(cx, pat, expr_ty, Level::Top);
    if let Some((span, mutability, level)) = maybe_mismatch {
        span_lint_and_help(
            cx,
            PATTERN_TYPE_MISMATCH,
            span,
            "type of pattern does not match the expression type",
            None,
            &format!(
                "{}explicitly match against a `{}` pattern and adjust the enclosed variable bindings",
                match (deref_possible, level) {
                    (DerefPossible::Possible, Level::Top) => "use `*` to dereference the match expression or ",
                    _ => "",
                },
                match mutability {
                    Mutability::Mut => "&mut _",
                    Mutability::Not => "&_",
                },
            ),
        );
        true
    } else {
        false
    }
}

#[derive(Debug, Copy, Clone)]
enum Level {
    Top,
    Lower,
}

#[allow(rustc::usage_of_ty_tykind)]
fn find_first_mismatch<'tcx>(
    cx: &LateContext<'tcx>,
    pat: &Pat<'_>,
    ty: Ty<'tcx>,
    level: Level,
) -> Option<(Span, Mutability, Level)> {
    if let PatKind::Ref(ref sub_pat, _) = pat.kind {
        if let TyKind::Ref(_, sub_ty, _) = ty.kind {
            return find_first_mismatch(cx, sub_pat, sub_ty, Level::Lower);
        }
    }

    if let TyKind::Ref(_, _, mutability) = ty.kind {
        if is_non_ref_pattern(&pat.kind) {
            return Some((pat.span, mutability, level));
        }
    }

    if let PatKind::Struct(ref qpath, ref field_pats, _) = pat.kind {
        if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind {
            if let Some(variant) = get_variant(adt_def, qpath) {
                let field_defs = &variant.fields;
                return find_first_mismatch_in_struct(cx, field_pats, field_defs, substs_ref);
            }
        }
    }

    if let PatKind::TupleStruct(ref qpath, ref pats, _) = pat.kind {
        if let TyKind::Adt(ref adt_def, ref substs_ref) = ty.kind {
            if let Some(variant) = get_variant(adt_def, qpath) {
                let field_defs = &variant.fields;
                let ty_iter = field_defs.iter().map(|field_def| field_def.ty(cx.tcx, substs_ref));
                return find_first_mismatch_in_tuple(cx, pats, ty_iter);
            }
        }
    }

    if let PatKind::Tuple(ref pats, _) = pat.kind {
        if let TyKind::Tuple(..) = ty.kind {
            return find_first_mismatch_in_tuple(cx, pats, ty.tuple_fields());
        }
    }

    if let PatKind::Or(sub_pats) = pat.kind {
        for pat in sub_pats {
            let maybe_mismatch = find_first_mismatch(cx, pat, ty, level);
            if let Some(mismatch) = maybe_mismatch {
                return Some(mismatch);
            }
        }
    }

    None
}

fn get_variant<'a>(adt_def: &'a AdtDef, qpath: &QPath<'_>) -> Option<&'a VariantDef> {
    if adt_def.is_struct() {
        if let Some(variant) = adt_def.variants.iter().next() {
            return Some(variant);
        }
    }

    if adt_def.is_enum() {
        let pat_ident = last_path_segment(qpath).ident;
        for variant in &adt_def.variants {
            if variant.ident == pat_ident {
                return Some(variant);
            }
        }
    }

    None
}

fn find_first_mismatch_in_tuple<'tcx, I>(
    cx: &LateContext<'tcx>,
    pats: &[&Pat<'_>],
    ty_iter_src: I,
) -> Option<(Span, Mutability, Level)>
where
    I: IntoIterator<Item = Ty<'tcx>>,
{
    let mut field_tys = ty_iter_src.into_iter();
    'fields: for pat in pats {
        let field_ty = if let Some(ty) = field_tys.next() {
            ty
        } else {
            break 'fields;
        };

        let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower);
        if let Some(mismatch) = maybe_mismatch {
            return Some(mismatch);
        }
    }

    None
}

fn find_first_mismatch_in_struct<'tcx>(
    cx: &LateContext<'tcx>,
    field_pats: &[FieldPat<'_>],
    field_defs: &[FieldDef],
    substs_ref: SubstsRef<'tcx>,
) -> Option<(Span, Mutability, Level)> {
    for field_pat in field_pats {
        'definitions: for field_def in field_defs {
            if field_pat.ident == field_def.ident {
                let field_ty = field_def.ty(cx.tcx, substs_ref);
                let pat = &field_pat.pat;
                let maybe_mismatch = find_first_mismatch(cx, pat, field_ty, Level::Lower);
                if let Some(mismatch) = maybe_mismatch {
                    return Some(mismatch);
                }
                break 'definitions;
            }
        }
    }

    None
}

fn is_non_ref_pattern(pat_kind: &PatKind<'_>) -> bool {
    match pat_kind {
        PatKind::Struct(..) | PatKind::Tuple(..) | PatKind::TupleStruct(..) | PatKind::Path(..) => true,
        PatKind::Or(sub_pats) => sub_pats.iter().any(|pat| is_non_ref_pattern(&pat.kind)),
        _ => false,
    }
}
<|endoftext|>


<commit_before>pub type door_attr_t = ::c_uint;
pub type door_id_t = ::c_ulonglong;

s! {
    pub struct shmid_ds {
        pub shm_perm: ::ipc_perm,
        pub shm_segsz: ::size_t,
        pub shm_flags: ::uintptr_t,
        pub shm_lkcnt: ::c_ushort,
        pub shm_lpid: ::pid_t,
        pub shm_cpid: ::pid_t,
        pub shm_nattch: ::shmatt_t,
        pub shm_cnattch: ::c_ulong,
        pub shm_atime: ::time_t,
        pub shm_dtime: ::time_t,
        pub shm_ctime: ::time_t,
        pub shm_amp: *mut ::c_void,
        pub shm_gransize: u64,
        pub shm_allocated: u64,
        pub shm_pad4: [i64; 1],
    }

    pub struct door_desc_t__d_data__d_desc {
        pub d_descriptor: ::c_int,
        pub d_id: ::door_id_t
    }
}

pub const PORT_SOURCE_POSTWAIT: ::c_int = 8;
pub const PORT_SOURCE_SIGNAL: ::c_int = 9;

pub const AF_LOCAL: ::c_int = 0;
pub const AF_FILE: ::c_int = 0;

pub const TCP_KEEPIDLE: ::c_int = 0x1d;
pub const TCP_KEEPCNT: ::c_int = 0x1e;
pub const TCP_KEEPINTVL: ::c_int = 0x1f;

pub const F_DUPFD_CLOEXEC: ::c_int = 47;
pub const F_DUPFD_CLOFORK: ::c_int = 49;
pub const F_DUP2FD_CLOEXEC: ::c_int = 48;
pub const F_DUP2FD_CLOFORK: ::c_int = 50;

extern "C" {
    pub fn fexecve(
        fd: ::c_int,
        argv: *const *const ::c_char,
        envp: *const *const ::c_char,
    ) -> ::c_int;

    pub fn mincore(addr: *const ::c_void, len: ::size_t, vec: *mut ::c_char) -> ::c_int;

    pub fn door_call(d: ::c_int, params: *const door_arg_t) -> ::c_int;
    pub fn door_return(
        data_ptr: *const ::c_char,
        data_size: ::size_t,
        desc_ptr: *const door_desc_t,
        num_desc: ::c_uint,
    );
    pub fn door_create(
        server_procedure: extern "C" fn(
            cookie: *const ::c_void,
            argp: *const ::c_char,
            arg_size: ::size_t,
            dp: *const door_desc_t,
            n_desc: ::c_uint,
        ),
        cookie: *const ::c_void,
        attributes: door_attr_t,
    ) -> ::c_int;

    pub fn fattach(fildes: ::c_int, path: *const ::c_char) -> ::c_int;

    pub fn pthread_getattr_np(thread: ::pthread_t, attr: *mut ::pthread_attr_t) -> ::c_int;
}

s_no_extra_traits! {
    #[cfg_attr(feature = "extra_traits", allow(missing_debug_implementations))]
    pub union door_desc_t__d_data {
        pub d_desc: door_desc_t__d_data__d_desc,
        d_resv: [::c_int; 5], /* Check out /usr/include/sys/door.h */
    }

    #[cfg_attr(feature = "extra_traits", allow(missing_debug_implementations))]
    pub struct door_desc_t {
        pub d_attributes: door_attr_t,
        pub d_data: door_desc_t__d_data,
    }

    #[cfg_attr(feature = "extra_traits", allow(missing_debug_implementations))]
    pub struct door_arg_t {
        pub data_ptr: *const ::c_char,
        pub data_size: ::size_t,
        pub desc_ptr: *const door_desc_t,
        pub dec_num: ::c_uint,
        pub rbuf: *const ::c_char,
        pub rsize: ::size_t,
    }
}
<commit_msg>Auto merge of #2901 - gco:tcp_keepcnt, r=JohnTitor<commit_after>pub type door_attr_t = ::c_uint;
pub type door_id_t = ::c_ulonglong;

s! {
    pub struct shmid_ds {
        pub shm_perm: ::ipc_perm,
        pub shm_segsz: ::size_t,
        pub shm_flags: ::uintptr_t,
        pub shm_lkcnt: ::c_ushort,
        pub shm_lpid: ::pid_t,
        pub shm_cpid: ::pid_t,
        pub shm_nattch: ::shmatt_t,
        pub shm_cnattch: ::c_ulong,
        pub shm_atime: ::time_t,
        pub shm_dtime: ::time_t,
        pub shm_ctime: ::time_t,
        pub shm_amp: *mut ::c_void,
        pub shm_gransize: u64,
        pub shm_allocated: u64,
        pub shm_pad4: [i64; 1],
    }

    pub struct door_desc_t__d_data__d_desc {
        pub d_descriptor: ::c_int,
        pub d_id: ::door_id_t
    }
}

pub const PORT_SOURCE_POSTWAIT: ::c_int = 8;
pub const PORT_SOURCE_SIGNAL: ::c_int = 9;

pub const AF_LOCAL: ::c_int = 0;
pub const AF_FILE: ::c_int = 0;

pub const TCP_KEEPIDLE: ::c_int = 0x1d;
pub const TCP_KEEPINTVL: ::c_int = 0x1e;
pub const TCP_KEEPCNT: ::c_int = 0x1f;

pub const F_DUPFD_CLOEXEC: ::c_int = 47;
pub const F_DUPFD_CLOFORK: ::c_int = 49;
pub const F_DUP2FD_CLOEXEC: ::c_int = 48;
pub const F_DUP2FD_CLOFORK: ::c_int = 50;

extern "C" {
    pub fn fexecve(
        fd: ::c_int,
        argv: *const *const ::c_char,
        envp: *const *const ::c_char,
    ) -> ::c_int;

    pub fn mincore(addr: *const ::c_void, len: ::size_t, vec: *mut ::c_char) -> ::c_int;

    pub fn door_call(d: ::c_int, params: *const door_arg_t) -> ::c_int;
    pub fn door_return(
        data_ptr: *const ::c_char,
        data_size: ::size_t,
        desc_ptr: *const door_desc_t,
        num_desc: ::c_uint,
    );
    pub fn door_create(
        server_procedure: extern "C" fn(
            cookie: *const ::c_void,
            argp: *const ::c_char,
            arg_size: ::size_t,
            dp: *const door_desc_t,
            n_desc: ::c_uint,
        ),
        cookie: *const ::c_void,
        attributes: door_attr_t,
    ) -> ::c_int;

    pub fn fattach(fildes: ::c_int, path: *const ::c_char) -> ::c_int;

    pub fn pthread_getattr_np(thread: ::pthread_t, attr: *mut ::pthread_attr_t) -> ::c_int;
}

s_no_extra_traits! {
    #[cfg_attr(feature = "extra_traits", allow(missing_debug_implementations))]
    pub union door_desc_t__d_data {
        pub d_desc: door_desc_t__d_data__d_desc,
        d_resv: [::c_int; 5], /* Check out /usr/include/sys/door.h */
    }

    #[cfg_attr(feature = "extra_traits", allow(missing_debug_implementations))]
    pub struct door_desc_t {
        pub d_attributes: door_attr_t,
        pub d_data: door_desc_t__d_data,
    }

    #[cfg_attr(feature = "extra_traits", allow(missing_debug_implementations))]
    pub struct door_arg_t {
        pub data_ptr: *const ::c_char,
        pub data_size: ::size_t,
        pub desc_ptr: *const door_desc_t,
        pub dec_num: ::c_uint,
        pub rbuf: *const ::c_char,
        pub rsize: ::size_t,
    }
}
<|endoftext|>


<commit_before>#![allow(unused_imports)]

use core::intrinsics;

// NOTE These functions are implemented using assembly because they using a custom
// calling convention which can't be implemented using a normal Rust function

// NOTE These functions are never mangled as they are not tested against compiler-rt
// and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca

#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))]
#[naked]
#[no_mangle]
pub unsafe fn ___chkstk_ms() {
    asm!("
        push   %rcx
        push   %rax
        cmp    $$0x1000,%rax
        lea    24(%rsp),%rcx
        jb     1f
    2:
        sub    $$0x1000,%rcx
        test   %rcx,(%rcx)
        sub    $$0x1000,%rax
        cmp    $$0x1000,%rax
        ja     2b
    1:
        sub    %rax,%rcx
        test   %rcx,(%rcx)
        pop    %rax
        pop    %rcx
        ret" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))]
#[naked]
#[no_mangle]
pub unsafe fn __alloca() {
    asm!("mov    %rcx,%rax  // x64 _alloca is a normal function with parameter in rcx
          jmp    ___chkstk  // Jump to ___chkstk since fallthrough may be unreliable"
         ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))]
#[naked]
#[no_mangle]
pub unsafe fn ___chkstk() {
    asm!(
        "
        push   %rcx
        cmp    $$0x1000,%rax
        lea    16(%rsp),%rcx  // rsp before calling this routine -> rcx
        jb     1f
    2:
        sub    $$0x1000,%rcx
        test   %rcx,(%rcx)
        sub    $$0x1000,%rax
        cmp    $$0x1000,%rax
        ja     2b
    1:
        sub    %rax,%rcx
        test   %rcx,(%rcx)

        lea    8(%rsp),%rax   // load pointer to the return address into rax
        mov    %rcx,%rsp      // install the new top of stack pointer into rsp
        mov    -8(%rax),%rcx  // restore rcx
        push   (%rax)         // push return address onto the stack
        sub    %rsp,%rax      // restore the original value in rax
        ret"
        ::: "memory" : "volatile"
    );
    intrinsics::unreachable();
}
<commit_msg>Emit `_fltused` on `uefi` targets as a short-term workaround (#317)<commit_after>#![allow(unused_imports)]

use core::intrinsics;

// NOTE These functions are implemented using assembly because they using a custom
// calling convention which can't be implemented using a normal Rust function

// NOTE These functions are never mangled as they are not tested against compiler-rt
// and mangling ___chkstk would break the `jmp ___chkstk` instruction in __alloca

#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))]
#[naked]
#[no_mangle]
pub unsafe fn ___chkstk_ms() {
    asm!("
        push   %rcx
        push   %rax
        cmp    $$0x1000,%rax
        lea    24(%rsp),%rcx
        jb     1f
    2:
        sub    $$0x1000,%rcx
        test   %rcx,(%rcx)
        sub    $$0x1000,%rax
        cmp    $$0x1000,%rax
        ja     2b
    1:
        sub    %rax,%rcx
        test   %rcx,(%rcx)
        pop    %rax
        pop    %rcx
        ret" ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))]
#[naked]
#[no_mangle]
pub unsafe fn __alloca() {
    asm!("mov    %rcx,%rax  // x64 _alloca is a normal function with parameter in rcx
          jmp    ___chkstk  // Jump to ___chkstk since fallthrough may be unreliable"
         ::: "memory" : "volatile");
    intrinsics::unreachable();
}

#[cfg(all(windows, target_env = "gnu", not(feature = "mangled-names")))]
#[naked]
#[no_mangle]
pub unsafe fn ___chkstk() {
    asm!(
        "
        push   %rcx
        cmp    $$0x1000,%rax
        lea    16(%rsp),%rcx  // rsp before calling this routine -> rcx
        jb     1f
    2:
        sub    $$0x1000,%rcx
        test   %rcx,(%rcx)
        sub    $$0x1000,%rax
        cmp    $$0x1000,%rax
        ja     2b
    1:
        sub    %rax,%rcx
        test   %rcx,(%rcx)

        lea    8(%rsp),%rax   // load pointer to the return address into rax
        mov    %rcx,%rsp      // install the new top of stack pointer into rsp
        mov    -8(%rax),%rcx  // restore rcx
        push   (%rax)         // push return address onto the stack
        sub    %rsp,%rax      // restore the original value in rax
        ret"
        ::: "memory" : "volatile"
    );
    intrinsics::unreachable();
}

// HACK(https://github.com/rust-lang/rust/issues/62785): x86_64-unknown-uefi needs special LLVM
// support unless we emit the _fltused
#[no_mangle]
#[used]
#[cfg(target_os = "uefi")]
static _fltused: i32 = 0;
<|endoftext|>