<commit_before>#![allow(clippy::borrowed_box)]

use crate::error::*;

use crate::buffer::Buffered;
use std::any::Any;
use std::io::SeekFrom;
use std::sync::Arc;

use crate::common::*;

use crate::data::packet::Packet;
use crate::stream::Stream;

#[derive(Clone, Debug)]
pub enum Event {
    NewPacket(Packet),
    NewStream(Stream),
    MoreDataNeeded(usize),
    Continue,
    Eof,
    // use #[non_exhaustive] once this works:
    // https://github.com/rust-lang/rust/issues/44109
    #[doc(hidden)]
    __NonExaustive,
}

pub trait Demuxer: Send {
    fn read_headers(&mut self, buf: &Box<dyn Buffered>, info: &mut GlobalInfo) -> Result<SeekFrom>;
    fn read_event(&mut self, buf: &Box<dyn Buffered>) -> Result<(SeekFrom, Event)>;
}

#[derive(Clone, Debug, PartialEq)]
pub struct Descr {
    pub name: &'static str,
    pub demuxer: &'static str,
    pub description: &'static str,
    pub extensions: &'static [&'static str],
    pub mime: &'static [&'static str],
}

pub trait Descriptor {
    fn create(&self) -> Box<dyn Demuxer>;
    fn describe(&self) -> &Descr;

    fn probe(&self, data: &[u8]) -> u8;
}

pub struct Context {
    demuxer: Box<dyn Demuxer>,
    reader: Box<dyn Buffered>,
    pub info: GlobalInfo,
    pub user_private: Option<Arc<dyn Any + Send + Sync>>,
}

impl Context {
    pub fn new<R: Buffered + 'static>(demuxer: Box<dyn Demuxer>, reader: Box<R>) -> Self {
        Context {
            demuxer,
            reader,
            info: GlobalInfo {
                duration: None,
                timebase: None,
                streams: Vec::with_capacity(2),
            },
            user_private: None,
        }
    }

    fn read_headers_internal(&mut self) -> Result<()> {
        let demux = &mut self.demuxer;

        let res = demux.read_headers(&self.reader, &mut self.info);
        match res {
            Err(e) => Err(e),
            Ok(seek) => {
                //TODO: handle seeking here
                let res = self.reader.seek(seek);
                trace!("stream now at index: {:?}", res);
                Ok(())
            }
        }
    }

    pub fn read_headers(&mut self) -> Result<()> {
        loop {
            // TODO: wrap fill_buf() with a check for Eof
            self.reader.fill_buf()?;
            match self.read_headers_internal() {
                Err(e) => match e {
                    Error::MoreDataNeeded(needed) => {
                        self.reader.grow(needed);
                    }
                    _ => return Err(e),
                },
                Ok(_) => return Ok(()),
            }
        }
    }

    fn read_event_internal(&mut self) -> Result<Event> {
        let demux = &mut self.demuxer;

        let res = demux.read_event(&self.reader);
        match res {
            Err(e) => Err(e),
            Ok((seek, mut event)) => {
                //TODO: handle seeking here
                let _ = self.reader.seek(seek)?;
                if let Event::NewStream(ref st) = event {
                    self.info.streams.push(st.clone());
                }
                if let Event::MoreDataNeeded(size) = event {
                    return Err(Error::MoreDataNeeded(size));
                }
                if let Event::NewPacket(ref mut pkt) = event {
                    if pkt.t.timebase.is_none() {
                        if let Some(ref st) = self
                            .info
                            .streams
                            .iter()
                            .find(|s| s.index as isize == pkt.stream_index)
                        {
                            pkt.t.timebase = Some(st.timebase);
                        }
                    }
                }
                Ok(event)
            }
        }
    }

    pub fn read_event(&mut self) -> Result<Event> {
        // TODO: guard against infiniloops and maybe factor the loop.
        loop {
            match self.read_event_internal() {
                Err(e) => match e {
                    Error::MoreDataNeeded(needed) => {
                        let len = self.reader.data().len();

                        // we might have sent MoreDatNeeded(0) to request a new call
                        if len >= needed {
                            continue;
                        }
                        self.reader.grow(needed);
                        self.reader.fill_buf()?;
                        if self.reader.data().len() <= len {
                            return Ok(Event::Eof);
                        }
                    }
                    _ => return Err(e),
                },
                Ok(ev) => return Ok(ev),
            }
        }
    }
}

pub const PROBE_DATA: usize = 4 * 1024;
pub const PROBE_SCORE_EXTENSION: u8 = 50;

// TODO:
// IntoIterator<Item = &'static Descriptor> is confusing

pub trait Probe {
    fn probe(&self, data: &[u8]) -> Option<&'static dyn Descriptor>;
}

impl<'a> Probe for [&'static dyn Descriptor] {
    fn probe(&self, data: &[u8]) -> Option<&'static dyn Descriptor> {
        let mut max = u8::min_value();
        let mut candidate: Option<&'static dyn Descriptor> = None;
        for desc in self {
            let score = desc.probe(data);

            if score > max {
                max = score;
                candidate = Some(*desc);
            }
        }

        if max > PROBE_SCORE_EXTENSION {
            candidate
        } else {
            None
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::data::packet::Packet;
    use std::io::SeekFrom;

    struct DummyDes {
        d: Descr,
    }

    struct DummyDemuxer {}

    impl Demuxer for DummyDemuxer {
        fn read_headers(
            &mut self,
            buf: &Box<dyn Buffered>,
            _info: &mut GlobalInfo,
        ) -> Result<SeekFrom> {
            let len = buf.data().len();
            if 9 > len {
                let needed = 9 - len;
                Err(Error::MoreDataNeeded(needed))
            } else {
                Ok(SeekFrom::Current(9))
            }
        }
        fn read_event(&mut self, buf: &Box<dyn Buffered>) -> Result<(SeekFrom, Event)> {
            let size = 2;
            let len = buf.data().len();
            if size > len {
                Err(Error::MoreDataNeeded(size - len))
            } else {
                debug!("{:?}", buf.data());
                match &buf.data()[..2] {
                    b"p1" => Ok((SeekFrom::Current(3), Event::NewPacket(Packet::new()))),
                    b"e1" => Ok((SeekFrom::Current(3), Event::MoreDataNeeded(0))),
                    _ => Err(Error::InvalidData.into()),
                }
            }
        }
    }

    impl Descriptor for DummyDes {
        fn create(&self) -> Box<dyn Demuxer> {
            Box::new(DummyDemuxer {})
        }
        fn describe<'a>(&'a self) -> &'a Descr {
            &self.d
        }
        fn probe(&self, data: &[u8]) -> u8 {
            match data {
                b"dummy" => 100,
                _ => 0,
            }
        }
    }

    const DUMMY_DES: &dyn Descriptor = &DummyDes {
        d: Descr {
            name: "dummy",
            demuxer: "dummy",
            description: "Dummy dem",
            extensions: &["dm", "dum"],
            mime: &["application/dummy"],
        },
    };

    #[test]
    fn probe() {
        let demuxers: &[&'static dyn Descriptor] = &[DUMMY_DES];

        demuxers.probe(b"dummy").unwrap();
    }

    use crate::buffer::*;
    use std::io::Cursor;

    #[test]
    fn read_headers() {
        let buf = b"dummy header";
        let r = AccReader::with_capacity(4, Cursor::new(buf));
        let d = DUMMY_DES.create();
        let mut c = Context::new(d, Box::new(r));

        c.read_headers().unwrap();
    }

    #[test]
    fn read_event() {
        let buf = b"dummy header p1 e1 p1 ";

        let r = AccReader::with_capacity(4, Cursor::new(buf));
        let d = DUMMY_DES.create();
        let mut c = Context::new(d, Box::new(r));

        c.read_headers().unwrap();

        println!("{:?}", c.read_event());
        println!("{:?}", c.read_event());
        println!("{:?}", c.read_event());
        println!("{:?}", c.read_event());
    }
}
<commit_msg>Use the new non_exhaustive attribute<commit_after>#![allow(clippy::borrowed_box)]

use crate::error::*;

use crate::buffer::Buffered;
use std::any::Any;
use std::io::SeekFrom;
use std::sync::Arc;

use crate::common::*;

use crate::data::packet::Packet;
use crate::stream::Stream;

#[non_exhaustive]
#[derive(Clone, Debug)]
pub enum Event {
    NewPacket(Packet),
    NewStream(Stream),
    MoreDataNeeded(usize),
    Continue,
    Eof,
}

pub trait Demuxer: Send {
    fn read_headers(&mut self, buf: &Box<dyn Buffered>, info: &mut GlobalInfo) -> Result<SeekFrom>;
    fn read_event(&mut self, buf: &Box<dyn Buffered>) -> Result<(SeekFrom, Event)>;
}

#[derive(Clone, Debug, PartialEq)]
pub struct Descr {
    pub name: &'static str,
    pub demuxer: &'static str,
    pub description: &'static str,
    pub extensions: &'static [&'static str],
    pub mime: &'static [&'static str],
}

pub trait Descriptor {
    fn create(&self) -> Box<dyn Demuxer>;
    fn describe(&self) -> &Descr;

    fn probe(&self, data: &[u8]) -> u8;
}

pub struct Context {
    demuxer: Box<dyn Demuxer>,
    reader: Box<dyn Buffered>,
    pub info: GlobalInfo,
    pub user_private: Option<Arc<dyn Any + Send + Sync>>,
}

impl Context {
    pub fn new<R: Buffered + 'static>(demuxer: Box<dyn Demuxer>, reader: Box<R>) -> Self {
        Context {
            demuxer,
            reader,
            info: GlobalInfo {
                duration: None,
                timebase: None,
                streams: Vec::with_capacity(2),
            },
            user_private: None,
        }
    }

    fn read_headers_internal(&mut self) -> Result<()> {
        let demux = &mut self.demuxer;

        let res = demux.read_headers(&self.reader, &mut self.info);
        match res {
            Err(e) => Err(e),
            Ok(seek) => {
                //TODO: handle seeking here
                let res = self.reader.seek(seek);
                trace!("stream now at index: {:?}", res);
                Ok(())
            }
        }
    }

    pub fn read_headers(&mut self) -> Result<()> {
        loop {
            // TODO: wrap fill_buf() with a check for Eof
            self.reader.fill_buf()?;
            match self.read_headers_internal() {
                Err(e) => match e {
                    Error::MoreDataNeeded(needed) => {
                        self.reader.grow(needed);
                    }
                    _ => return Err(e),
                },
                Ok(_) => return Ok(()),
            }
        }
    }

    fn read_event_internal(&mut self) -> Result<Event> {
        let demux = &mut self.demuxer;

        let res = demux.read_event(&self.reader);
        match res {
            Err(e) => Err(e),
            Ok((seek, mut event)) => {
                //TODO: handle seeking here
                let _ = self.reader.seek(seek)?;
                if let Event::NewStream(ref st) = event {
                    self.info.streams.push(st.clone());
                }
                if let Event::MoreDataNeeded(size) = event {
                    return Err(Error::MoreDataNeeded(size));
                }
                if let Event::NewPacket(ref mut pkt) = event {
                    if pkt.t.timebase.is_none() {
                        if let Some(ref st) = self
                            .info
                            .streams
                            .iter()
                            .find(|s| s.index as isize == pkt.stream_index)
                        {
                            pkt.t.timebase = Some(st.timebase);
                        }
                    }
                }
                Ok(event)
            }
        }
    }

    pub fn read_event(&mut self) -> Result<Event> {
        // TODO: guard against infiniloops and maybe factor the loop.
        loop {
            match self.read_event_internal() {
                Err(e) => match e {
                    Error::MoreDataNeeded(needed) => {
                        let len = self.reader.data().len();

                        // we might have sent MoreDatNeeded(0) to request a new call
                        if len >= needed {
                            continue;
                        }
                        self.reader.grow(needed);
                        self.reader.fill_buf()?;
                        if self.reader.data().len() <= len {
                            return Ok(Event::Eof);
                        }
                    }
                    _ => return Err(e),
                },
                Ok(ev) => return Ok(ev),
            }
        }
    }
}

pub const PROBE_DATA: usize = 4 * 1024;
pub const PROBE_SCORE_EXTENSION: u8 = 50;

// TODO:
// IntoIterator<Item = &'static Descriptor> is confusing

pub trait Probe {
    fn probe(&self, data: &[u8]) -> Option<&'static dyn Descriptor>;
}

impl<'a> Probe for [&'static dyn Descriptor] {
    fn probe(&self, data: &[u8]) -> Option<&'static dyn Descriptor> {
        let mut max = u8::min_value();
        let mut candidate: Option<&'static dyn Descriptor> = None;
        for desc in self {
            let score = desc.probe(data);

            if score > max {
                max = score;
                candidate = Some(*desc);
            }
        }

        if max > PROBE_SCORE_EXTENSION {
            candidate
        } else {
            None
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use crate::data::packet::Packet;
    use std::io::SeekFrom;

    struct DummyDes {
        d: Descr,
    }

    struct DummyDemuxer {}

    impl Demuxer for DummyDemuxer {
        fn read_headers(
            &mut self,
            buf: &Box<dyn Buffered>,
            _info: &mut GlobalInfo,
        ) -> Result<SeekFrom> {
            let len = buf.data().len();
            if 9 > len {
                let needed = 9 - len;
                Err(Error::MoreDataNeeded(needed))
            } else {
                Ok(SeekFrom::Current(9))
            }
        }
        fn read_event(&mut self, buf: &Box<dyn Buffered>) -> Result<(SeekFrom, Event)> {
            let size = 2;
            let len = buf.data().len();
            if size > len {
                Err(Error::MoreDataNeeded(size - len))
            } else {
                debug!("{:?}", buf.data());
                match &buf.data()[..2] {
                    b"p1" => Ok((SeekFrom::Current(3), Event::NewPacket(Packet::new()))),
                    b"e1" => Ok((SeekFrom::Current(3), Event::MoreDataNeeded(0))),
                    _ => Err(Error::InvalidData.into()),
                }
            }
        }
    }

    impl Descriptor for DummyDes {
        fn create(&self) -> Box<dyn Demuxer> {
            Box::new(DummyDemuxer {})
        }
        fn describe<'a>(&'a self) -> &'a Descr {
            &self.d
        }
        fn probe(&self, data: &[u8]) -> u8 {
            match data {
                b"dummy" => 100,
                _ => 0,
            }
        }
    }

    const DUMMY_DES: &dyn Descriptor = &DummyDes {
        d: Descr {
            name: "dummy",
            demuxer: "dummy",
            description: "Dummy dem",
            extensions: &["dm", "dum"],
            mime: &["application/dummy"],
        },
    };

    #[test]
    fn probe() {
        let demuxers: &[&'static dyn Descriptor] = &[DUMMY_DES];

        demuxers.probe(b"dummy").unwrap();
    }

    use crate::buffer::*;
    use std::io::Cursor;

    #[test]
    fn read_headers() {
        let buf = b"dummy header";
        let r = AccReader::with_capacity(4, Cursor::new(buf));
        let d = DUMMY_DES.create();
        let mut c = Context::new(d, Box::new(r));

        c.read_headers().unwrap();
    }

    #[test]
    fn read_event() {
        let buf = b"dummy header p1 e1 p1 ";

        let r = AccReader::with_capacity(4, Cursor::new(buf));
        let d = DUMMY_DES.create();
        let mut c = Context::new(d, Box::new(r));

        c.read_headers().unwrap();

        println!("{:?}", c.read_event());
        println!("{:?}", c.read_event());
        println!("{:?}", c.read_event());
        println!("{:?}", c.read_event());
    }
}
<|endoftext|>


<commit_before>use crate::wrapper::atom;
use crate::wrapper::NIF_TERM;
use crate::{Decoder, Encoder, Env, Error, NifResult, Term};

// Atoms are a special case of a term. They can be stored and used on all envs regardless of where
// it lives and when it is created.
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct Atom {
    term: NIF_TERM,
}

impl Atom {
    pub fn as_c_arg(self) -> NIF_TERM {
        self.term
    }

    pub fn to_term(self, env: Env) -> Term {
        // Safe because atoms are not associated with any environment.
        unsafe { Term::new(env, self.term) }
    }

    unsafe fn from_nif_term(term: NIF_TERM) -> Self {
        Atom { term }
    }

    pub fn from_term(term: Term) -> NifResult<Self> {
        if term.is_atom() {
            Ok(unsafe { Atom::from_nif_term(term.as_c_arg()) })
        } else {
            Err(Error::BadArg)
        }
    }

    /// Return the atom whose text representation is `bytes`, like `erlang:binary_to_atom/2`.
    ///
    /// # Errors
    /// `Error::BadArg` if `bytes.len() > 255`.
    pub fn from_bytes<'a>(env: Env<'a>, bytes: &[u8]) -> NifResult<Atom> {
        if bytes.len() > 255 {
            return Err(Error::BadArg);
        }
        unsafe { Ok(Atom::from_nif_term(atom::make_atom(env.as_c_arg(), bytes))) }
    }

    /// Return the atom whose text representation is `bytes`, like `erlang:binary_to_existing_atom/2`, if atom with given text representation exists.
    ///
    /// # Errors
    /// `Error::BadArg` if `bytes.len() > 255`.
    pub fn try_from_bytes<'a>(env: Env<'a>, bytes: &[u8]) -> NifResult<Option<Atom>> {
        if bytes.len() > 255 {
            return Err(Error::BadArg);
        }
        unsafe {
            match atom::make_existing_atom(env.as_c_arg(), bytes) {
                Some(term) => Ok(Some(Atom::from_nif_term(term))),
                None => Ok(None),
            }
        }
    }

    /// Return the atom whose text representation is the given `string`, like `erlang:list_to_atom/2`.
    ///
    /// # Errors
    /// `Error::BadArg` if `string` contains characters that aren't in Latin-1, or if it's too
    /// long. The maximum length is 255 characters.
    pub fn from_str<'a>(env: Env<'a>, string: &str) -> NifResult<Atom> {
        if string.is_ascii() {
            // Fast path.
            Atom::from_bytes(env, string.as_bytes())
        } else {
            // Convert from Rust UTF-8 to Latin-1.
            let mut bytes = Vec::with_capacity(string.len());
            for c in string.chars() {
                if (c as u32) >= 256 {
                    return Err(Error::BadArg);
                }
                bytes.push(c as u8);
            }
            Atom::from_bytes(env, &bytes)
        }
    }
}

use std::fmt;
impl fmt::Debug for Atom {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        crate::wrapper::term::fmt(self.as_c_arg(), f)
    }
}

impl Encoder for Atom {
    fn encode<'a>(&self, env: Env<'a>) -> Term<'a> {
        self.to_term(env)
    }
}
impl<'a> Decoder<'a> for Atom {
    fn decode(term: Term<'a>) -> NifResult<Atom> {
        Atom::from_term(term)
    }
}

impl<'a> PartialEq<Term<'a>> for Atom {
    fn eq(&self, other: &Term<'a>) -> bool {
        self.as_c_arg() == other.as_c_arg()
    }
}

/// ## Atom terms
impl<'a> Term<'a> {
    /// When the term is an atom, this method will return the string
    /// representation of it.
    ///
    /// If you only need to test for equality, comparing the terms directly
    /// is much faster.
    ///
    /// Will return None if the term is not an atom.
    pub fn atom_to_string(&self) -> NifResult<String> {
        unsafe { atom::get_atom(self.get_env().as_c_arg(), self.as_c_arg()) }
    }
}

pub fn is_truthy(term: Term) -> bool {
    !((term.as_c_arg() == false_().as_c_arg()) || (term.as_c_arg() == nil().as_c_arg()))
}

pub(in crate::types) fn decode_bool(term: Term) -> NifResult<bool> {
    let as_c_arg = term.as_c_arg();

    if as_c_arg == true_().as_c_arg() {
        return Ok(true);
    }

    if as_c_arg == false_().as_c_arg() {
        return Ok(false);
    }

    Err(Error::BadArg)
}

// This is safe because atoms are never removed/changed once they are created.
unsafe impl Sync for Atom {}
unsafe impl Send for Atom {}

/// Macro for defining Rust functions that return Erlang atoms.
/// To use this macro, you must also import the `lazy_static` crate.
///
/// For example, this code:
///
///     #[macro_use] extern crate rustler;
///
///     mod my_atoms {
///         rustler::atoms! {
///             jpeg,
///         }
///     }
///     # fn main() {}
///
/// defines a public function `my_atoms::jpeg()` that returns the `Atom` for the `jpeg` atom.
///
/// Multiple atoms can be defined. Each one can have its own doc comment and other attributes.
///
///     # #[macro_use] extern crate rustler;
///     rustler::atoms! {
///         /// The `jpeg` atom.
///         jpeg,
///
///         /// The `png` atom.
///         png,
///
///         #[allow(non_snake_case)]
///         WebP,
///     }
///     # fn main() {}
///
/// When you need an atom that's not a legal Rust function name, write `NAME = "ATOM"`, like
/// this:
///
///     # #[macro_use] extern crate rustler;
///     rustler::atoms! {
///         /// The `mod` atom. The function isn't called `mod` because that's
///         /// a Rust keyword.
///         mod_atom = "mod",
///
///         /// The atom `'hello world'`. Obviously this function can't be
///         /// called `hello world` because there's a space in it.
///         hello_world = "hello world",
///     }
///     # fn main() {}
///
/// # Performance
///
/// These functions are faster than `get_atom` and `get_atom_init`. The first time you call one, it
/// creates atoms for all its sibling functions and caches them, so that all later calls are fast.
/// The only overhead is checking that the atoms have been created (an atomic integer read).
///
#[macro_export]
macro_rules! atoms {
    {
        $(
            $( #[$attr:meta] )*
            $name:ident $( = $str:expr )?
        ),*$(,)?
    } => {
        #[allow(non_snake_case)]
        struct RustlerAtoms {
            $( $name : $crate::types::atom::Atom ),*
        }
        $crate::lazy_static::lazy_static! {
            static ref RUSTLER_ATOMS: RustlerAtoms = $crate::env::OwnedEnv::new().run(|env| {
                RustlerAtoms {
                    $( $name: $crate::atoms!(@internal_make_atom(env, $name $( = $str)? )) ),*
                }
            });
        }
        $(
            $( #[$attr] )*
            pub fn $name() -> $crate::types::atom::Atom {
                RUSTLER_ATOMS.$name
            }
        )*
    };

    // Internal helper macros.
    { @internal_make_atom($env:ident, $name:ident) } => {
        $crate::atoms!(@internal_make_atom($env, $name = stringify!($name)))
    };
    { @internal_make_atom($env:ident, $name:ident = $str:expr) } => {
        $crate::types::atom::Atom::from_str($env, $str)
            .ok().expect("rustler::atoms!: bad atom string")
    };
}

#[macro_export]
#[deprecated(since = "0.22.0", note = "Please use `atoms!` instead.")]
macro_rules! rustler_atoms {
    {
        $(
            $( #[$attr:meta] )*
            atom $name:ident $( = $str:expr )?;
        )*
    } => {
        #[allow(non_snake_case)]
        struct RustlerAtoms {
            $( $name : $crate::types::atom::Atom ),*
        }
        $crate::lazy_static::lazy_static! {
            static ref RUSTLER_ATOMS: RustlerAtoms = $crate::env::OwnedEnv::new().run(|env| {
                RustlerAtoms {
                    $( $name: $crate::rustler_atoms!(@internal_make_atom(env, $name $( = $str)? )) ),*
                }
            });
        }
        $(
            $( #[$attr] )*
            pub fn $name() -> $crate::types::atom::Atom {
                RUSTLER_ATOMS.$name
            }
        )*
    };

    // Internal helper macros.
    { @internal_make_atom($env:ident, $name:ident) } => {
        $crate::rustler_atoms!(@internal_make_atom($env, $name = stringify!($name)))
    };
    { @internal_make_atom($env:ident, $name:ident = $str:expr) } => {
        $crate::types::atom::Atom::from_str($env, $str)
            .ok().expect("rustler::atoms!: bad atom string")
    };
}

atoms! {
    /// The `nil` atom.
    nil,

    /// The `ok` atom, commonly used in success tuples.
    ok,

    /// The `error` atom, commonly used in error tuples.
    error,

    /// The `badarg` atom, which Rustler sometimes returns to indicate that a function was
    /// called with incorrect arguments.
    badarg,

    /// The `false` atom. (Trailing underscore because `false` is a keyword in Rust.)
    ///
    /// If you're looking to convert between Erlang terms and Rust `bool`
    /// values, use `Encoder` and `Decoder` instead.
    false_ = "false",

    /// The `true` atom. (Trailing underscore because `true` is a keyword in Rust.)
    ///
    /// If you're looking to convert between Erlang terms and Rust `bool`
    /// values, use `Encoder` and `Decoder` instead.
    true_ = "true",

    /// The `__struct__` atom used by Elixir.
    __struct__,

    /// The `first` atom used by `Elixir.Range`.
    first,

    /// The `last` atom used by `Elixir.Range`.
    last,
}
<commit_msg>Drop another unneeded ok()<commit_after>use crate::wrapper::atom;
use crate::wrapper::NIF_TERM;
use crate::{Decoder, Encoder, Env, Error, NifResult, Term};

// Atoms are a special case of a term. They can be stored and used on all envs regardless of where
// it lives and when it is created.
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct Atom {
    term: NIF_TERM,
}

impl Atom {
    pub fn as_c_arg(self) -> NIF_TERM {
        self.term
    }

    pub fn to_term(self, env: Env) -> Term {
        // Safe because atoms are not associated with any environment.
        unsafe { Term::new(env, self.term) }
    }

    unsafe fn from_nif_term(term: NIF_TERM) -> Self {
        Atom { term }
    }

    pub fn from_term(term: Term) -> NifResult<Self> {
        if term.is_atom() {
            Ok(unsafe { Atom::from_nif_term(term.as_c_arg()) })
        } else {
            Err(Error::BadArg)
        }
    }

    /// Return the atom whose text representation is `bytes`, like `erlang:binary_to_atom/2`.
    ///
    /// # Errors
    /// `Error::BadArg` if `bytes.len() > 255`.
    pub fn from_bytes<'a>(env: Env<'a>, bytes: &[u8]) -> NifResult<Atom> {
        if bytes.len() > 255 {
            return Err(Error::BadArg);
        }
        unsafe { Ok(Atom::from_nif_term(atom::make_atom(env.as_c_arg(), bytes))) }
    }

    /// Return the atom whose text representation is `bytes`, like `erlang:binary_to_existing_atom/2`, if atom with given text representation exists.
    ///
    /// # Errors
    /// `Error::BadArg` if `bytes.len() > 255`.
    pub fn try_from_bytes<'a>(env: Env<'a>, bytes: &[u8]) -> NifResult<Option<Atom>> {
        if bytes.len() > 255 {
            return Err(Error::BadArg);
        }
        unsafe {
            match atom::make_existing_atom(env.as_c_arg(), bytes) {
                Some(term) => Ok(Some(Atom::from_nif_term(term))),
                None => Ok(None),
            }
        }
    }

    /// Return the atom whose text representation is the given `string`, like `erlang:list_to_atom/2`.
    ///
    /// # Errors
    /// `Error::BadArg` if `string` contains characters that aren't in Latin-1, or if it's too
    /// long. The maximum length is 255 characters.
    pub fn from_str<'a>(env: Env<'a>, string: &str) -> NifResult<Atom> {
        if string.is_ascii() {
            // Fast path.
            Atom::from_bytes(env, string.as_bytes())
        } else {
            // Convert from Rust UTF-8 to Latin-1.
            let mut bytes = Vec::with_capacity(string.len());
            for c in string.chars() {
                if (c as u32) >= 256 {
                    return Err(Error::BadArg);
                }
                bytes.push(c as u8);
            }
            Atom::from_bytes(env, &bytes)
        }
    }
}

use std::fmt;
impl fmt::Debug for Atom {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        crate::wrapper::term::fmt(self.as_c_arg(), f)
    }
}

impl Encoder for Atom {
    fn encode<'a>(&self, env: Env<'a>) -> Term<'a> {
        self.to_term(env)
    }
}
impl<'a> Decoder<'a> for Atom {
    fn decode(term: Term<'a>) -> NifResult<Atom> {
        Atom::from_term(term)
    }
}

impl<'a> PartialEq<Term<'a>> for Atom {
    fn eq(&self, other: &Term<'a>) -> bool {
        self.as_c_arg() == other.as_c_arg()
    }
}

/// ## Atom terms
impl<'a> Term<'a> {
    /// When the term is an atom, this method will return the string
    /// representation of it.
    ///
    /// If you only need to test for equality, comparing the terms directly
    /// is much faster.
    ///
    /// Will return None if the term is not an atom.
    pub fn atom_to_string(&self) -> NifResult<String> {
        unsafe { atom::get_atom(self.get_env().as_c_arg(), self.as_c_arg()) }
    }
}

pub fn is_truthy(term: Term) -> bool {
    !((term.as_c_arg() == false_().as_c_arg()) || (term.as_c_arg() == nil().as_c_arg()))
}

pub(in crate::types) fn decode_bool(term: Term) -> NifResult<bool> {
    let as_c_arg = term.as_c_arg();

    if as_c_arg == true_().as_c_arg() {
        return Ok(true);
    }

    if as_c_arg == false_().as_c_arg() {
        return Ok(false);
    }

    Err(Error::BadArg)
}

// This is safe because atoms are never removed/changed once they are created.
unsafe impl Sync for Atom {}
unsafe impl Send for Atom {}

/// Macro for defining Rust functions that return Erlang atoms.
/// To use this macro, you must also import the `lazy_static` crate.
///
/// For example, this code:
///
///     #[macro_use] extern crate rustler;
///
///     mod my_atoms {
///         rustler::atoms! {
///             jpeg,
///         }
///     }
///     # fn main() {}
///
/// defines a public function `my_atoms::jpeg()` that returns the `Atom` for the `jpeg` atom.
///
/// Multiple atoms can be defined. Each one can have its own doc comment and other attributes.
///
///     # #[macro_use] extern crate rustler;
///     rustler::atoms! {
///         /// The `jpeg` atom.
///         jpeg,
///
///         /// The `png` atom.
///         png,
///
///         #[allow(non_snake_case)]
///         WebP,
///     }
///     # fn main() {}
///
/// When you need an atom that's not a legal Rust function name, write `NAME = "ATOM"`, like
/// this:
///
///     # #[macro_use] extern crate rustler;
///     rustler::atoms! {
///         /// The `mod` atom. The function isn't called `mod` because that's
///         /// a Rust keyword.
///         mod_atom = "mod",
///
///         /// The atom `'hello world'`. Obviously this function can't be
///         /// called `hello world` because there's a space in it.
///         hello_world = "hello world",
///     }
///     # fn main() {}
///
/// # Performance
///
/// These functions are faster than `get_atom` and `get_atom_init`. The first time you call one, it
/// creates atoms for all its sibling functions and caches them, so that all later calls are fast.
/// The only overhead is checking that the atoms have been created (an atomic integer read).
///
#[macro_export]
macro_rules! atoms {
    {
        $(
            $( #[$attr:meta] )*
            $name:ident $( = $str:expr )?
        ),*$(,)?
    } => {
        #[allow(non_snake_case)]
        struct RustlerAtoms {
            $( $name : $crate::types::atom::Atom ),*
        }
        $crate::lazy_static::lazy_static! {
            static ref RUSTLER_ATOMS: RustlerAtoms = $crate::env::OwnedEnv::new().run(|env| {
                RustlerAtoms {
                    $( $name: $crate::atoms!(@internal_make_atom(env, $name $( = $str)? )) ),*
                }
            });
        }
        $(
            $( #[$attr] )*
            pub fn $name() -> $crate::types::atom::Atom {
                RUSTLER_ATOMS.$name
            }
        )*
    };

    // Internal helper macros.
    { @internal_make_atom($env:ident, $name:ident) } => {
        $crate::atoms!(@internal_make_atom($env, $name = stringify!($name)))
    };
    { @internal_make_atom($env:ident, $name:ident = $str:expr) } => {
        $crate::types::atom::Atom::from_str($env, $str)
            .ok().expect("rustler::atoms!: bad atom string")
    };
}

#[macro_export]
#[deprecated(since = "0.22.0", note = "Please use `atoms!` instead.")]
macro_rules! rustler_atoms {
    {
        $(
            $( #[$attr:meta] )*
            atom $name:ident $( = $str:expr )?;
        )*
    } => {
        #[allow(non_snake_case)]
        struct RustlerAtoms {
            $( $name : $crate::types::atom::Atom ),*
        }
        $crate::lazy_static::lazy_static! {
            static ref RUSTLER_ATOMS: RustlerAtoms = $crate::env::OwnedEnv::new().run(|env| {
                RustlerAtoms {
                    $( $name: $crate::rustler_atoms!(@internal_make_atom(env, $name $( = $str)? )) ),*
                }
            });
        }
        $(
            $( #[$attr] )*
            pub fn $name() -> $crate::types::atom::Atom {
                RUSTLER_ATOMS.$name
            }
        )*
    };

    // Internal helper macros.
    { @internal_make_atom($env:ident, $name:ident) } => {
        $crate::rustler_atoms!(@internal_make_atom($env, $name = stringify!($name)))
    };
    { @internal_make_atom($env:ident, $name:ident = $str:expr) } => {
        $crate::types::atom::Atom::from_str($env, $str)
            .expect("rustler::atoms!: bad atom string")
    };
}

atoms! {
    /// The `nil` atom.
    nil,

    /// The `ok` atom, commonly used in success tuples.
    ok,

    /// The `error` atom, commonly used in error tuples.
    error,

    /// The `badarg` atom, which Rustler sometimes returns to indicate that a function was
    /// called with incorrect arguments.
    badarg,

    /// The `false` atom. (Trailing underscore because `false` is a keyword in Rust.)
    ///
    /// If you're looking to convert between Erlang terms and Rust `bool`
    /// values, use `Encoder` and `Decoder` instead.
    false_ = "false",

    /// The `true` atom. (Trailing underscore because `true` is a keyword in Rust.)
    ///
    /// If you're looking to convert between Erlang terms and Rust `bool`
    /// values, use `Encoder` and `Decoder` instead.
    true_ = "true",

    /// The `__struct__` atom used by Elixir.
    __struct__,

    /// The `first` atom used by `Elixir.Range`.
    first,

    /// The `last` atom used by `Elixir.Range`.
    last,
}
<|endoftext|>


<commit_before>// crypto_verify_32.h

extern {
    pub fn crypto_verify_32(x: *const u8, y: *const u8) -> c_int;
}<commit_msg>Completes definitions from crypto_verify_32.h<commit_after>// crypto_verify_32.h

pub const crypto_verify_32_BYTES: usize = 32;

extern {
    pub fn crypto_verify_32_bytes() -> size_t;
    pub fn crypto_verify_32(
        x: *const [u8; crypto_verify_32_BYTES],
        y: *const [u8; crypto_verify_32_BYTES]) -> c_int;
}

#[test]
fn test_crypto_verify_32_bytes() {
   assert_eq!(unsafe { crypto_verify_32_bytes() as usize },
                       crypto_verify_32_BYTES);
}
<|endoftext|>


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

use borrow_check::nll::region_infer::values::ToElementIndex;
use borrow_check::nll::region_infer::{Cause, ConstraintIndex, RegionInferenceContext};
use borrow_check::nll::region_infer::{ConstraintIndex, RegionInferenceContext};
use borrow_check::nll::type_check::Locations;
use rustc::hir::def_id::DefId;
use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
use rustc::infer::InferCtxt;
use rustc::mir::{self, Location, Mir, Place, Rvalue, StatementKind, TerminatorKind};
use rustc::ty::RegionVid;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::indexed_vec::IndexVec;
use std::fmt;
use syntax_pos::Span;

/// Constraints that are considered interesting can be categorized to
/// determine why they are interesting. Order of variants indicates
/// sort order of the category, thereby influencing diagnostic output.
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord)]
enum ConstraintCategory {
    Cast,
    Assignment,
    Return,
    CallArgument,
    Other,
    Boring,
}

impl fmt::Display for ConstraintCategory {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ConstraintCategory::Assignment => write!(f, "assignment"),
            ConstraintCategory::Return => write!(f, "return"),
            ConstraintCategory::Cast => write!(f, "cast"),
            ConstraintCategory::CallArgument => write!(f, "argument"),
            _ => write!(f, "free region"),
        }
    }
}

impl<'tcx> RegionInferenceContext<'tcx> {
    /// Walks the graph of constraints (where `'a: 'b` is considered
    /// an edge `'b -> 'a`) to find all paths from `from_region` to
    /// `to_region`. The paths are accumulated into the vector
    /// `results`. The paths are stored as a series of
    /// `ConstraintIndex` values -- in other words, a list of *edges*.
    ///
    /// # Parameters
    ///
    /// - `from_region`
    /// When reporting an error, it is useful to be able to determine
    /// which constraints influenced the region being reported as an
    /// error. This function finds all of the paths from the
    /// constraint.
    fn find_constraint_paths_between_regions(
        &self,
        from_region: RegionVid,
        target_test: impl Fn(RegionVid) -> bool,
    ) -> Vec<Vec<ConstraintIndex>> {
        let mut results = vec![];
        self.find_constraint_paths_between_regions_helper(
            from_region,
            from_region,
            &target_test,
            &mut FxHashSet::default(),
            &mut vec![],
            &mut results,
        );
        results
    }

    /// Helper for `find_constraint_paths_between_regions`.
    fn find_constraint_paths_between_regions_helper(
        &self,
        from_region: RegionVid,
        current_region: RegionVid,
        target_test: &impl Fn(RegionVid) -> bool,
        visited: &mut FxHashSet<RegionVid>,
        stack: &mut Vec<ConstraintIndex>,
        results: &mut Vec<Vec<ConstraintIndex>>,
    ) {
        let dependency_map = self.dependency_map.as_ref().unwrap();

        // Check if we already visited this region.
        if !visited.insert(current_region) {
            return;
        }

        // Check if we reached the region we were looking for.
        if target_test(current_region) {
            if !stack.is_empty() {
                assert_eq!(self.constraints[stack[0]].sub, from_region);
                results.push(stack.clone());
            }
            return;
        }

        self.constraints
            .each_affected_by_dirty(dependency_map[current_region], |constraint| {
                assert_eq!(self.constraints[constraint].sub, current_region);
                stack.push(constraint);
                self.find_constraint_paths_between_regions_helper(
                    from_region,
                    self.constraints[constraint].sup,
                    target_test,
                    visited,
                    stack,
                    results,
                );
                stack.pop();
            });
    }

    /// This function will return true if a constraint is interesting and false if a constraint
    /// is not. It is useful in filtering constraint paths to only interesting points.
    fn constraint_is_interesting(&self, index: ConstraintIndex) -> bool {
        let constraint = self.constraints[index];
        debug!(
            "constraint_is_interesting: locations={:?} constraint={:?}",
            constraint.locations, constraint
        );
        if let Locations::Interesting(_) = constraint.locations {
            true
        } else {
            false
        }
    }

    /// This function classifies a constraint from a location.
    fn classify_constraint(
        &self,
        index: ConstraintIndex,
        mir: &Mir<'tcx>,
    ) -> Option<(ConstraintCategory, Span)> {
        let constraint = self.constraints[index];
        let span = constraint.locations.span(mir);
        let location = constraint.locations.from_location()?;

        if !self.constraint_is_interesting(index) {
            return Some((ConstraintCategory::Boring, span));
        }

        let data = &mir[location.block];
        let category = if location.statement_index == data.statements.len() {
            if let Some(ref terminator) = data.terminator {
                match terminator.kind {
                    TerminatorKind::DropAndReplace { .. } => ConstraintCategory::Assignment,
                    TerminatorKind::Call { .. } => ConstraintCategory::CallArgument,
                    _ => ConstraintCategory::Other,
                }
            } else {
                ConstraintCategory::Other
            }
        } else {
            let statement = &data.statements[location.statement_index];
            match statement.kind {
                StatementKind::Assign(ref place, ref rvalue) => {
                    if *place == Place::Local(mir::RETURN_PLACE) {
                        ConstraintCategory::Return
                    } else {
                        match rvalue {
                            Rvalue::Cast(..) => ConstraintCategory::Cast,
                            Rvalue::Use(..) => ConstraintCategory::Assignment,
                            _ => ConstraintCategory::Other,
                        }
                    }
                }
                _ => ConstraintCategory::Other,
            }
        };

        Some((category, span))
    }

    /// Report an error because the universal region `fr` was required to outlive
    /// `outlived_fr` but it is not known to do so. For example:
    ///
    /// ```
    /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
    /// ```
    ///
    /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`.
    pub(super) fn report_error(
        &self,
        mir: &Mir<'tcx>,
        infcx: &InferCtxt<'_, '_, 'tcx>,
        mir_def_id: DefId,
        fr: RegionVid,
        outlived_fr: RegionVid,
        blame_span: Span,
    ) {
        debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);

        let fr_name = self.to_error_region(fr);
        let outlived_fr_name = self.to_error_region(outlived_fr);

        if let (Some(f), Some(o)) = (fr_name, outlived_fr_name) {
            let tables = infcx.tcx.typeck_tables_of(mir_def_id);
            let nice = NiceRegionError::new_from_span(infcx.tcx, blame_span, o, f, Some(tables));
            if let Some(_error_reported) = nice.try_report() {
                return;
            }
        }

        let fr_string = match fr_name {
            Some(r) => format!("free region `{}`", r),
            None => format!("free region `{:?}`", fr),
        };

        let outlived_fr_string = match outlived_fr_name {
            Some(r) => format!("free region `{}`", r),
            None => format!("free region `{:?}`", outlived_fr),
        };

        // Find all paths
        let constraint_paths = self.find_constraint_paths_between_regions(outlived_fr, |r| r == fr);
        debug!("report_error: constraint_paths={:#?}", constraint_paths);

        // Find the shortest such path.
        let path = constraint_paths.iter().min_by_key(|p| p.len()).unwrap();
        debug!("report_error: shortest_path={:?}", path);

        // Classify each of the constraints along the path.
        let mut categorized_path: Vec<(ConstraintCategory, Span)> = path.iter()
            .filter_map(|&index| self.classify_constraint(index, mir))
            .collect();
        debug!("report_error: categorized_path={:?}", categorized_path);

        // Find what appears to be the most interesting path to report to the user.
        categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0));
        debug!("report_error: sorted_path={:?}", categorized_path);

        // If we found something, cite that as the main cause of the problem.
        if let Some((category, span)) = categorized_path.first() {
            let mut diag = infcx.tcx.sess.struct_span_err(
                *span,
                &format!(
                    "{} requires that data must outlive {}",
                    category, outlived_fr_string
                ),
            );

            diag.emit();
        } else {
            let mut diag = infcx.tcx.sess.struct_span_err(
                blame_span,
                &format!("{} does not outlive {}", fr_string, outlived_fr_string,),
            );

            diag.emit();
        }
    }

    // Find some constraint `X: Y` where:
    // - `fr1: X` transitively
    // - and `Y` is live at `elem`
    crate fn find_constraint(&self, fr1: RegionVid, elem: Location) -> RegionVid {
        let index = self.blame_constraint(fr1, elem);
        self.constraints[index].sub
    }

    /// Tries to finds a good span to blame for the fact that `fr1`
    /// contains `fr2`.
    pub(super) fn blame_constraint(
        &self,
        fr1: RegionVid,
        elem: impl ToElementIndex,
    ) -> ConstraintIndex {
        // Find everything that influenced final value of `fr`.
        let influenced_fr1 = self.dependencies(fr1);

        // Try to find some outlives constraint `'X: fr2` where `'X`
        // influenced `fr1`. Blame that.
        //
        // NB, this is a pretty bad choice most of the time. In
        // particular, the connection between `'X` and `fr1` may not
        // be obvious to the user -- not to mention the naive notion
        // of dependencies, which doesn't account for the locations of
        // contraints at all. But it will do for now.
        let relevant_constraint = self.constraints
            .iter_enumerated()
            .filter_map(|(i, constraint)| {
                if !self.liveness_constraints.contains(constraint.sub, elem) {
                    None
                } else {
                    influenced_fr1[constraint.sup]
                        .map(|distance| (distance, i))
                }
            })
            .min() // constraining fr1 with fewer hops *ought* to be more obvious
            .map(|(_dist, i)| i);

        relevant_constraint.unwrap_or_else(|| {
            bug!(
                "could not find any constraint to blame for {:?}: {:?}",
                fr1,
                elem,
            );
        })
    }

    /// Finds all regions whose values `'a` may depend on in some way.
    /// For each region, returns either `None` (does not influence
    /// `'a`) or `Some(d)` which indicates that it influences `'a`
    /// with distinct `d` (minimum number of edges that must be
    /// traversed).
    ///
    /// Used during error reporting, extremely naive and inefficient.
    fn dependencies(&self, r0: RegionVid) -> IndexVec<RegionVid, Option<usize>> {
        let mut result_set = IndexVec::from_elem(None, &self.definitions);
        let mut changed = true;
        result_set[r0] = Some(0); // distance 0 from `r0`

        while changed {
            changed = false;
            for constraint in &*self.constraints {
                if let Some(n) = result_set[constraint.sup] {
                    let m = n + 1;
                    if result_set[constraint.sub]
                        .map(|distance| m < distance)
                        .unwrap_or(true)
                    {
                        result_set[constraint.sub] = Some(m);
                        changed = true;
                    }
                }
            }
        }

        result_set
    }
}
<commit_msg>always create a category, even it is just "boring"<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use borrow_check::nll::region_infer::values::ToElementIndex;
use borrow_check::nll::region_infer::{Cause, ConstraintIndex, RegionInferenceContext};
use borrow_check::nll::region_infer::{ConstraintIndex, RegionInferenceContext};
use borrow_check::nll::type_check::Locations;
use rustc::hir::def_id::DefId;
use rustc::infer::error_reporting::nice_region_error::NiceRegionError;
use rustc::infer::InferCtxt;
use rustc::mir::{self, Location, Mir, Place, Rvalue, StatementKind, TerminatorKind};
use rustc::ty::RegionVid;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::indexed_vec::IndexVec;
use std::fmt;
use syntax_pos::Span;

/// Constraints that are considered interesting can be categorized to
/// determine why they are interesting. Order of variants indicates
/// sort order of the category, thereby influencing diagnostic output.
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord)]
enum ConstraintCategory {
    Cast,
    Assignment,
    Return,
    CallArgument,
    Other,
    Boring,
}

impl fmt::Display for ConstraintCategory {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ConstraintCategory::Assignment => write!(f, "assignment"),
            ConstraintCategory::Return => write!(f, "return"),
            ConstraintCategory::Cast => write!(f, "cast"),
            ConstraintCategory::CallArgument => write!(f, "argument"),
            _ => write!(f, "free region"),
        }
    }
}

impl<'tcx> RegionInferenceContext<'tcx> {
    /// Walks the graph of constraints (where `'a: 'b` is considered
    /// an edge `'b -> 'a`) to find all paths from `from_region` to
    /// `to_region`. The paths are accumulated into the vector
    /// `results`. The paths are stored as a series of
    /// `ConstraintIndex` values -- in other words, a list of *edges*.
    ///
    /// # Parameters
    ///
    /// - `from_region`
    /// When reporting an error, it is useful to be able to determine
    /// which constraints influenced the region being reported as an
    /// error. This function finds all of the paths from the
    /// constraint.
    fn find_constraint_paths_between_regions(
        &self,
        from_region: RegionVid,
        target_test: impl Fn(RegionVid) -> bool,
    ) -> Vec<Vec<ConstraintIndex>> {
        let mut results = vec![];
        self.find_constraint_paths_between_regions_helper(
            from_region,
            from_region,
            &target_test,
            &mut FxHashSet::default(),
            &mut vec![],
            &mut results,
        );
        results
    }

    /// Helper for `find_constraint_paths_between_regions`.
    fn find_constraint_paths_between_regions_helper(
        &self,
        from_region: RegionVid,
        current_region: RegionVid,
        target_test: &impl Fn(RegionVid) -> bool,
        visited: &mut FxHashSet<RegionVid>,
        stack: &mut Vec<ConstraintIndex>,
        results: &mut Vec<Vec<ConstraintIndex>>,
    ) {
        let dependency_map = self.dependency_map.as_ref().unwrap();

        // Check if we already visited this region.
        if !visited.insert(current_region) {
            return;
        }

        // Check if we reached the region we were looking for.
        if target_test(current_region) {
            if !stack.is_empty() {
                assert_eq!(self.constraints[stack[0]].sub, from_region);
                results.push(stack.clone());
            }
            return;
        }

        self.constraints
            .each_affected_by_dirty(dependency_map[current_region], |constraint| {
                assert_eq!(self.constraints[constraint].sub, current_region);
                stack.push(constraint);
                self.find_constraint_paths_between_regions_helper(
                    from_region,
                    self.constraints[constraint].sup,
                    target_test,
                    visited,
                    stack,
                    results,
                );
                stack.pop();
            });
    }

    /// This function will return true if a constraint is interesting and false if a constraint
    /// is not. It is useful in filtering constraint paths to only interesting points.
    fn constraint_is_interesting(&self, index: ConstraintIndex) -> bool {
        let constraint = self.constraints[index];
        debug!(
            "constraint_is_interesting: locations={:?} constraint={:?}",
            constraint.locations, constraint
        );
        if let Locations::Interesting(_) = constraint.locations {
            true
        } else {
            false
        }
    }

    /// This function classifies a constraint from a location.
    fn classify_constraint(
        &self,
        index: ConstraintIndex,
        mir: &Mir<'tcx>,
    ) -> (ConstraintCategory, Span) {
        let constraint = self.constraints[index];
        let span = constraint.locations.span(mir);
        let location = constraint.locations.from_location().unwrap_or(Location::START);

        if !self.constraint_is_interesting(index) {
            return (ConstraintCategory::Boring, span);
        }

        let data = &mir[location.block];
        let category = if location.statement_index == data.statements.len() {
            if let Some(ref terminator) = data.terminator {
                match terminator.kind {
                    TerminatorKind::DropAndReplace { .. } => ConstraintCategory::Assignment,
                    TerminatorKind::Call { .. } => ConstraintCategory::CallArgument,
                    _ => ConstraintCategory::Other,
                }
            } else {
                ConstraintCategory::Other
            }
        } else {
            let statement = &data.statements[location.statement_index];
            match statement.kind {
                StatementKind::Assign(ref place, ref rvalue) => {
                    if *place == Place::Local(mir::RETURN_PLACE) {
                        ConstraintCategory::Return
                    } else {
                        match rvalue {
                            Rvalue::Cast(..) => ConstraintCategory::Cast,
                            Rvalue::Use(..) => ConstraintCategory::Assignment,
                            _ => ConstraintCategory::Other,
                        }
                    }
                }
                _ => ConstraintCategory::Other,
            }
        };

        (category, span)
    }

    /// Report an error because the universal region `fr` was required to outlive
    /// `outlived_fr` but it is not known to do so. For example:
    ///
    /// ```
    /// fn foo<'a, 'b>(x: &'a u32) -> &'b u32 { x }
    /// ```
    ///
    /// Here we would be invoked with `fr = 'a` and `outlived_fr = `'b`.
    pub(super) fn report_error(
        &self,
        mir: &Mir<'tcx>,
        infcx: &InferCtxt<'_, '_, 'tcx>,
        mir_def_id: DefId,
        fr: RegionVid,
        outlived_fr: RegionVid,
        blame_span: Span,
    ) {
        debug!("report_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);

        let fr_name = self.to_error_region(fr);
        let outlived_fr_name = self.to_error_region(outlived_fr);

        if let (Some(f), Some(o)) = (fr_name, outlived_fr_name) {
            let tables = infcx.tcx.typeck_tables_of(mir_def_id);
            let nice = NiceRegionError::new_from_span(infcx.tcx, blame_span, o, f, Some(tables));
            if let Some(_error_reported) = nice.try_report() {
                return;
            }
        }

        let fr_string = match fr_name {
            Some(r) => format!("free region `{}`", r),
            None => format!("free region `{:?}`", fr),
        };

        let outlived_fr_string = match outlived_fr_name {
            Some(r) => format!("free region `{}`", r),
            None => format!("free region `{:?}`", outlived_fr),
        };

        // Find all paths
        let constraint_paths = self.find_constraint_paths_between_regions(outlived_fr, |r| r == fr);
        debug!("report_error: constraint_paths={:#?}", constraint_paths);

        // Find the shortest such path.
        let path = constraint_paths.iter().min_by_key(|p| p.len()).unwrap();
        debug!("report_error: shortest_path={:?}", path);

        // Classify each of the constraints along the path.
        let mut categorized_path: Vec<(ConstraintCategory, Span)> = path.iter()
            .map(|&index| self.classify_constraint(index, mir))
            .collect();
        debug!("report_error: categorized_path={:?}", categorized_path);

        // Find what appears to be the most interesting path to report to the user.
        categorized_path.sort_by(|p0, p1| p0.0.cmp(&p1.0));
        debug!("report_error: sorted_path={:?}", categorized_path);

        // If we found something, cite that as the main cause of the problem.
        if let Some((category, span)) = categorized_path.first() {
            let mut diag = infcx.tcx.sess.struct_span_err(
                *span,
                &format!(
                    "{} requires that data must outlive {}",
                    category, outlived_fr_string
                ),
            );

            diag.emit();
        } else {
            let mut diag = infcx.tcx.sess.struct_span_err(
                blame_span,
                &format!("{} does not outlive {}", fr_string, outlived_fr_string,),
            );

            diag.emit();
        }
    }

    // Find some constraint `X: Y` where:
    // - `fr1: X` transitively
    // - and `Y` is live at `elem`
    crate fn find_constraint(&self, fr1: RegionVid, elem: Location) -> RegionVid {
        let index = self.blame_constraint(fr1, elem);
        self.constraints[index].sub
    }

    /// Tries to finds a good span to blame for the fact that `fr1`
    /// contains `fr2`.
    pub(super) fn blame_constraint(
        &self,
        fr1: RegionVid,
        elem: impl ToElementIndex,
    ) -> ConstraintIndex {
        // Find everything that influenced final value of `fr`.
        let influenced_fr1 = self.dependencies(fr1);

        // Try to find some outlives constraint `'X: fr2` where `'X`
        // influenced `fr1`. Blame that.
        //
        // NB, this is a pretty bad choice most of the time. In
        // particular, the connection between `'X` and `fr1` may not
        // be obvious to the user -- not to mention the naive notion
        // of dependencies, which doesn't account for the locations of
        // contraints at all. But it will do for now.
        let relevant_constraint = self.constraints
            .iter_enumerated()
            .filter_map(|(i, constraint)| {
                if !self.liveness_constraints.contains(constraint.sub, elem) {
                    None
                } else {
                    influenced_fr1[constraint.sup]
                        .map(|distance| (distance, i))
                }
            })
            .min() // constraining fr1 with fewer hops *ought* to be more obvious
            .map(|(_dist, i)| i);

        relevant_constraint.unwrap_or_else(|| {
            bug!(
                "could not find any constraint to blame for {:?}: {:?}",
                fr1,
                elem,
            );
        })
    }

    /// Finds all regions whose values `'a` may depend on in some way.
    /// For each region, returns either `None` (does not influence
    /// `'a`) or `Some(d)` which indicates that it influences `'a`
    /// with distinct `d` (minimum number of edges that must be
    /// traversed).
    ///
    /// Used during error reporting, extremely naive and inefficient.
    fn dependencies(&self, r0: RegionVid) -> IndexVec<RegionVid, Option<usize>> {
        let mut result_set = IndexVec::from_elem(None, &self.definitions);
        let mut changed = true;
        result_set[r0] = Some(0); // distance 0 from `r0`

        while changed {
            changed = false;
            for constraint in &*self.constraints {
                if let Some(n) = result_set[constraint.sup] {
                    let m = n + 1;
                    if result_set[constraint.sub]
                        .map(|distance| m < distance)
                        .unwrap_or(true)
                    {
                        result_set[constraint.sub] = Some(m);
                        changed = true;
                    }
                }
            }
        }

        result_set
    }
}
<|endoftext|>


<commit_before>use std::{result, io, net};
use server;
///Represents a Fastnet error.
#[derive(Debug)]
pub enum Error {
    TimedOut,
    HostNotFound,
    PeerNotFound,
    NotListening,
    IncompatibleVersions,
    ConnectionAborted,
    MessageTooLarge,
    IoError(io::Error),
}

pub type Result<T> = result::Result<T, Error>;

/**A Fastnet server.

Fastnet does not distinguish between clients and servers.  This is used both for connecting to other peers and listening for incoming connections.*/
pub struct Server<H: Handler+Send+'static> {
    server: server::MioServer<H>,
}

impl<H: Handler+Send+'static> Server<H> {
    pub fn new(addr: net::SocketAddr, handler: H)->Result<Server<H>> {
        let s = try!(server::MioServer::new(addr, handler).map_err(Error::IoError));
        Ok(Server{server: s})
    }

    /**For debugging, as this implementation is currently alpha.

    This will go away, but enables printing sent/received packets to stdout, among other things.*/
    pub fn enable_debug_print(&mut self) {
        self.server.with(|s| s.enable_debug_print());
    }

    /**Schedule a connection request.

    This will cause the associated handler to be passed the result with the specified request ID.*/
    pub fn connect(&mut self, addr: net::SocketAddr, request_id: u64) {
        self.server.with(move |s| s.connect(addr, request_id));
    }

    /**Disconnect from a peer with the specified ID.*/
    pub fn disconnect(&mut self, id: u64, request_id: u64) {
        self.server.with(move |s| s.disconnect(id, request_id));
    }
}

/**An event handler.

The methods in this trait are called in a thread which is running in the background, not on the main thread.  None of them should ever block.*/
pub trait Handler {
    fn connected(&mut self, id: u64, request_id: Option<u64>);
    fn disconnected(&mut self, id: u64, request_id: Option<u64>);
    fn incoming_message(&mut self, id: u64, channel: u16, payload: &[u8]);
    fn request_failed(&mut self, request_id: u64, error: Error);
}
<commit_msg>Stub examples for a simple client and server.<commit_after>use std::{result, io, net};
use server;
///Represents a Fastnet error.
#[derive(Debug)]
pub enum Error {
    TimedOut,
    HostNotFound,
    PeerNotFound,
    NotListening,
    IncompatibleVersions,
    ConnectionAborted,
    MessageTooLarge,
    IoError(io::Error),
}

pub type Result<T> = result::Result<T, Error>;

/**A Fastnet server.

Fastnet does not distinguish between clients and servers.  This is used both for connecting to other peers and listening for incoming connections.*/
pub struct Server<H: Handler+Send+'static> {
    server: server::MioServer<H>,
}

impl<H: Handler+Send+'static> Server<H> {
    pub fn new(addr: net::SocketAddr, handler: H)->Result<Server<H>> {
        let s = try!(server::MioServer::new(addr, handler).map_err(Error::IoError));
        Ok(Server{server: s})
    }

    /**For debugging, as this implementation is currently alpha.

    This will go away, but enables printing sent/received packets to stdout, among other things.*/
    pub fn enable_debug_print(&mut self) {
        self.server.with(|s| s.enable_debug_print());
    }

    /**Schedule a connection request.

    This will cause the associated handler to be passed the result with the specified request ID.*/
    pub fn connect(&mut self, addr: net::SocketAddr, request_id: u64) {
        self.server.with(move |s| s.connect(addr, request_id));
    }

    /**Disconnect from a peer with the specified ID.*/
    pub fn disconnect(&mut self, id: u64, request_id: u64) {
        self.server.with(move |s| s.disconnect(id, request_id));
    }
}

/**An event handler.

The methods in this trait are called in a thread which is running in the background, not on the main thread.  None of them should ever block.*/
pub trait Handler {
    fn connected(&mut self, id: u64, request_id: Option<u64>) {
    }

    fn disconnected(&mut self, id: u64, request_id: Option<u64>) {
    }

    fn incoming_message(&mut self, id: u64, channel: u16, payload: &[u8]) {
    }

    fn request_failed(&mut self, request_id: u64, error: Error) {
    }
}
<|endoftext|>


<commit_before>use libc::{self, c_int, c_uint, c_void};
use nix;
use std::collections::BTreeMap;
use std::ffi::CString;
use std::error::Error;
use libaio::{self, aio_context_t, io_event, iocb};
use std::ptr;
use std::slice;

const MAX_EVENTS: c_int = 32;

// Meaning of block/sector sizes:
//
// physical block size - true physical block size of hardware
// sector size - minimum size of reads and writes supported by hardware (potentially smaller than
// physical block size)
// (logical) block size - a value that may actually vary across partitions, depending on whether a filesystem
// is mounted
//
// Alignment for O_DIRECT:
//
// In 2.4: buffer offset and transfer size must be multiples of logical block size.
// In 2.5: buffer offset and transfer size must be multiples of sector size.
//
// See https://lists.gt.net/linux/kernel/350775

#[derive(Debug)]
pub struct BlockDevice {
    block_size_physical: usize,
    context: aio_context_t,
    fd: c_int,
    iocbs: Vec<(bool, iocb)>,
    requests: BTreeMap<usize, Request>,
    sector_size: usize,
    size_bytes: u64,
}

mod ioctl {
    use libc::c_uint;
    pub const BLK: c_uint = 0x12;
    pub const SSZGET: c_uint = 104;
    pub const GETSIZE64: c_uint = 114;
    pub const PBSZGET: c_uint = 123;
}

#[derive(Debug)]
pub struct Request {
    pub offset: u64,
    pub size: u64,
    pub buffer: Buffer,
    pub result: isize,
}

impl Request {
    pub fn new(offset: u64, size: u64, buffer: Buffer) -> Request {
        assert!(buffer.size as u64 >= size, "Supplied buffer is too small");
        Request {
            offset: offset,
            size: size,
            buffer: buffer,
            result: -1,
        }
    }

    pub fn get_data(&self) -> &[u8] {
        if self.result < 0 {
            &[]
        } else {
            &self.buffer.as_slice()[0..(self.result as usize)]
        }
    }

    pub fn reclaim_buffer(self) -> Buffer {
        self.buffer
    }

    pub fn is_data_zeros(&self) -> bool {
        for c in self.get_data() {
            if *c != 0 {
                return false;
            }
        }
        return true;
    }
}

#[derive(Debug)]
pub struct Buffer {
    alignment: usize,
    size: usize,
    data: *mut c_void,
}

impl Buffer {
    pub fn allocate_aligned(size: usize, alignment: usize) -> Buffer {
        let buffer = unsafe { libc::memalign(alignment, size) };
        if buffer.is_null() {
            panic!("Buffer allocation failed!");
        }
        Buffer {
            alignment: alignment,
            size: size,
            data: buffer,
        }
    }

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

    pub fn as_slice(&self) -> &[u8] {
        unsafe {
            let data = self.data as *const u8;
            slice::from_raw_parts(data, self.size)
        }
    }

    pub fn clear(&mut self) {
        unsafe {
            libc::memset(self.data, 0, self.size);
        }
    }
}

impl Drop for Buffer {
    fn drop(&mut self) {
        unsafe {
            libc::free(self.data);
        }
    }
}

impl BlockDevice {
    pub fn open(path: &str) -> Result<BlockDevice, Box<Error>> {
        let path = CString::new(path)?;
        let fd = unsafe { libc::open(path.as_ptr(), libc::O_RDONLY | libc::O_DIRECT) };
        if fd == -1 {
            return Err(Box::new(Self::fail_errno()));
        }
        let block_size_physical = Self::query_block_size_physical(fd)?;
        let sector_size = Self::query_sector_size(fd)?;
        let size_bytes = Self::query_size_bytes(fd)?;
        let iocbs = vec![(false, iocb::new()); MAX_EVENTS as usize];
        let mut context: aio_context_t = ptr::null_mut();
        if unsafe { libaio::io_setup(iocbs.len() as i32, &mut context as *mut aio_context_t) } == -1 {
            return Err(Box::new(Self::fail_errno()));
        }

        let result = BlockDevice {
            context: context,
            block_size_physical: block_size_physical as usize,
            fd: fd,
            iocbs: iocbs,
            requests: BTreeMap::new(),
            size_bytes: size_bytes,
            sector_size: sector_size as usize,
        };
        Ok(result)
    }

    fn query_block_size_physical(fd: c_int) -> Result<c_uint, nix::Error> {
        let mut block_size_physical: c_uint = 0;
        let ioc = ioc!(nix::sys::ioctl::NONE, ioctl::BLK, ioctl::PBSZGET, 0);
        if unsafe { libc::ioctl(fd, ioc, &mut block_size_physical as *mut c_uint) } == -1 {
            Err(Self::fail_errno())
        } else {
            Ok(block_size_physical)
        }
    }

    fn query_sector_size(fd: c_int) -> Result<c_uint, nix::Error> {
        let mut sector_size: c_uint = 0;
        let ioc = ioc!(nix::sys::ioctl::NONE, ioctl::BLK, ioctl::SSZGET, 0);
        if unsafe { libc::ioctl(fd, ioc, &mut sector_size as *mut c_uint) } == -1 {
            Err(Self::fail_errno())
        } else {
            Ok(sector_size)
        }
    }

    fn query_size_bytes(fd: c_int) -> Result<u64, nix::Error> {
        let mut size_bytes: u64 = 0;
        let ioc = ior!(ioctl::BLK, ioctl::GETSIZE64, 8);
        if unsafe { libc::ioctl(fd, ioc, &mut size_bytes as *mut u64) } == -1 {
            Err(Self::fail_errno())
        } else {
            Ok(size_bytes)
        }
    }

    pub fn submit_request(&mut self, req: Request) -> Result<(), nix::Error> {
        assert!(self.requests_avail() > 0);
        let slot = self.find_slot();
        let iocb = &mut self.iocbs[slot];
        iocb.0 = true;
        libaio::io_prep_pread(&mut iocb.1, self.fd as u32, req.buffer.data, req.size, req.offset as i64);
        let iocb_ptr = &mut iocb.1 as *mut iocb;
        let mut iocb_list = [iocb_ptr];
        //let iocb_list = &mut iocb_ptr as *mut *mut iocb;
        let res = unsafe {
            libaio::io_submit(self.context, iocb_list.len() as i64, &mut iocb_list[0] as *mut *mut iocb)
        };
        if res < 0 {
            let errno = nix::Errno::from_i32(-res as i32);
            Err(nix::Error::Sys(errno))
        } else {
            self.requests.insert(slot, req);
            Ok(())
        }
    }

    pub fn get_completed_request(&mut self) -> Result<Request, nix::Error> {
        let mut event = io_event::new();
        let res = unsafe {
            libaio::io_getevents(self.context, 1, 1, &mut event as *mut io_event, ptr::null_mut())
        };
        if res < 0 {
            let errno = nix::Errno::from_i32(-res as i32);
            Err(nix::Error::Sys(errno))
        } else {
            for (idx, &mut (ref mut used, ref mut cb)) in self.iocbs.iter_mut().enumerate() {
                if event.obj == cb as *mut iocb as u64 {
                    *used = false;
                    let mut req = self.requests.remove(&idx).unwrap();
                    req.result = event.res as isize;
                    return Ok(req);
                }
            }
            panic!("Couldn't find iocb for completed request!");
        }
    }

    fn find_slot(&self) -> usize {
        for (idx, &(used, _)) in self.iocbs.iter().enumerate() {
            if !used {
                return idx;
            }
        }
        panic!("No free slot");
    }

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

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

    pub fn get_size_bytes(&self) -> u64 {
        self.size_bytes
    }

    fn fail_errno() -> nix::Error {
        nix::Error::last()
    }

    pub fn max_requests(&self) -> usize {
        self.iocbs.len()
    }

    pub fn requests_avail(&self) -> usize {
        self.iocbs.iter().filter(|r| !r.0).count()
    }

    pub fn requests_pending(&self) -> usize {
        self.iocbs.iter().filter(|r| r.0).count()
    }

    pub fn create_io_buffer(&self, sectors: usize) -> Buffer {
        let bytes = sectors * self.sector_size;
        Buffer::allocate_aligned(bytes, self.sector_size)
    }
}

impl Drop for BlockDevice {
    fn drop(&mut self) {
        unsafe {
            libaio::io_destroy(self.context);
            libc::close(self.fd)
        };
    }
}
<commit_msg>Use Rust APIs to open block device.<commit_after>use libaio::{self, aio_context_t, io_event, iocb};
use libc::{self, c_int, c_uint, c_void};
use nix;
use std::collections::BTreeMap;
use std::error::Error;
use std::ptr;
use std::slice;
use std::fs::{File, OpenOptions};
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::AsRawFd;

const MAX_EVENTS: c_int = 32;

// Meaning of block/sector sizes:
//
// physical block size - true physical block size of hardware
// sector size - minimum size of reads and writes supported by hardware (potentially smaller than
// physical block size)
// (logical) block size - a value that may actually vary across partitions, depending on whether a filesystem
// is mounted
//
// Alignment for O_DIRECT:
//
// In 2.4: buffer offset and transfer size must be multiples of logical block size.
// In 2.5: buffer offset and transfer size must be multiples of sector size.
//
// See https://lists.gt.net/linux/kernel/350775

#[derive(Debug)]
pub struct BlockDevice {
    block_size_physical: usize,
    context: aio_context_t,
    file: File,
    iocbs: Vec<(bool, iocb)>,
    requests: BTreeMap<usize, Request>,
    sector_size: usize,
    size_bytes: u64,
}

mod ioctl {
    use libc::c_uint;
    pub const BLK: c_uint = 0x12;
    pub const SSZGET: c_uint = 104;
    pub const GETSIZE64: c_uint = 114;
    pub const PBSZGET: c_uint = 123;
}

#[derive(Debug)]
pub struct Request {
    pub offset: u64,
    pub size: u64,
    pub buffer: Buffer,
    pub result: isize,
}

impl Request {
    pub fn new(offset: u64, size: u64, buffer: Buffer) -> Request {
        assert!(buffer.size as u64 >= size, "Supplied buffer is too small");
        Request {
            offset: offset,
            size: size,
            buffer: buffer,
            result: -1,
        }
    }

    pub fn get_data(&self) -> &[u8] {
        if self.result < 0 {
            &[]
        } else {
            &self.buffer.as_slice()[0..(self.result as usize)]
        }
    }

    pub fn reclaim_buffer(self) -> Buffer {
        self.buffer
    }

    pub fn is_data_zeros(&self) -> bool {
        for c in self.get_data() {
            if *c != 0 {
                return false;
            }
        }
        return true;
    }
}

#[derive(Debug)]
pub struct Buffer {
    alignment: usize,
    size: usize,
    data: *mut c_void,
}

impl Buffer {
    pub fn allocate_aligned(size: usize, alignment: usize) -> Buffer {
        let buffer = unsafe { libc::memalign(alignment, size) };
        if buffer.is_null() {
            panic!("Buffer allocation failed!");
        }
        Buffer {
            alignment: alignment,
            size: size,
            data: buffer,
        }
    }

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

    pub fn as_slice(&self) -> &[u8] {
        unsafe {
            let data = self.data as *const u8;
            slice::from_raw_parts(data, self.size)
        }
    }

    pub fn clear(&mut self) {
        unsafe {
            libc::memset(self.data, 0, self.size);
        }
    }
}

impl Drop for Buffer {
    fn drop(&mut self) {
        unsafe {
            libc::free(self.data);
        }
    }
}

impl BlockDevice {
    pub fn open(path: &str) -> Result<BlockDevice, Box<Error>> {
        let file = OpenOptions::new()
            .read(true)
            .write(false)
            .custom_flags(libc::O_DIRECT)
            .open(path)?;
        let fd = file.as_raw_fd();
        let block_size_physical = Self::query_block_size_physical(fd)?;
        let sector_size = Self::query_sector_size(fd)?;
        let size_bytes = Self::query_size_bytes(fd)?;
        let iocbs = vec![(false, iocb::new()); MAX_EVENTS as usize];
        let mut context: aio_context_t = ptr::null_mut();
        if unsafe { libaio::io_setup(iocbs.len() as i32, &mut context as *mut aio_context_t) } == -1 {
            return Err(Box::new(Self::fail_errno()));
        }

        let result = BlockDevice {
            context: context,
            block_size_physical: block_size_physical as usize,
            file: file,
            iocbs: iocbs,
            requests: BTreeMap::new(),
            size_bytes: size_bytes,
            sector_size: sector_size as usize,
        };
        Ok(result)
    }

    fn get_fd(&self) -> c_int {
        self.file.as_raw_fd()
    }

    fn query_block_size_physical(fd: c_int) -> Result<c_uint, nix::Error> {
        let mut block_size_physical: c_uint = 0;
        let ioc = ioc!(nix::sys::ioctl::NONE, ioctl::BLK, ioctl::PBSZGET, 0);
        if unsafe { libc::ioctl(fd, ioc, &mut block_size_physical as *mut c_uint) } == -1 {
            Err(Self::fail_errno())
        } else {
            Ok(block_size_physical)
        }
    }

    fn query_sector_size(fd: c_int) -> Result<c_uint, nix::Error> {
        let mut sector_size: c_uint = 0;
        let ioc = ioc!(nix::sys::ioctl::NONE, ioctl::BLK, ioctl::SSZGET, 0);
        if unsafe { libc::ioctl(fd, ioc, &mut sector_size as *mut c_uint) } == -1 {
            Err(Self::fail_errno())
        } else {
            Ok(sector_size)
        }
    }

    fn query_size_bytes(fd: c_int) -> Result<u64, nix::Error> {
        let mut size_bytes: u64 = 0;
        let ioc = ior!(ioctl::BLK, ioctl::GETSIZE64, 8);
        if unsafe { libc::ioctl(fd, ioc, &mut size_bytes as *mut u64) } == -1 {
            Err(Self::fail_errno())
        } else {
            Ok(size_bytes)
        }
    }

    pub fn submit_request(&mut self, req: Request) -> Result<(), nix::Error> {
        assert!(self.requests_avail() > 0);
        let fd = self.get_fd();
        let slot = self.find_slot();
        let iocb = &mut self.iocbs[slot];
        iocb.0 = true;
        libaio::io_prep_pread(&mut iocb.1, fd as u32, req.buffer.data, req.size, req.offset as i64);
        let iocb_ptr = &mut iocb.1 as *mut iocb;
        let mut iocb_list = [iocb_ptr];
        let res = unsafe {
            libaio::io_submit(self.context, iocb_list.len() as i64, &mut iocb_list[0] as *mut *mut iocb)
        };
        if res < 0 {
            let errno = nix::Errno::from_i32(-res as i32);
            Err(nix::Error::Sys(errno))
        } else {
            self.requests.insert(slot, req);
            Ok(())
        }
    }

    pub fn get_completed_request(&mut self) -> Result<Request, nix::Error> {
        let mut event = io_event::new();
        let res = unsafe {
            libaio::io_getevents(self.context, 1, 1, &mut event as *mut io_event, ptr::null_mut())
        };
        if res < 0 {
            let errno = nix::Errno::from_i32(-res as i32);
            Err(nix::Error::Sys(errno))
        } else {
            for (idx, &mut (ref mut used, ref mut cb)) in self.iocbs.iter_mut().enumerate() {
                if event.obj == cb as *mut iocb as u64 {
                    *used = false;
                    let mut req = self.requests.remove(&idx).unwrap();
                    req.result = event.res as isize;
                    return Ok(req);
                }
            }
            panic!("Couldn't find iocb for completed request!");
        }
    }

    fn find_slot(&self) -> usize {
        for (idx, &(used, _)) in self.iocbs.iter().enumerate() {
            if !used {
                return idx;
            }
        }
        panic!("No free slot");
    }

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

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

    pub fn get_size_bytes(&self) -> u64 {
        self.size_bytes
    }

    fn fail_errno() -> nix::Error {
        nix::Error::last()
    }

    pub fn max_requests(&self) -> usize {
        self.iocbs.len()
    }

    pub fn requests_avail(&self) -> usize {
        self.iocbs.iter().filter(|r| !r.0).count()
    }

    pub fn requests_pending(&self) -> usize {
        self.iocbs.iter().filter(|r| r.0).count()
    }

    pub fn create_io_buffer(&self, sectors: usize) -> Buffer {
        let bytes = sectors * self.sector_size;
        Buffer::allocate_aligned(bytes, self.sector_size)
    }
}

impl Drop for BlockDevice {
    fn drop(&mut self) {
        unsafe {
            libaio::io_destroy(self.context);
        };
    }
}
<|endoftext|>


<commit_before>use std::cast;
use std::mem::size_of;
use std::raw::Slice;
use std::num::Zero;

mod buffer;
mod schema;

static LEAF_MARKER: u8 = 0b111111111;
static BRANCH_MARKER: u8 = 0b0;

struct BTree<'a, K> {
	segment: u64,
	manager: &'a mut buffer::BufferManager,
	tree: LazyNode,
	next_free_page: u64,
}

impl<'a, K: TotalOrd + Zero> BTree<'a, K> {
	fn new<'b>(segment_id: u64, dummy: K, manager: &'b mut buffer::BufferManager) -> BTree<'b, K> {
		BTree {
			segment: segment_id,
			manager: manager,
			tree: LazyNode::new(1),
			next_free_page: 2,
		}
	}

	//fn locate_page

	fn insert(&mut self, key: K, value: schema::TID) {
		let node = self.tree.load(self.manager);
		// try insertion and see if the root was split
		let candidate = match node {
			Branch(mut n) => n.insert_value(self, key, value),
			Leaf(mut n) => n.insert_value(key, value),
		};
		// set new tree root if it was split
		match candidate {
			Some(new_node) => self.tree = new_node,
			None => (),
		}
	}

	fn next_page(&mut self) -> u64 {
		let n = self.next_free_page;
		self.next_free_page += 1;
		n
	}

	fn create_branch_page(&mut self) -> LazyNode {
		let next = self.next_page();
		let page_path = buffer::join_segment(self.segment, next);
		let pagelock = self.manager.fix_page(page_path).unwrap();
		let mut page = pagelock.write();
		let data = page.get_mut_data();
		data[0] = 0;
		LazyNode::new(page_path)
	}

	fn create_leaf_page(&mut self) -> LazyNode {
		let next = self.next_page();
		let page_path = buffer::join_segment(self.segment, next);
		let pagelock = self.manager.fix_page(page_path).unwrap();
		let mut page = pagelock.write();
		let data = page.get_mut_data();
		// marker to be a leaf page
		data[0] = 255;
		LazyNode::new(page_path)

	}

	fn erase(&mut self, key: K) {
	}

	fn lookup(self, key: K) -> Option<schema::TID> {
		None
	}
}

/* a placeholder for the actual page */
struct LazyNode {
	page_id: u64,
}

// TODO implement Drop to unfix page
impl LazyNode {
	fn new(page_id: u64) -> LazyNode {
		LazyNode {page_id: page_id}
	}

	/*
	 * As this is just a placeholder, return the actual node that his is
	 * representing
	 */
	fn load<'a, K: TotalOrd + Zero>(&self, manager: &mut buffer::BufferManager) -> Node<'a, K> {
		let pagelock = manager.fix_page(self.page_id).unwrap();
		let page = pagelock.read();
		LazyNode::load_node(page.get_data())
	}

	/* helper method to load a Node tepending on the page marker */
	fn load_node<'a, K: TotalOrd + Zero>(page: &[u8]) -> Node<'a, K> {
		if page[0] == 255 {
			Leaf(LeafNode::new(page))
		} else {
			Branch(BranchNode::new(page))
		}
	}
}

/* a node might either be an inner node (branch node) or a leaf node (LeafNode) */
enum Node<'a, K> {
	Branch(BranchNode<'a, K>),
	Leaf(LeafNode<'a, K>),
}

/* leaf pages consist mainly of leaf entries which are (K, TID) pairs */
struct LeafEntry<K> {
	key: K,
	tid: schema::TID,
}

/* branch pages consist mainly of branch entries which are (K, page_id) pairs */
struct BranchEntry<K> {
	key: K,
	page_id: u64,
}

struct LeafNode<'a, K> {
	capacity: uint,
	entries: &'a mut [LeafEntry<K>],
}

impl<'a, K: TotalOrd + Zero> LeafNode<'a, K> {
	fn new(page: &[u8]) -> LeafNode<'a, K> {
		// first byte is a Leaf/Branch marker
		let entry_size = size_of::<LeafEntry<K>>();
		let entry_num = (page.len() - size_of::<u8>()) / entry_size;

		let mut r: &mut[LeafEntry<K>] = unsafe {
			cast::transmute(
				Slice::<LeafEntry<K>> {
					data: page.as_ptr() as *() as *LeafEntry<K>,
					len: entry_num,
				}
			)
		};

		/* find slots that are used */
		let mut capacity = r.len();
		for i in range(0, r.len()) {
			if !r[i].key.is_zero() && !r[i].tid.is_invalid() {
				capacity -= 1;
			}
		}

		LeafNode {
			entries: r,
			capacity: capacity
		}
	}

	fn insert_value(&mut self, key: K, tid: schema::TID) -> Option<LazyNode> {
		if self.capacity == 0 {
			// TODO split
			fail!("shit");
			return None
		}

		// find place to insert
		let location = self.find_slot(&key);
		// free that spot
		self.shift_from(location);
		// and put it in
		self.entries[location].key = key;
		self.entries[location].tid = tid;

		// insertion went fine, done
		None
	}

	/* finds the location at which a key should be inserted */
	fn find_slot(&self, key: &K) -> uint {
		let mut found = 0;
		for i in range(0, self.entries.len()) {
			println!("Entry {:?}", self.entries[i]);
			if &self.entries[i].key > key {
				found = i - 1;
			}
		}
		found
	}

	/* moves all items from `index` one number back */
	fn shift_from(&mut self, index: uint) {
		// TODO
	}
}

struct BranchNode<'a, K> {
	capacity: uint,
	entries: &'a mut [BranchEntry<K>],
}

impl<'a, K: TotalOrd + Zero> BranchNode<'a, K> {
	fn new(page: &[u8]) -> BranchNode<'a, K> {
		let entry_size = size_of::<BranchEntry<K>>();
		let entry_num = (page.len() - size_of::<u8>()) / entry_size;
		let mut r: &mut [BranchEntry<K>] = unsafe {
			cast::transmute(
				Slice::<BranchEntry<K>> {
					data: page.as_ptr() as *() as *BranchEntry<K>,
					len: entry_num,
				}
			)
		};

		/* find slots that are used */
		let mut capacity = r.len();
		for i in range(0, r.len()) {
			if r[i].page_id != 0 {
				capacity -= 1;
			}
		}

		println!("BranchNode computed capacity: {}", capacity);

		BranchNode {
			entries: r,
			capacity: capacity
		}
	}

	/* might return a new branch node if this one was split */
	fn insert_value(&mut self, tree: &mut BTree<K>, key: K, value: schema::TID) -> Option<LazyNode> {
		let mut place = 0;
		// locate the place where to insert
		for i in range(0, self.entries.len()) {
			if self.entries[i].page_id == 0 {
				continue
			}
			println!("Entry i {:?}, key {:?}", self.entries[i], self.entries[i].key);
			// TODO find place
		}
		let go_to_page = self.entries[place].page_id;
		if go_to_page == 0 {
			let lazy_node = tree.create_leaf_page();
			let new_node = lazy_node.load(tree.manager);
			let split_candidate = match new_node {
				Leaf(mut n) => n.insert_value(key, value),
				Branch(_) => fail!("Did not create a leaf page"),
			};
			self.entries[place].page_id = lazy_node.page_id;
			return split_candidate
		}

		// currently not caring about splitting branch pages
		None
	}
}

#[test]
fn simple_insert() {
	let p = Path::new(".");
	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let mut bt = BTree::new(23, 42, &mut manager);
	bt.insert(42, schema::TID::new(0, 0));
	assert!(false);
}

#[test]
fn create_leaf_page() {
	let p = Path::new(".");
	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let pagelock = manager.fix_page(0).unwrap();
	let page = pagelock.read();
	let lp: LeafNode<u64> = LeafNode::new(page.get_data());
	println!("lp len: {}", lp.entries.len());
	assert!(false);
}
<commit_msg>Implemented moving slice elements<commit_after>use std::cast;
use std::mem::size_of;
use std::raw::Slice;
use std::num::Zero;

mod buffer;
mod schema;

static LEAF_MARKER: u8 = 0b111111111;
static BRANCH_MARKER: u8 = 0b0;

struct BTree<'a, K> {
	segment: u64,
	manager: &'a mut buffer::BufferManager,
	tree: LazyNode,
	next_free_page: u64,
}

impl<'a, K: TotalOrd + Zero> BTree<'a, K> {
	fn new<'b>(segment_id: u64, dummy: K, manager: &'b mut buffer::BufferManager) -> BTree<'b, K> {
		BTree {
			segment: segment_id,
			manager: manager,
			tree: LazyNode::new(1),
			next_free_page: 2,
		}
	}

	//fn locate_page

	fn insert(&mut self, key: K, value: schema::TID) {
		let node = self.tree.load(self.manager);
		// try insertion and see if the root was split
		let candidate = match node {
			Branch(mut n) => n.insert_value(self, key, value),
			Leaf(mut n) => n.insert_value(key, value),
		};
		// set new tree root if it was split
		match candidate {
			Some(new_node) => self.tree = new_node,
			None => (),
		}
	}

	fn next_page(&mut self) -> u64 {
		let n = self.next_free_page;
		self.next_free_page += 1;
		n
	}

	fn create_branch_page(&mut self) -> LazyNode {
		let next = self.next_page();
		let page_path = buffer::join_segment(self.segment, next);
		let pagelock = self.manager.fix_page(page_path).unwrap();
		let mut page = pagelock.write();
		let data = page.get_mut_data();
		data[0] = 0;
		LazyNode::new(page_path)
	}

	fn create_leaf_page(&mut self) -> LazyNode {
		let next = self.next_page();
		let page_path = buffer::join_segment(self.segment, next);
		let pagelock = self.manager.fix_page(page_path).unwrap();
		let mut page = pagelock.write();
		let data = page.get_mut_data();
		// marker to be a leaf page
		data[0] = 255;
		LazyNode::new(page_path)

	}

	fn erase(&mut self, key: K) {
	}

	fn lookup(self, key: K) -> Option<schema::TID> {
		None
	}
}

/* a placeholder for the actual page */
struct LazyNode {
	page_id: u64,
}

// TODO implement Drop to unfix page
impl LazyNode {
	fn new(page_id: u64) -> LazyNode {
		LazyNode {page_id: page_id}
	}

	/*
	 * As this is just a placeholder, return the actual node that his is
	 * representing
	 */
	fn load<'a, K: TotalOrd + Zero>(&self, manager: &mut buffer::BufferManager) -> Node<'a, K> {
		let pagelock = manager.fix_page(self.page_id).unwrap();
		let page = pagelock.read();
		LazyNode::load_node(page.get_data())
	}

	/* helper method to load a Node tepending on the page marker */
	fn load_node<'a, K: TotalOrd + Zero>(page: &[u8]) -> Node<'a, K> {
		if page[0] == 255 {
			Leaf(LeafNode::new(page))
		} else {
			Branch(BranchNode::new(page))
		}
	}
}

/* a node might either be an inner node (branch node) or a leaf node (LeafNode) */
enum Node<'a, K> {
	Branch(BranchNode<'a, K>),
	Leaf(LeafNode<'a, K>),
}

/* leaf pages consist mainly of leaf entries which are (K, TID) pairs */
struct LeafEntry<K> {
	key: K,
	tid: schema::TID,
}

/* branch pages consist mainly of branch entries which are (K, page_id) pairs */
struct BranchEntry<K> {
	key: K,
	page_id: u64,
}

struct LeafNode<'a, K> {
	capacity: uint,
	entries: &'a mut [LeafEntry<K>],
}

impl<'a, K: TotalOrd + Zero> LeafNode<'a, K> {
	fn new(page: &[u8]) -> LeafNode<'a, K> {
		// first byte is a Leaf/Branch marker
		let entry_size = size_of::<LeafEntry<K>>();
		let entry_num = (page.len() - size_of::<u8>()) / entry_size;

		let mut r: &mut[LeafEntry<K>] = unsafe {
			cast::transmute(
				Slice::<LeafEntry<K>> {
					data: page.as_ptr() as *() as *LeafEntry<K>,
					len: entry_num,
				}
			)
		};

		/* find slots that are used */
		let mut capacity = r.len();
		for i in range(0, r.len()) {
			if !r[i].key.is_zero() && !r[i].tid.is_invalid() {
				capacity -= 1;
			}
		}

		LeafNode {
			entries: r,
			capacity: capacity
		}
	}

	fn insert_value(&mut self, key: K, tid: schema::TID) -> Option<LazyNode> {
		if self.capacity == 0 {
			// TODO split
			fail!("Not implemented");
			return None
		}

		// find place to insert
		let location = self.find_slot(&key);
		// free that spot
		self.shift_from(location);
		// and put it in
		self.entries[location].key = key;
		self.entries[location].tid = tid;

		// insertion went fine, done
		None
	}

	/* finds the location at which a key should be inserted */
	fn find_slot(&self, key: &K) -> uint {
		let mut found = 0;
		for i in range(0, self.entries.len()) {
			println!("Entry {:?}", self.entries[i]);
			if &self.entries[i].key > key {
				found = i - 1;
				break;
			}
		}
		found
	}

	/* moves all items from `index` one number back */
	fn shift_from(&mut self, index: uint) {
		// actually, this rotates right by 1 starting from index
		let last_elem = self.entries.len() - 1;
		for i in range(index, last_elem) {
			self.entries.swap(i, last_elem);
		}
	}
}

struct BranchNode<'a, K> {
	capacity: uint,
	entries: &'a mut [BranchEntry<K>],
}

impl<'a, K: TotalOrd + Zero> BranchNode<'a, K> {
	fn new(page: &[u8]) -> BranchNode<'a, K> {
		let entry_size = size_of::<BranchEntry<K>>();
		let entry_num = (page.len() - size_of::<u8>()) / entry_size;
		let mut r: &mut [BranchEntry<K>] = unsafe {
			cast::transmute(
				Slice::<BranchEntry<K>> {
					data: page.as_ptr() as *() as *BranchEntry<K>,
					len: entry_num,
				}
			)
		};

		/* find slots that are used */
		let mut capacity = r.len();
		for i in range(0, r.len()) {
			if r[i].page_id != 0 {
				capacity -= 1;
			}
		}

		println!("BranchNode computed capacity: {}", capacity);

		BranchNode {
			entries: r,
			capacity: capacity
		}
	}

	/* might return a new branch node if this one was split */
	fn insert_value(&mut self, tree: &mut BTree<K>, key: K, value: schema::TID) -> Option<LazyNode> {
		let mut place = 0;
		// locate the place where to insert
		for i in range(0, self.entries.len()) {
			if self.entries[i].page_id == 0 {
				continue
			}
			println!("Entry i {:?}, key {:?}", self.entries[i], self.entries[i].key);
			// TODO find place
		}
		let go_to_page = self.entries[place].page_id;
		if go_to_page == 0 {
			let lazy_node = tree.create_leaf_page();
			let new_node = lazy_node.load(tree.manager);
			let split_candidate = match new_node {
				Leaf(mut n) => n.insert_value(key, value),
				Branch(_) => fail!("Did not create a leaf page"),
			};
			self.entries[place].page_id = lazy_node.page_id;
			return split_candidate
		}

		// currently not caring about splitting branch pages
		None
	}
}

#[test]
fn simple_insert() {
	let p = Path::new(".");
	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let mut bt = BTree::new(23, 42, &mut manager);
	bt.insert(42, schema::TID::new(0, 0));
	assert!(false);
}

#[test]
fn create_leaf_page() {
	let p = Path::new(".");
	let mut manager = buffer::BufferManager::new(1024, p.clone());
	let pagelock = manager.fix_page(0).unwrap();
	let page = pagelock.read();
	let lp: LeafNode<u64> = LeafNode::new(page.get_data());
	println!("lp len: {}", lp.entries.len());
	assert!(false);
}
<|endoftext|>