<commit_before>use super::Stream;
use crate::task::{LocalWaker, Poll};
use core::fmt;
use core::marker::PhantomData;
use core::mem;
use core::pin::Pin;

/// A custom trait object for polling streams, roughly akin to
/// `Box<dyn Stream<Item = T> + 'a>`.
///
/// This custom trait object was introduced for two reasons:
/// - Currently it is not possible to take `dyn Trait` by value and
///   `Box<dyn Trait>` is not available in no_std contexts.
pub struct LocalStreamObj<'a, T> {
    ptr: *mut (),
    poll_next_fn: unsafe fn(*mut (), &LocalWaker) -> Poll<Option<T>>,
    drop_fn: unsafe fn(*mut ()),
    _marker: PhantomData<&'a ()>,
}

impl<'a, T> Unpin for LocalStreamObj<'a, T> {}

impl<'a, T> LocalStreamObj<'a, T> {
    /// Create a `LocalStreamObj` from a custom trait object representation.
    #[inline]
    pub fn new<F: UnsafeStreamObj<'a, T> + 'a>(f: F) -> LocalStreamObj<'a, T> {
        LocalStreamObj {
            ptr: f.into_raw(),
            poll_next_fn: F::poll_next,
            drop_fn: F::drop,
            _marker: PhantomData,
        }
    }

    /// Converts the `LocalStreamObj` into a `StreamObj`
    /// To make this operation safe one has to ensure that the `UnsafeStreamObj`
    /// instance from which this `LocalStreamObj` was created actually
    /// implements `Send`.
    #[inline]
    pub unsafe fn into_stream_obj(self) -> StreamObj<'a, T> {
        StreamObj(self)
    }
}

impl<'a, T> fmt::Debug for LocalStreamObj<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("LocalStreamObj").finish()
    }
}

impl<'a, T> From<StreamObj<'a, T>> for LocalStreamObj<'a, T> {
    #[inline]
    fn from(f: StreamObj<'a, T>) -> LocalStreamObj<'a, T> {
        f.0
    }
}

impl<'a, T> Stream for LocalStreamObj<'a, T> {
    type Item = T;

    #[inline]
    fn poll_next(
        self: Pin<&mut Self>,
        lw: &LocalWaker,
    ) -> Poll<Option<T>> {
        unsafe { (self.poll_next_fn)(self.ptr, lw) }
    }
}

impl<'a, T> Drop for LocalStreamObj<'a, T> {
    fn drop(&mut self) {
        unsafe { (self.drop_fn)(self.ptr) }
    }
}

/// A custom trait object for polling streams, roughly akin to
/// `Box<dyn Stream<Item = T> + Send + 'a>`.
///
/// This custom trait object was introduced for two reasons:
/// - Currently it is not possible to take `dyn Trait` by value and
///   `Box<dyn Trait>` is not available in no_std contexts.
/// - The `Stream` trait is currently not object safe: The `Stream::poll_next`
///   method makes uses the arbitrary self types feature and traits in which
///   this feature is used are currently not object safe due to current compiler
///   limitations. (See tracking issue for arbitray self types for more
///   information #44874)
pub struct StreamObj<'a, T>(LocalStreamObj<'a, T>);

impl<'a, T> Unpin for StreamObj<'a, T> {}
unsafe impl<'a, T> Send for StreamObj<'a, T> {}

impl<'a, T> StreamObj<'a, T> {
    /// Create a `StreamObj` from a custom trait object representation.
    #[inline]
    pub fn new<F: UnsafeStreamObj<'a, T> + Send>(f: F) -> StreamObj<'a, T> {
        StreamObj(LocalStreamObj::new(f))
    }
}

impl<'a, T> fmt::Debug for StreamObj<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("StreamObj").finish()
    }
}

impl<'a, T> Stream for StreamObj<'a, T> {
    type Item = T;

    #[inline]
    fn poll_next(
        self: Pin<&mut Self>,
        lw: &LocalWaker,
    ) -> Poll<Option<T>> {
        let pinned_field = unsafe { Pin::map_unchecked_mut(self, |x| &mut x.0) };
        pinned_field.poll_next(lw)
    }
}

/// A custom implementation of a stream trait object for `StreamObj`, providing
/// a hand-rolled vtable.
///
/// This custom representation is typically used only in `no_std` contexts,
/// where the default `Box`-based implementation is not available.
///
/// The implementor must guarantee that it is safe to call `poll_next`
/// repeatedly (in a non-concurrent fashion) with the result of `into_raw` until
/// `drop` is called.
pub unsafe trait UnsafeStreamObj<'a, T>: 'a {
    /// Convert an owned instance into a (conceptually owned) void pointer.
    fn into_raw(self) -> *mut ();

    /// Poll the stream represented by the given void pointer.
    ///
    /// # Safety
    ///
    /// The trait implementor must guarantee that it is safe to repeatedly call
    /// `poll_next` with the result of `into_raw` until `drop` is called; such
    /// calls are not, however, allowed to race with each other or with calls to
    /// `drop`.
    unsafe fn poll_next(
        ptr: *mut (),
        lw: &LocalWaker,
    ) -> Poll<Option<T>>;

    /// Drops the stream represented by the given void pointer.
    ///
    /// # Safety
    ///
    /// The trait implementor must guarantee that it is safe to call this
    /// function once per `into_raw` invocation; that call cannot race with
    /// other calls to `drop` or `poll_next`.
    unsafe fn drop(ptr: *mut ());
}

unsafe impl<'a, T, F> UnsafeStreamObj<'a, T> for &'a mut F
where
    F: Stream<Item = T> + Unpin + 'a,
{
    fn into_raw(self) -> *mut () {
        self as *mut F as *mut ()
    }

    unsafe fn poll_next(
        ptr: *mut (),
        lw: &LocalWaker,
    ) -> Poll<Option<T>> {
        Pin::new_unchecked(&mut *(ptr as *mut F)).poll_next(lw)
    }

    unsafe fn drop(_ptr: *mut ()) {}
}

unsafe impl<'a, T, F> UnsafeStreamObj<'a, T> for Pin<&'a mut F>
where
    F: Stream<Item = T> + 'a,
{
    fn into_raw(self) -> *mut () {
        unsafe { Pin::get_unchecked_mut(self) as *mut F as *mut () }
    }

    unsafe fn poll_next(
        ptr: *mut (),
        lw: &LocalWaker,
    ) -> Poll<Option<T>> {
        Pin::new_unchecked(&mut *(ptr as *mut F)).poll_next(lw)
    }

    unsafe fn drop(_ptr: *mut ()) {}
}

#[cfg(feature = "std")]
mod if_std {
    use std::boxed::Box;
    use super::*;

    unsafe impl<'a, T, F> UnsafeStreamObj<'a, T> for Box<F>
        where F: Stream<Item = T> + 'a
    {
        fn into_raw(self) -> *mut () {
            Box::into_raw(self) as *mut ()
        }

        unsafe fn poll_next(ptr: *mut (), lw: &LocalWaker) -> Poll<Option<T>> {
            let ptr = ptr as *mut F;
            let pin: Pin<&mut F> = Pin::new_unchecked(&mut *ptr);
            pin.poll_next(lw)
        }

        unsafe fn drop(ptr: *mut ()) {
            drop(Box::from_raw(ptr as *mut F))
        }
    }

    unsafe impl<'a, T, F> UnsafeStreamObj<'a, T> for Pin<Box<F>>
        where F: Stream<Item = T> + 'a
    {
        fn into_raw(mut self) -> *mut () {
            let mut_ref: &mut F = unsafe { Pin::get_unchecked_mut(Pin::as_mut(&mut self)) };
            let ptr = mut_ref as *mut F as *mut ();
            mem::forget(self); // Don't drop the box
            ptr
        }

        unsafe fn poll_next(ptr: *mut (), lw: &LocalWaker) -> Poll<Option<T>> {
            let ptr = ptr as *mut F;
            let pin: Pin<&mut F> = Pin::new_unchecked(&mut *ptr);
            pin.poll_next(lw)
        }

        unsafe fn drop(ptr: *mut ()) {
            drop(Box::from_raw(ptr as *mut F))
        }
    }

    impl<'a, F: Stream<Item = ()> + Send + 'a> From<Pin<Box<F>>> for StreamObj<'a, ()> {
        fn from(boxed: Pin<Box<F>>) -> Self {
            StreamObj::new(boxed)
        }
    }

    impl<'a, F: Stream<Item = ()> + Send + 'a> From<Box<F>> for StreamObj<'a, ()> {
        fn from(boxed: Box<F>) -> Self {
            StreamObj::new(boxed)
        }
    }

    impl<'a, F: Stream<Item = ()> + 'a> From<Pin<Box<F>>> for LocalStreamObj<'a, ()> {
        fn from(boxed: Pin<Box<F>>) -> Self {
            LocalStreamObj::new(boxed)
        }
    }

    impl<'a, F: Stream<Item = ()> + 'a> From<Box<F>> for LocalStreamObj<'a, ()> {
        fn from(boxed: Box<F>) -> Self {
            LocalStreamObj::new(boxed)
        }
    }
}
<commit_msg>Fix unused_imports warning on --no-default-features build<commit_after>use super::Stream;
use crate::task::{LocalWaker, Poll};
use core::fmt;
use core::marker::PhantomData;
use core::pin::Pin;

/// A custom trait object for polling streams, roughly akin to
/// `Box<dyn Stream<Item = T> + 'a>`.
///
/// This custom trait object was introduced for two reasons:
/// - Currently it is not possible to take `dyn Trait` by value and
///   `Box<dyn Trait>` is not available in no_std contexts.
pub struct LocalStreamObj<'a, T> {
    ptr: *mut (),
    poll_next_fn: unsafe fn(*mut (), &LocalWaker) -> Poll<Option<T>>,
    drop_fn: unsafe fn(*mut ()),
    _marker: PhantomData<&'a ()>,
}

impl<'a, T> Unpin for LocalStreamObj<'a, T> {}

impl<'a, T> LocalStreamObj<'a, T> {
    /// Create a `LocalStreamObj` from a custom trait object representation.
    #[inline]
    pub fn new<F: UnsafeStreamObj<'a, T> + 'a>(f: F) -> LocalStreamObj<'a, T> {
        LocalStreamObj {
            ptr: f.into_raw(),
            poll_next_fn: F::poll_next,
            drop_fn: F::drop,
            _marker: PhantomData,
        }
    }

    /// Converts the `LocalStreamObj` into a `StreamObj`
    /// To make this operation safe one has to ensure that the `UnsafeStreamObj`
    /// instance from which this `LocalStreamObj` was created actually
    /// implements `Send`.
    #[inline]
    pub unsafe fn into_stream_obj(self) -> StreamObj<'a, T> {
        StreamObj(self)
    }
}

impl<'a, T> fmt::Debug for LocalStreamObj<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("LocalStreamObj").finish()
    }
}

impl<'a, T> From<StreamObj<'a, T>> for LocalStreamObj<'a, T> {
    #[inline]
    fn from(f: StreamObj<'a, T>) -> LocalStreamObj<'a, T> {
        f.0
    }
}

impl<'a, T> Stream for LocalStreamObj<'a, T> {
    type Item = T;

    #[inline]
    fn poll_next(
        self: Pin<&mut Self>,
        lw: &LocalWaker,
    ) -> Poll<Option<T>> {
        unsafe { (self.poll_next_fn)(self.ptr, lw) }
    }
}

impl<'a, T> Drop for LocalStreamObj<'a, T> {
    fn drop(&mut self) {
        unsafe { (self.drop_fn)(self.ptr) }
    }
}

/// A custom trait object for polling streams, roughly akin to
/// `Box<dyn Stream<Item = T> + Send + 'a>`.
///
/// This custom trait object was introduced for two reasons:
/// - Currently it is not possible to take `dyn Trait` by value and
///   `Box<dyn Trait>` is not available in no_std contexts.
/// - The `Stream` trait is currently not object safe: The `Stream::poll_next`
///   method makes uses the arbitrary self types feature and traits in which
///   this feature is used are currently not object safe due to current compiler
///   limitations. (See tracking issue for arbitray self types for more
///   information #44874)
pub struct StreamObj<'a, T>(LocalStreamObj<'a, T>);

impl<'a, T> Unpin for StreamObj<'a, T> {}
unsafe impl<'a, T> Send for StreamObj<'a, T> {}

impl<'a, T> StreamObj<'a, T> {
    /// Create a `StreamObj` from a custom trait object representation.
    #[inline]
    pub fn new<F: UnsafeStreamObj<'a, T> + Send>(f: F) -> StreamObj<'a, T> {
        StreamObj(LocalStreamObj::new(f))
    }
}

impl<'a, T> fmt::Debug for StreamObj<'a, T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("StreamObj").finish()
    }
}

impl<'a, T> Stream for StreamObj<'a, T> {
    type Item = T;

    #[inline]
    fn poll_next(
        self: Pin<&mut Self>,
        lw: &LocalWaker,
    ) -> Poll<Option<T>> {
        let pinned_field = unsafe { Pin::map_unchecked_mut(self, |x| &mut x.0) };
        pinned_field.poll_next(lw)
    }
}

/// A custom implementation of a stream trait object for `StreamObj`, providing
/// a hand-rolled vtable.
///
/// This custom representation is typically used only in `no_std` contexts,
/// where the default `Box`-based implementation is not available.
///
/// The implementor must guarantee that it is safe to call `poll_next`
/// repeatedly (in a non-concurrent fashion) with the result of `into_raw` until
/// `drop` is called.
pub unsafe trait UnsafeStreamObj<'a, T>: 'a {
    /// Convert an owned instance into a (conceptually owned) void pointer.
    fn into_raw(self) -> *mut ();

    /// Poll the stream represented by the given void pointer.
    ///
    /// # Safety
    ///
    /// The trait implementor must guarantee that it is safe to repeatedly call
    /// `poll_next` with the result of `into_raw` until `drop` is called; such
    /// calls are not, however, allowed to race with each other or with calls to
    /// `drop`.
    unsafe fn poll_next(
        ptr: *mut (),
        lw: &LocalWaker,
    ) -> Poll<Option<T>>;

    /// Drops the stream represented by the given void pointer.
    ///
    /// # Safety
    ///
    /// The trait implementor must guarantee that it is safe to call this
    /// function once per `into_raw` invocation; that call cannot race with
    /// other calls to `drop` or `poll_next`.
    unsafe fn drop(ptr: *mut ());
}

unsafe impl<'a, T, F> UnsafeStreamObj<'a, T> for &'a mut F
where
    F: Stream<Item = T> + Unpin + 'a,
{
    fn into_raw(self) -> *mut () {
        self as *mut F as *mut ()
    }

    unsafe fn poll_next(
        ptr: *mut (),
        lw: &LocalWaker,
    ) -> Poll<Option<T>> {
        Pin::new_unchecked(&mut *(ptr as *mut F)).poll_next(lw)
    }

    unsafe fn drop(_ptr: *mut ()) {}
}

unsafe impl<'a, T, F> UnsafeStreamObj<'a, T> for Pin<&'a mut F>
where
    F: Stream<Item = T> + 'a,
{
    fn into_raw(self) -> *mut () {
        unsafe { Pin::get_unchecked_mut(self) as *mut F as *mut () }
    }

    unsafe fn poll_next(
        ptr: *mut (),
        lw: &LocalWaker,
    ) -> Poll<Option<T>> {
        Pin::new_unchecked(&mut *(ptr as *mut F)).poll_next(lw)
    }

    unsafe fn drop(_ptr: *mut ()) {}
}

#[cfg(feature = "std")]
mod if_std {
    use std::boxed::Box;
    use std::mem;
    use super::*;

    unsafe impl<'a, T, F> UnsafeStreamObj<'a, T> for Box<F>
        where F: Stream<Item = T> + 'a
    {
        fn into_raw(self) -> *mut () {
            Box::into_raw(self) as *mut ()
        }

        unsafe fn poll_next(ptr: *mut (), lw: &LocalWaker) -> Poll<Option<T>> {
            let ptr = ptr as *mut F;
            let pin: Pin<&mut F> = Pin::new_unchecked(&mut *ptr);
            pin.poll_next(lw)
        }

        unsafe fn drop(ptr: *mut ()) {
            drop(Box::from_raw(ptr as *mut F))
        }
    }

    unsafe impl<'a, T, F> UnsafeStreamObj<'a, T> for Pin<Box<F>>
        where F: Stream<Item = T> + 'a
    {
        fn into_raw(mut self) -> *mut () {
            let mut_ref: &mut F = unsafe { Pin::get_unchecked_mut(Pin::as_mut(&mut self)) };
            let ptr = mut_ref as *mut F as *mut ();
            mem::forget(self); // Don't drop the box
            ptr
        }

        unsafe fn poll_next(ptr: *mut (), lw: &LocalWaker) -> Poll<Option<T>> {
            let ptr = ptr as *mut F;
            let pin: Pin<&mut F> = Pin::new_unchecked(&mut *ptr);
            pin.poll_next(lw)
        }

        unsafe fn drop(ptr: *mut ()) {
            drop(Box::from_raw(ptr as *mut F))
        }
    }

    impl<'a, F: Stream<Item = ()> + Send + 'a> From<Pin<Box<F>>> for StreamObj<'a, ()> {
        fn from(boxed: Pin<Box<F>>) -> Self {
            StreamObj::new(boxed)
        }
    }

    impl<'a, F: Stream<Item = ()> + Send + 'a> From<Box<F>> for StreamObj<'a, ()> {
        fn from(boxed: Box<F>) -> Self {
            StreamObj::new(boxed)
        }
    }

    impl<'a, F: Stream<Item = ()> + 'a> From<Pin<Box<F>>> for LocalStreamObj<'a, ()> {
        fn from(boxed: Pin<Box<F>>) -> Self {
            LocalStreamObj::new(boxed)
        }
    }

    impl<'a, F: Stream<Item = ()> + 'a> From<Box<F>> for LocalStreamObj<'a, ()> {
        fn from(boxed: Box<F>) -> Self {
            LocalStreamObj::new(boxed)
        }
    }
}
<|endoftext|>


<commit_before>//! Build configuration for Rust's release channels.
//!
//! Implements the stable/beta/nightly channel distinctions by setting various
//! flags like the `unstable_features`, calculating variables like `release` and
//! `package_vers`, and otherwise indicating to the compiler what it should
//! print out as part of its version information.

use std::path::Path;
use std::process::Command;

use build_helper::output;

use crate::Build;

// The version number
pub const CFG_RELEASE_NUM: &str = "1.35.0";

pub struct GitInfo {
    inner: Option<Info>,
}

struct Info {
    commit_date: String,
    sha: String,
    short_sha: String,
}

impl GitInfo {
    pub fn new(ignore_git: bool, dir: &Path) -> GitInfo {
        // See if this even begins to look like a git dir
        if ignore_git || !dir.join(".git").exists() {
            return GitInfo { inner: None }
        }

        // Make sure git commands work
        match Command::new("git")
            .arg("rev-parse")
            .current_dir(dir)
            .output()
        {
            Ok(ref out) if out.status.success() => {}
            _ => return GitInfo { inner: None },
        }

        // Ok, let's scrape some info
        let ver_date = output(Command::new("git").current_dir(dir)
                                      .arg("log").arg("-1")
                                      .arg("--date=short")
                                      .arg("--pretty=format:%cd"));
        let ver_hash = output(Command::new("git").current_dir(dir)
                                      .arg("rev-parse").arg("HEAD"));
        let short_ver_hash = output(Command::new("git")
                                            .current_dir(dir)
                                            .arg("rev-parse")
                                            .arg("--short=9")
                                            .arg("HEAD"));
        GitInfo {
            inner: Some(Info {
                commit_date: ver_date.trim().to_string(),
                sha: ver_hash.trim().to_string(),
                short_sha: short_ver_hash.trim().to_string(),
            }),
        }
    }

    pub fn sha(&self) -> Option<&str> {
        self.inner.as_ref().map(|s| &s.sha[..])
    }

    pub fn sha_short(&self) -> Option<&str> {
        self.inner.as_ref().map(|s| &s.short_sha[..])
    }

    pub fn commit_date(&self) -> Option<&str> {
        self.inner.as_ref().map(|s| &s.commit_date[..])
    }

    pub fn version(&self, build: &Build, num: &str) -> String {
        let mut version = build.release(num);
        if let Some(ref inner) = self.inner {
            version.push_str(" (");
            version.push_str(&inner.short_sha);
            version.push_str(" ");
            version.push_str(&inner.commit_date);
            version.push_str(")");
        }
        version
    }

    pub fn is_git(&self) -> bool {
        self.inner.is_some()
    }
}
<commit_msg>bump bootstrap; nightly => 1.36.<commit_after>//! Build configuration for Rust's release channels.
//!
//! Implements the stable/beta/nightly channel distinctions by setting various
//! flags like the `unstable_features`, calculating variables like `release` and
//! `package_vers`, and otherwise indicating to the compiler what it should
//! print out as part of its version information.

use std::path::Path;
use std::process::Command;

use build_helper::output;

use crate::Build;

// The version number
pub const CFG_RELEASE_NUM: &str = "1.36.0";

pub struct GitInfo {
    inner: Option<Info>,
}

struct Info {
    commit_date: String,
    sha: String,
    short_sha: String,
}

impl GitInfo {
    pub fn new(ignore_git: bool, dir: &Path) -> GitInfo {
        // See if this even begins to look like a git dir
        if ignore_git || !dir.join(".git").exists() {
            return GitInfo { inner: None }
        }

        // Make sure git commands work
        match Command::new("git")
            .arg("rev-parse")
            .current_dir(dir)
            .output()
        {
            Ok(ref out) if out.status.success() => {}
            _ => return GitInfo { inner: None },
        }

        // Ok, let's scrape some info
        let ver_date = output(Command::new("git").current_dir(dir)
                                      .arg("log").arg("-1")
                                      .arg("--date=short")
                                      .arg("--pretty=format:%cd"));
        let ver_hash = output(Command::new("git").current_dir(dir)
                                      .arg("rev-parse").arg("HEAD"));
        let short_ver_hash = output(Command::new("git")
                                            .current_dir(dir)
                                            .arg("rev-parse")
                                            .arg("--short=9")
                                            .arg("HEAD"));
        GitInfo {
            inner: Some(Info {
                commit_date: ver_date.trim().to_string(),
                sha: ver_hash.trim().to_string(),
                short_sha: short_ver_hash.trim().to_string(),
            }),
        }
    }

    pub fn sha(&self) -> Option<&str> {
        self.inner.as_ref().map(|s| &s.sha[..])
    }

    pub fn sha_short(&self) -> Option<&str> {
        self.inner.as_ref().map(|s| &s.short_sha[..])
    }

    pub fn commit_date(&self) -> Option<&str> {
        self.inner.as_ref().map(|s| &s.commit_date[..])
    }

    pub fn version(&self, build: &Build, num: &str) -> String {
        let mut version = build.release(num);
        if let Some(ref inner) = self.inner {
            version.push_str(" (");
            version.push_str(&inner.short_sha);
            version.push_str(" ");
            version.push_str(&inner.commit_date);
            version.push_str(")");
        }
        version
    }

    pub fn is_git(&self) -> bool {
        self.inner.is_some()
    }
}
<|endoftext|>


<commit_before>use super::stack_with_trace::Op;

pub enum Node {
    Add(Box<Node>, Box<Node>),
    ReadLocal(u8),
    LitI8(i8),
}

pub enum Stmt {
    BranchLt(Node, Node, i8 /* bc offset */, bool /* taken */),
}

pub fn trace_to_node(ops: &[*const u8]) -> Node {
    let mut i = 0;
    let mut stack = vec![];
    let mut stmts = vec![];
    let res;

    fn next_op(ops: &[*const u8], i: &mut usize) -> Op {
        let op = Op::from(unsafe { *ops[*i] });
        *i += 1;
        op
    }

    fn next_oparg(ops: &[*const u8], i: &mut usize) -> u8 {
        let oparg = unsafe { *ops[*i] };
        *i += 1;
        oparg
    }

    fn figure_out_next_op_ptr(ops: &[*const u8], i: usize) -> *const u8 {
        if i >= ops.len() {
            ops[0]
        } else {
            ops[i]
        }
    }

    loop {
        match next_op(ops, &mut i) {
            Op::LoadI8 => {
                stack.push(Node::LitI8(next_oparg(ops, &mut i) as i8));
                i += 2;
            }
            Op::Ret => {
                res = stack.pop().unwrap();
                let nlocals = next_oparg(ops, &mut i) as usize;
                assert_eq!(stack.len(), nlocals);
                break;
            }
            Op::Add => {
                let r = stack.pop().unwrap();
                let l = stack.pop().unwrap();
                stack.push(Node::Add(box r, box l));
            }
            Op::BranchLt => {
                let op_ptr = ops[i - 1];
                let pc_incr = next_oparg(ops, &mut i) as isize;
                let r = stack.pop().unwrap();
                let l = stack.pop().unwrap();
                let branch_target = figure_out_next_op_ptr(ops, i);
                let taken = unsafe {
                    if branch_target == op_ptr.offset(2 + pc_incr) {
                        true
                    } else if branch_target == op_ptr.offset(2) {
                        false
                    } else {
                        panic!("invalid branch target");
                    }
                };
                stmts.push(Stmt::BranchLt(r, l, pc_incr as i8, taken));
            }
            _ => {
                panic!();
            }
        }
    }
    res
}
<commit_msg>Thinking about trace analysis...<commit_after>use super::stack_with_trace::Op;

#[derive(Eq, PartialEq, Debug)]
pub enum Node {
    Add(Box<Node>, Box<Node>),
    ReadLocal(u8),
    LitI8(i8),
}

#[derive(Eq, PartialEq, Debug)]
pub enum Stmt {
    BranchLt(Node, Node, i8 /* bc offset */, bool /* taken */),
    Ret(Node, u8 /* nlocals */),
    Seq(Vec<Stmt>),
}

pub fn trace_to_node(ops: &[*const u8]) -> Stmt {
    let mut i = 0;
    let mut stack = vec![];
    let mut stmts = vec![];

    fn next_op(ops: &[*const u8], i: &mut usize) -> Op {
        let op = Op::from(unsafe { *ops[*i] });
        *i += 1;
        op
    }

    fn next_oparg(ops: &[*const u8], i: &mut usize) -> u8 {
        let oparg = unsafe { *ops[*i] };
        *i += 1;
        oparg
    }

    fn figure_out_next_op_ptr(ops: &[*const u8], i: usize) -> *const u8 {
        if i >= ops.len() {
            ops[0]
        } else {
            ops[i]
        }
    }

    while i < ops.len() {
        match next_op(ops, &mut i) {
            Op::LoadI8 => {
                stack.push(Node::LitI8(next_oparg(ops, &mut i) as i8));
                i += 2;
            }
            Op::Ret => {
                // Call / Ret should be handled in two flavors:
                // - A ret paired with a call can be inlined
                // - An unpaired call or ret means recursive activation
                //   and should be treated differently.
                let top = stack.pop().unwrap();
                let nlocals = next_oparg(ops, &mut i) as usize;
                for _ in 0..nlocals {
                    stack.pop();
                }
                stmts.push(Stmt::Ret(top, nlocals as u8));
            }
            Op::Add => {
                let r = stack.pop().unwrap();
                let l = stack.pop().unwrap();
                stack.push(Node::Add(box r, box l));
            }
            Op::BranchLt => {
                let op_ptr = ops[i - 1];
                let pc_incr = next_oparg(ops, &mut i) as isize;
                let r = stack.pop().unwrap();
                let l = stack.pop().unwrap();
                let branch_target = figure_out_next_op_ptr(ops, i);
                let taken = unsafe {
                    if branch_target == op_ptr.offset(2 + pc_incr) {
                        true
                    } else if branch_target == op_ptr.offset(2) {
                        false
                    } else {
                        panic!("invalid branch target");
                    }
                };
                stmts.push(Stmt::BranchLt(r, l, pc_incr as i8, taken));
            }
            _ => {
                panic!();
            }
        }
    }
    Stmt::Seq(stmts)
}
<|endoftext|>


<commit_before>/*
Copyright (c) 2020, R. Ou <rqou@robertou.com> and contributors
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

extern crate proc_macro;
use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::*;
use syn::*;
use syn::parse::*;
use syn::punctuated::*;

mod kw {
    syn::custom_keyword!(default);
    syn::custom_keyword!(errtype);
    syn::custom_keyword!(bitnames);
    syn::custom_keyword!(variant);
}

// Args for the #[bitpattern] macro

// Default return value if no match
#[derive(Debug)]
struct BitPatternDefaultExpr {
    _ident: Ident,
    _eq: syn::token::Eq,
    expr: Expr,
}

impl Parse for BitPatternDefaultExpr {
    fn parse(input: ParseStream) -> syn::parse::Result<Self> {
        Ok(BitPatternDefaultExpr {
            _ident: input.parse()?,
            _eq: input.parse()?,
            expr: input.parse()?,
        })
    }
}

// Error return type for Result
#[derive(Debug)]
struct BitPatternErrType {
    _ident: Ident,
    _eq: syn::token::Eq,
    ty: Type,
}

impl Parse for BitPatternErrType {
    fn parse(input: ParseStream) -> syn::parse::Result<Self> {
        Ok(BitPatternErrType {
            _ident: input.parse()?,
            _eq: input.parse()?,
            ty: input.parse()?,
        })
    }
}

// Custom names for each bit
#[derive(Debug)]
struct BitPatternBitNames {
    _ident: Ident,
    _eq: syn::token::Eq,
    names: LitStr,
}

impl Parse for BitPatternBitNames {
    fn parse(input: ParseStream) -> syn::parse::Result<Self> {
        Ok(BitPatternBitNames {
            _ident: input.parse()?,
            _eq: input.parse()?,
            names: input.parse()?,
        })
    }
}

// Different encoding variants
#[derive(Debug, PartialEq)]
struct BitPatternEncodingVariant {
    _ident: Ident,
    _eq: syn::token::Eq,
    ty: Type,
}

impl Parse for BitPatternEncodingVariant {
    fn parse(input: ParseStream) -> syn::parse::Result<Self> {
        Ok(BitPatternEncodingVariant {
            _ident: input.parse()?,
            _eq: input.parse()?,
            ty: input.parse()?,
        })
    }
}

#[derive(Debug)]
enum BitPatternSetting {
    DefaultExpr(BitPatternDefaultExpr),
    ErrType(BitPatternErrType),
    BitNames(BitPatternBitNames),
    Variant(BitPatternEncodingVariant),
}

impl Parse for BitPatternSetting {
    fn parse(input: ParseStream) -> syn::parse::Result<Self> {
        let lookahead = input.lookahead1();
        if lookahead.peek(kw::default) {
            input.parse().map(BitPatternSetting::DefaultExpr)
        } else if lookahead.peek(kw::errtype) {
            input.parse().map(BitPatternSetting::ErrType)
        } else if lookahead.peek(kw::bitnames) {
            input.parse().map(BitPatternSetting::BitNames)
        } else if lookahead.peek(kw::variant) {
            input.parse().map(BitPatternSetting::Variant)
        } else {
            Err(lookahead.error())
        }
    }
}

#[derive(Debug)]
struct BitPatternSettings(Punctuated<BitPatternSetting, token::Comma>);

impl Parse for BitPatternSettings {
    fn parse(input: ParseStream) -> syn::parse::Result<Self> {
        Ok(BitPatternSettings(input.parse_terminated(BitPatternSetting::parse)?))
    }
}

// Args for the #[bits] attribute macro
#[derive(Debug)]
enum BitValueSetting {
    BitValueString(LitStr),
    Variant(BitPatternEncodingVariant),
}

impl Parse for BitValueSetting {
    fn parse(input: ParseStream) -> syn::parse::Result<Self> {
        let lookahead = input.lookahead1();
        if lookahead.peek(LitStr) {
            input.parse().map(BitValueSetting::BitValueString)
        } else if lookahead.peek(kw::variant) {
            input.parse().map(BitValueSetting::Variant)
        } else {
            Err(lookahead.error())
        }
    }
}

type BitValueSettings = Punctuated<BitValueSetting, token::Comma>;

pub fn bitpattern(args: TokenStream, input: TokenStream) -> TokenStream {
    let args = parse_macro_input!(args as BitPatternSettings);
    let mut input = parse_macro_input!(input as ItemEnum);

    let mut default_expr = None;
    let mut errtype = None;
    let mut bitnames_str = None;
    let mut encode_variant = None;

    // process args
    for arg in args.0 {
        match arg {
            BitPatternSetting::DefaultExpr(bpdx) => {
                default_expr = Some(bpdx.expr);
            },
            BitPatternSetting::ErrType(bpet) => {
                errtype = Some(bpet.ty);
            },
            BitPatternSetting::BitNames(bpbn) => {
                bitnames_str = Some(bpbn.names.value());
            },
            BitPatternSetting::Variant(bpev) => {
                encode_variant = Some(bpev.ty);
            },
        }
    }

    // Ignore enums with no variants
    if input.variants.len() == 0 {
        println!("Warning: BitPattern used on enum with no variants");
        return TokenStream::from(quote!{#input});
    }

    let enum_id = input.ident.clone();

    // loop over the variants and grab the necessary data
    let mut var_data = Vec::new();
    for var in &mut input.variants {
        let var_id = var.ident.clone();

        if var.fields != Fields::Unit {
            panic!("Variant {} must be a unit variant", var_id.to_string());
        }

        // Find the #[bits] attribute and docstrings
        let mut bits_attrib = None;
        let mut bits_docs = String::new();
        for (i, attr) in var.attrs.iter().enumerate() {
            if attr.path.is_ident("bits") {
                let parser = BitValueSettings::parse_separated_nonempty;
                let bits_args = attr.parse_args_with(parser);
                if let Err(e) = bits_args {
                    return e.to_compile_error().into();
                }
                let bits_args = bits_args.unwrap();

                // Possibly filter by bit encoding variant
                let mut maybe_str = None;
                let mut maybe_var_ty = None;
                for bits_arg in bits_args {
                    match bits_arg {
                        BitValueSetting::BitValueString(s) => {
                            if maybe_str.is_some() {
                                panic!("Only one string allowed in #[bits] on {}", var_id.to_string());
                            }
                            maybe_str = Some(s.value());
                        },
                        BitValueSetting::Variant(v) => {
                            if maybe_var_ty.is_some() {
                                panic!("Only one variant= allowed in #[bits] on {}", var_id.to_string());
                            }
                            maybe_var_ty = Some(v.ty);
                        },
                    }
                }

                if maybe_str.is_none() {
                    panic!("No string in #[bits] on {}", var_id.to_string());
                }

                if maybe_var_ty.is_none() && encode_variant.is_none() ||
                    (maybe_var_ty.is_some() && encode_variant.is_some() &&
                        maybe_var_ty.as_ref().unwrap() == encode_variant.as_ref().unwrap()) {
                    if bits_attrib.is_some() {
                        panic!("Only one #[bits] attribute allowed on {}", var_id.to_string());
                    }

                    bits_attrib = Some((i, maybe_str.unwrap()));
                }
            }

            if attr.path.is_ident("doc") {
                let doc_meta = attr.parse_meta();
                if let Err(e) = doc_meta {
                    return e.to_compile_error().into();
                }
                let doc_meta = doc_meta.unwrap();

                if let Meta::NameValue(nv) = doc_meta {
                    if let Lit::Str(s) = nv.lit {
                        if bits_docs.len() != 0 {
                            bits_docs.push_str(" ");
                        }
                        bits_docs.push_str(s.value().trim());
                    }
                }
            }
        }
        if bits_attrib.is_none() {
            panic!("Enum variant {} must have a #[bits] attribute", var_id.to_string());
        }

        let (bits_attrib_i, bits_string) = bits_attrib.unwrap();
        var.attrs.remove(bits_attrib_i);

        var_data.push((var_id, bits_string, bits_docs));
    }

    // Gathered all variants and their settings, do some checks to make sure
    // things are valid
    let num_bits = var_data[0].1.len();
    for (_, bits_string, _) in &var_data {
        if bits_string.len() != num_bits {
            panic!("All bits need to be the same length");
        }

        for c in bits_string.chars() {
            if c != '0'  && c != '1' && c != 'x' && c != 'X' {
                panic!("Illegal character in bits attribute");
            }
        }
    }

    // Can start generating code now
    let encode_variant = if let Some(x) = encode_variant {
        x.into_token_stream()
    } else {
        quote!(())
    };

    let bit_names: Vec<LitStr>;
    if let Some(bitnames_str) = bitnames_str {
        let bitnames_vec = bitnames_str.split_whitespace().collect::<Vec<_>>();
        if bitnames_vec.len() == 1 {
            // No spaces; each char is a bit name
            let bit_names_chars = bitnames_vec[0].chars().collect::<Vec<_>>();
            if bit_names_chars.len() != num_bits {
                panic!("Mismatched number of names in bitnames");
            }
            bit_names = bit_names_chars.iter().map(|x| LitStr::new(&x.to_string(), Span::call_site())).collect();
        } else {
            // Has spaces; each word is a bit name
            if bitnames_vec.len() != num_bits {
                panic!("Mismatched number of names in bitnames");
            }
            bit_names = bitnames_vec.iter().map(|x| LitStr::new(x, Span::call_site())).collect();
        }
    } else {
        // Each bit is just named by the bit index
        bit_names = (0..num_bits).map(|x| LitStr::new(&x.to_string(), Span::call_site())).collect();

    }
    let bit_names2 = bit_names.clone();
    let bit_nums = 0..num_bits;

    // For encode function
    let encode_values = var_data.iter().map(|x|
        x.1.chars().map(|c|
            match c {
                '0'|'x' => quote! {false},
                '1'|'X' => quote! {true},
                _ => unreachable!(),
            }
        ).collect::<Vec<_>>()
    );
    let encode_var_id = var_data.iter().map(|x| x.0.clone());

    // For decode function
    let decode_values = var_data.iter().map(|x|
        x.1.chars().map(|c|
            match c {
                '0' => quote! {false},
                '1' => quote! {true},
                'x'|'X' => quote! {_},
                _ => unreachable!(),
            }
        ).collect::<Vec<_>>()
    );
    let decode_var_id = var_data.iter().map(|x| x.0.clone());

    let default_expr = default_expr.iter();
    let default_expr = if errtype.is_none() {
        quote!{
            #(,_ => Ok(#default_expr))*
        }
    } else {
        quote!{
            #(,_ => Err(#default_expr))*
        }
    };

    let errtype = if errtype.is_none() {
        quote!{()}
    } else {
        quote!{#errtype}
    };

    // For docs
    let num_variants = input.variants.len();
    let variant_names = var_data.iter().map(|x| LitStr::new(&x.0.to_string(), Span::call_site()));
    let variant_docs = var_data.iter().map(|x| LitStr::new(&x.2.to_string(), Span::call_site()));
    let variant_bits = var_data.iter().map(|x| LitStr::new(&x.1.to_string(), Span::call_site()));

    let output = quote!{
        #input

        impl ::bittwiddler::BitPattern<#encode_variant> for #enum_id {
            type BitsArrType = [bool; #num_bits];
            const BITS_COUNT: usize = #num_bits;

            type ErrType = #errtype;

            const VARIANT_COUNT: usize = #num_variants;

            fn encode(&self) -> Self::BitsArrType {
                match self {
                    #(Self::#encode_var_id => [#(#encode_values),*]),*
                }
            }

            fn decode(bits: Self::BitsArrType) -> Result<Self, Self::ErrType> {
                match bits {
                    #([#(#decode_values),*] => Ok(Self::#decode_var_id)),*
                    #default_expr
                }
            }

            fn _pos_to_name(pos: usize) -> &'static str {
                [#(#bit_names),*][pos]
            }

            fn _name_to_pos(name: &'static str) -> usize {
                match name {
                    #(#bit_names2 => #bit_nums),*
                    ,_ => unreachable!()
                }
            }

            fn variantname(var: usize) -> &'static str {
                [#(#variant_names),*][var]
            }

            fn variantdesc(var: usize) -> &'static str {
                [#(#variant_docs),*][var]
            }

            fn variantbits(var: usize) -> &'static str {
                [#(#variant_bits),*][var]
            }
        }
    };

    TokenStream::from(output)
}
<commit_msg>bittwiddler: Clean up bitpattern args types<commit_after>/*
Copyright (c) 2020, R. Ou <rqou@robertou.com> and contributors
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
   this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
   this list of conditions and the following disclaimer in the documentation
   and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

extern crate proc_macro;
use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::*;
use syn::*;
use syn::parse::*;
use syn::punctuated::*;

mod kw {
    syn::custom_keyword!(default);
    syn::custom_keyword!(errtype);
    syn::custom_keyword!(bitnames);
    syn::custom_keyword!(variant);
}

#[derive(Debug)]
struct ArgWithExpr {
    _ident: Ident,
    _eq: syn::token::Eq,
    expr: Expr,
}

impl Parse for ArgWithExpr {
    fn parse(input: ParseStream) -> syn::parse::Result<Self> {
        Ok(ArgWithExpr {
            _ident: input.parse()?,
            _eq: input.parse()?,
            expr: input.parse()?,
        })
    }
}

#[derive(Debug)]
struct ArgWithType {
    _ident: Ident,
    _eq: syn::token::Eq,
    ty: Type,
}

impl Parse for ArgWithType {
    fn parse(input: ParseStream) -> syn::parse::Result<Self> {
        Ok(ArgWithType {
            _ident: input.parse()?,
            _eq: input.parse()?,
            ty: input.parse()?,
        })
    }
}

#[derive(Debug)]
struct ArgWithLitStr {
    _ident: Ident,
    _eq: syn::token::Eq,
    names: LitStr,
}

impl Parse for ArgWithLitStr {
    fn parse(input: ParseStream) -> syn::parse::Result<Self> {
        Ok(ArgWithLitStr {
            _ident: input.parse()?,
            _eq: input.parse()?,
            names: input.parse()?,
        })
    }
}

#[derive(Debug)]
enum BitPatternSetting {
    DefaultExpr(ArgWithExpr),
    ErrType(ArgWithType),
    BitNames(ArgWithLitStr),
    Variant(ArgWithType),
}

impl Parse for BitPatternSetting {
    fn parse(input: ParseStream) -> syn::parse::Result<Self> {
        let lookahead = input.lookahead1();
        if lookahead.peek(kw::default) {
            input.parse().map(BitPatternSetting::DefaultExpr)
        } else if lookahead.peek(kw::errtype) {
            input.parse().map(BitPatternSetting::ErrType)
        } else if lookahead.peek(kw::bitnames) {
            input.parse().map(BitPatternSetting::BitNames)
        } else if lookahead.peek(kw::variant) {
            input.parse().map(BitPatternSetting::Variant)
        } else {
            Err(lookahead.error())
        }
    }
}

#[derive(Debug)]
struct BitPatternSettings(Punctuated<BitPatternSetting, token::Comma>);

impl Parse for BitPatternSettings {
    fn parse(input: ParseStream) -> syn::parse::Result<Self> {
        Ok(BitPatternSettings(input.parse_terminated(BitPatternSetting::parse)?))
    }
}

// Args for the #[bits] attribute macro
#[derive(Debug)]
enum BitValueSetting {
    BitValueString(LitStr),
    Variant(ArgWithType),
}

impl Parse for BitValueSetting {
    fn parse(input: ParseStream) -> syn::parse::Result<Self> {
        let lookahead = input.lookahead1();
        if lookahead.peek(LitStr) {
            input.parse().map(BitValueSetting::BitValueString)
        } else if lookahead.peek(kw::variant) {
            input.parse().map(BitValueSetting::Variant)
        } else {
            Err(lookahead.error())
        }
    }
}

type BitValueSettings = Punctuated<BitValueSetting, token::Comma>;

pub fn bitpattern(args: TokenStream, input: TokenStream) -> TokenStream {
    let args = parse_macro_input!(args as BitPatternSettings);
    let mut input = parse_macro_input!(input as ItemEnum);

    let mut default_expr = None;
    let mut errtype = None;
    let mut bitnames_str = None;
    let mut encode_variant = None;

    // process args
    for arg in args.0 {
        match arg {
            BitPatternSetting::DefaultExpr(bpdx) => {
                default_expr = Some(bpdx.expr);
            },
            BitPatternSetting::ErrType(bpet) => {
                errtype = Some(bpet.ty);
            },
            BitPatternSetting::BitNames(bpbn) => {
                bitnames_str = Some(bpbn.names.value());
            },
            BitPatternSetting::Variant(bpev) => {
                encode_variant = Some(bpev.ty);
            },
        }
    }

    // Ignore enums with no variants
    if input.variants.len() == 0 {
        println!("Warning: BitPattern used on enum with no variants");
        return TokenStream::from(quote!{#input});
    }

    let enum_id = input.ident.clone();

    // loop over the variants and grab the necessary data
    let mut var_data = Vec::new();
    for var in &mut input.variants {
        let var_id = var.ident.clone();

        if var.fields != Fields::Unit {
            panic!("Variant {} must be a unit variant", var_id.to_string());
        }

        // Find the #[bits] attribute and docstrings
        let mut bits_attrib = None;
        let mut bits_docs = String::new();
        for (i, attr) in var.attrs.iter().enumerate() {
            if attr.path.is_ident("bits") {
                let parser = BitValueSettings::parse_separated_nonempty;
                let bits_args = attr.parse_args_with(parser);
                if let Err(e) = bits_args {
                    return e.to_compile_error().into();
                }
                let bits_args = bits_args.unwrap();

                // Possibly filter by bit encoding variant
                let mut maybe_str = None;
                let mut maybe_var_ty = None;
                for bits_arg in bits_args {
                    match bits_arg {
                        BitValueSetting::BitValueString(s) => {
                            if maybe_str.is_some() {
                                panic!("Only one string allowed in #[bits] on {}", var_id.to_string());
                            }
                            maybe_str = Some(s.value());
                        },
                        BitValueSetting::Variant(v) => {
                            if maybe_var_ty.is_some() {
                                panic!("Only one variant= allowed in #[bits] on {}", var_id.to_string());
                            }
                            maybe_var_ty = Some(v.ty);
                        },
                    }
                }

                if maybe_str.is_none() {
                    panic!("No string in #[bits] on {}", var_id.to_string());
                }

                if maybe_var_ty.is_none() && encode_variant.is_none() ||
                    (maybe_var_ty.is_some() && encode_variant.is_some() &&
                        maybe_var_ty.as_ref().unwrap() == encode_variant.as_ref().unwrap()) {
                    if bits_attrib.is_some() {
                        panic!("Only one #[bits] attribute allowed on {}", var_id.to_string());
                    }

                    bits_attrib = Some((i, maybe_str.unwrap()));
                }
            }

            if attr.path.is_ident("doc") {
                let doc_meta = attr.parse_meta();
                if let Err(e) = doc_meta {
                    return e.to_compile_error().into();
                }
                let doc_meta = doc_meta.unwrap();

                if let Meta::NameValue(nv) = doc_meta {
                    if let Lit::Str(s) = nv.lit {
                        if bits_docs.len() != 0 {
                            bits_docs.push_str(" ");
                        }
                        bits_docs.push_str(s.value().trim());
                    }
                }
            }
        }
        if bits_attrib.is_none() {
            panic!("Enum variant {} must have a #[bits] attribute", var_id.to_string());
        }

        let (bits_attrib_i, bits_string) = bits_attrib.unwrap();
        var.attrs.remove(bits_attrib_i);

        var_data.push((var_id, bits_string, bits_docs));
    }

    // Gathered all variants and their settings, do some checks to make sure
    // things are valid
    let num_bits = var_data[0].1.len();
    for (_, bits_string, _) in &var_data {
        if bits_string.len() != num_bits {
            panic!("All bits need to be the same length");
        }

        for c in bits_string.chars() {
            if c != '0'  && c != '1' && c != 'x' && c != 'X' {
                panic!("Illegal character in bits attribute");
            }
        }
    }

    // Can start generating code now
    let encode_variant = if let Some(x) = encode_variant {
        x.into_token_stream()
    } else {
        quote!(())
    };

    let bit_names: Vec<LitStr>;
    if let Some(bitnames_str) = bitnames_str {
        let bitnames_vec = bitnames_str.split_whitespace().collect::<Vec<_>>();
        if bitnames_vec.len() == 1 {
            // No spaces; each char is a bit name
            let bit_names_chars = bitnames_vec[0].chars().collect::<Vec<_>>();
            if bit_names_chars.len() != num_bits {
                panic!("Mismatched number of names in bitnames");
            }
            bit_names = bit_names_chars.iter().map(|x| LitStr::new(&x.to_string(), Span::call_site())).collect();
        } else {
            // Has spaces; each word is a bit name
            if bitnames_vec.len() != num_bits {
                panic!("Mismatched number of names in bitnames");
            }
            bit_names = bitnames_vec.iter().map(|x| LitStr::new(x, Span::call_site())).collect();
        }
    } else {
        // Each bit is just named by the bit index
        bit_names = (0..num_bits).map(|x| LitStr::new(&x.to_string(), Span::call_site())).collect();

    }
    let bit_names2 = bit_names.clone();
    let bit_nums = 0..num_bits;

    // For encode function
    let encode_values = var_data.iter().map(|x|
        x.1.chars().map(|c|
            match c {
                '0'|'x' => quote! {false},
                '1'|'X' => quote! {true},
                _ => unreachable!(),
            }
        ).collect::<Vec<_>>()
    );
    let encode_var_id = var_data.iter().map(|x| x.0.clone());

    // For decode function
    let decode_values = var_data.iter().map(|x|
        x.1.chars().map(|c|
            match c {
                '0' => quote! {false},
                '1' => quote! {true},
                'x'|'X' => quote! {_},
                _ => unreachable!(),
            }
        ).collect::<Vec<_>>()
    );
    let decode_var_id = var_data.iter().map(|x| x.0.clone());

    let default_expr = default_expr.iter();
    let default_expr = if errtype.is_none() {
        quote!{
            #(,_ => Ok(#default_expr))*
        }
    } else {
        quote!{
            #(,_ => Err(#default_expr))*
        }
    };

    let errtype = if errtype.is_none() {
        quote!{()}
    } else {
        quote!{#errtype}
    };

    // For docs
    let num_variants = input.variants.len();
    let variant_names = var_data.iter().map(|x| LitStr::new(&x.0.to_string(), Span::call_site()));
    let variant_docs = var_data.iter().map(|x| LitStr::new(&x.2.to_string(), Span::call_site()));
    let variant_bits = var_data.iter().map(|x| LitStr::new(&x.1.to_string(), Span::call_site()));

    let output = quote!{
        #input

        impl ::bittwiddler::BitPattern<#encode_variant> for #enum_id {
            type BitsArrType = [bool; #num_bits];
            const BITS_COUNT: usize = #num_bits;

            type ErrType = #errtype;

            const VARIANT_COUNT: usize = #num_variants;

            fn encode(&self) -> Self::BitsArrType {
                match self {
                    #(Self::#encode_var_id => [#(#encode_values),*]),*
                }
            }

            fn decode(bits: Self::BitsArrType) -> Result<Self, Self::ErrType> {
                match bits {
                    #([#(#decode_values),*] => Ok(Self::#decode_var_id)),*
                    #default_expr
                }
            }

            fn _pos_to_name(pos: usize) -> &'static str {
                [#(#bit_names),*][pos]
            }

            fn _name_to_pos(name: &'static str) -> usize {
                match name {
                    #(#bit_names2 => #bit_nums),*
                    ,_ => unreachable!()
                }
            }

            fn variantname(var: usize) -> &'static str {
                [#(#variant_names),*][var]
            }

            fn variantdesc(var: usize) -> &'static str {
                [#(#variant_docs),*][var]
            }

            fn variantbits(var: usize) -> &'static str {
                [#(#variant_bits),*][var]
            }
        }
    };

    TokenStream::from(output)
}
<|endoftext|>


<commit_before>// #![cfg_attr(docsrs, feature(doc_cfg))]
#![ cfg_attr( feature = "nightly", feature( type_name_of_val ) ) ]
// #![ feature( type_name_of_val ) ]
// #![ feature( trace_macros ) ]
// #![ feature( concat_idents ) ]

mod implements_test
{
  use typing_tools as TheModule;
  include!( "./common/implements_test.rs" );
}
mod is_slice_test
{
  use typing_tools as TheModule;
  include!( "./common/is_slice_test.rs" );
}

// #![ cfg( feature = "nightly" ) ]
mod inspect_type_test
{
  #[ allow( unused_imports ) ]
  use typing_tools as TheModule;
  include!( "./common/inspect_type_test.rs" );
}
<commit_msg>add rust module : wautomata<commit_after>// #![cfg_attr(docsrs, feature(doc_cfg))]
#![ cfg_attr( feature = "nightly", feature( type_name_of_val ) ) ]
// #![ feature( type_name_of_val ) ]
// #![ feature( trace_macros ) ]
// #![ feature( concat_idents ) ]

mod implements_test
{
  use typing_tools as TheModule;
  include!( "./common/implements_test.rs" );
}
mod is_slice_test
{
  use typing_tools as TheModule;
  include!( "./common/is_slice_test.rs" );
}

// #![ cfg( feature = "nightly" ) ]
mod inspect_type_test
{
  #[ allow( unused_imports ) ]
  use typing_tools as TheModule;
  include!( "./common/inspect_type_test.rs" );
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::io;
use std::rc::{Rc, Weak};
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::time::Instant;
use log::LogLevel;
use mio::{Event, PollOpt, Ready, Token};
use mio::net::UdpSocket;

use super::client::Client;
use super::connection::{self, Connection, ConnectionId};
use super::datagram_buffer::DatagramBuffer;
use super::ipv4_packet::{IPv4Packet, MAX_PACKET_LENGTH};
use super::packetizer::Packetizer;
use super::selector::Selector;

const TAG: &'static str = "UDPConnection";

pub const IDLE_TIMEOUT_SECONDS: u64 = 2 * 60;

pub struct UDPConnection {
    id: ConnectionId,
    client: Weak<RefCell<Client>>,
    socket: UdpSocket,
    token: Token,
    client_to_network: DatagramBuffer,
    network_to_client: Packetizer,
    pending_packet_for_client: Option<Box<[u8]>>, // used when the client buffer is full, should be rare
    closed: bool,
    idle_since: Instant,
}

impl UDPConnection {
    pub fn new(selector: &mut Selector, id: ConnectionId, client: Weak<RefCell<Client>>, reference_packet: &IPv4Packet) -> io::Result<Rc<RefCell<Self>>> {
        let socket = UDPConnection::create_socket(&id)?;
        let raw: &[u8] = reference_packet.raw();
        let ipv4_header = reference_packet.ipv4_header().clone();
        let transport_header = reference_packet.transport_header().as_ref().unwrap().clone();
        let rc = Rc::new(RefCell::new(Self {
            id: id,
            client: client,
            socket: socket,
            token: Token(0), // default value, will be set afterwards
            client_to_network: DatagramBuffer::new(4 * MAX_PACKET_LENGTH),
            network_to_client: Packetizer::new(raw, ipv4_header, transport_header),
            pending_packet_for_client: None,
            closed: false,
            idle_since: Instant::now(),
        }));

        {
            let rc_clone = rc.clone();
            let handler = move |selector: &mut Selector, ready| {
                let mut self_ref = rc_clone.borrow_mut();
                self_ref.on_ready(selector, ready);
            };
            let mut self_ref = rc.borrow_mut();
            let token = selector.register(&self_ref.socket, handler, Ready::readable(), PollOpt::level())?;
            self_ref.token = token;
        }
        Ok(rc)
    }

    fn create_socket(id: &ConnectionId) -> io::Result<UdpSocket> {
        let autobind_addr = SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), 0);
        let udp_socket = UdpSocket::bind(&autobind_addr)?;
        let rewritten_destination = connection::rewritten_destination(id.destination_ip(), id.destination_port()).into();
        udp_socket.connect(rewritten_destination)?;
        Ok(udp_socket)
    }

    fn close(&mut self, selector: &mut Selector) {
        self.closed = true;
        self.disconnect(selector);

        // route is embedded in router which is embedded in client: the client necessarily exists
        let client_rc = self.client.upgrade().expect("expected client not found");
        let mut client = client_rc.borrow_mut();
        client.router().remove(&self.id);
    }

    fn process_send(&mut self, selector: &mut Selector) {
        if let Err(err) = self.write() {
            error!(target: TAG, "Cannot write: {}", err);
            self.close(selector);
        }
    }

    fn process_receive(&mut self, selector: &mut Selector) {
        if let Err(err) = self.read(selector) {
            error!(target: TAG, "Cannot read: {}", err);
            self.close(selector);
        }
    }

    fn read(&mut self, selector: &mut Selector) -> io::Result<()> {
        let ipv4_packet = self.network_to_client.packetize(&mut self.socket)?;
        let client_rc = self.client.upgrade().expect("expected client not found");
        match client_rc.borrow_mut().send_to_client(selector, &ipv4_packet) {
            Ok(_) => {
                debug!(target: TAG, "Packet ({} bytes) sent to client", ipv4_packet.length());
                if log_enabled!(target: TAG, LogLevel::Trace) {
                    // TODO log binary
                }
            },
            Err(err) => {
                // TODO copy packet locally for further sending

            }
        }
        Ok(())
    }

    fn write(&mut self) -> io::Result<()> {
        self.client_to_network.write_to(&mut self.socket)?;
        Ok(())
    }

    fn update_interests(&mut self, selector: &mut Selector) {
        let mut ready = Ready::empty();
        if self.may_read() {
            ready = Ready::readable();
        }
        if self.may_write() {
            ready = ready | Ready::writable();
        }
        selector.reregister(&self.socket, self.token, ready, PollOpt::level()).expect("Cannot register on poll");
    }

    fn may_read(&self) -> bool {
        // TODO
        true
    }

    fn may_write(&self) -> bool {
        !self.client_to_network.is_empty()
    }

    fn on_ready(&mut self, selector: &mut Selector, event: Event) {
        assert!(!self.closed);
        self.touch();
        let ready = event.readiness();
        if ready.is_writable() {
            self.process_send(selector);
        }
        if !self.closed && ready.is_readable() {
            self.process_receive(selector);
        }
        if !self.closed {
            self.update_interests(selector);
        }
    }

    fn touch(&mut self) {
        self.idle_since = Instant::now();
    }
}

impl Connection for UDPConnection {
    fn id(&self) -> &ConnectionId {
        &self.id
    }

    fn send_to_network(&mut self, selector: &mut Selector, ipv4_packet: &IPv4Packet) {
        match self.client_to_network.read_from(ipv4_packet.payload()) {
            Ok(_) => {
                self.update_interests(selector);
            },
            Err(err) => warn!(target: TAG, "Cannot send to network, drop packet: {}", err),
        }
    }

    fn disconnect(&mut self, selector: &mut Selector) {
        selector.deregister(&self.socket, self.token).unwrap();
        // socket will be closed by RAII
    }

    fn is_expired(&self) -> bool {
        self.idle_since.elapsed().as_secs() > IDLE_TIMEOUT_SECONDS
    }
}
<commit_msg>Provide connection ids in logs<commit_after>use std::cell::RefCell;
use std::io;
use std::rc::{Rc, Weak};
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::time::Instant;
use log::LogLevel;
use mio::{Event, PollOpt, Ready, Token};
use mio::net::UdpSocket;

use super::client::Client;
use super::connection::{self, Connection, ConnectionId};
use super::datagram_buffer::DatagramBuffer;
use super::ipv4_packet::{IPv4Packet, MAX_PACKET_LENGTH};
use super::packetizer::Packetizer;
use super::selector::Selector;

const TAG: &'static str = "UDPConnection";

pub const IDLE_TIMEOUT_SECONDS: u64 = 2 * 60;

pub struct UDPConnection {
    id: ConnectionId,
    client: Weak<RefCell<Client>>,
    socket: UdpSocket,
    token: Token,
    client_to_network: DatagramBuffer,
    network_to_client: Packetizer,
    pending_packet_for_client: Option<Box<[u8]>>, // used when the client buffer is full, should be rare
    closed: bool,
    idle_since: Instant,
}

impl UDPConnection {
    pub fn new(selector: &mut Selector, id: ConnectionId, client: Weak<RefCell<Client>>, reference_packet: &IPv4Packet) -> io::Result<Rc<RefCell<Self>>> {
        let socket = UDPConnection::create_socket(&id)?;
        let raw: &[u8] = reference_packet.raw();
        let ipv4_header = reference_packet.ipv4_header().clone();
        let transport_header = reference_packet.transport_header().as_ref().unwrap().clone();
        let rc = Rc::new(RefCell::new(Self {
            id: id,
            client: client,
            socket: socket,
            token: Token(0), // default value, will be set afterwards
            client_to_network: DatagramBuffer::new(4 * MAX_PACKET_LENGTH),
            network_to_client: Packetizer::new(raw, ipv4_header, transport_header),
            pending_packet_for_client: None,
            closed: false,
            idle_since: Instant::now(),
        }));

        {
            let rc_clone = rc.clone();
            let handler = move |selector: &mut Selector, ready| {
                let mut self_ref = rc_clone.borrow_mut();
                self_ref.on_ready(selector, ready);
            };
            let mut self_ref = rc.borrow_mut();
            let token = selector.register(&self_ref.socket, handler, Ready::readable(), PollOpt::level())?;
            self_ref.token = token;
        }
        Ok(rc)
    }

    fn create_socket(id: &ConnectionId) -> io::Result<UdpSocket> {
        let autobind_addr = SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), 0);
        let udp_socket = UdpSocket::bind(&autobind_addr)?;
        let rewritten_destination = connection::rewritten_destination(id.destination_ip(), id.destination_port()).into();
        udp_socket.connect(rewritten_destination)?;
        Ok(udp_socket)
    }

    fn close(&mut self, selector: &mut Selector) {
        self.closed = true;
        self.disconnect(selector);

        // route is embedded in router which is embedded in client: the client necessarily exists
        let client_rc = self.client.upgrade().expect("expected client not found");
        let mut client = client_rc.borrow_mut();
        client.router().remove(&self.id);
    }

    fn process_send(&mut self, selector: &mut Selector) {
        if let Err(err) = self.write() {
            error!(target: TAG, "{} Cannot write: {}", self.id, err);
            self.close(selector);
        }
    }

    fn process_receive(&mut self, selector: &mut Selector) {
        if let Err(err) = self.read(selector) {
            error!(target: TAG, "{} Cannot read: {}", self.id, err);
            self.close(selector);
        }
    }

    fn read(&mut self, selector: &mut Selector) -> io::Result<()> {
        let ipv4_packet = self.network_to_client.packetize(&mut self.socket)?;
        let client_rc = self.client.upgrade().expect("expected client not found");
        match client_rc.borrow_mut().send_to_client(selector, &ipv4_packet) {
            Ok(_) => {
                debug!(target: TAG, "{} Packet ({} bytes) sent to client", self.id, ipv4_packet.length());
                if log_enabled!(target: TAG, LogLevel::Trace) {
                    // TODO log binary
                }
            },
            Err(err) => {
                // TODO copy packet locally for further sending

            }
        }
        Ok(())
    }

    fn write(&mut self) -> io::Result<()> {
        self.client_to_network.write_to(&mut self.socket)?;
        Ok(())
    }

    fn update_interests(&mut self, selector: &mut Selector) {
        let mut ready = Ready::empty();
        if self.may_read() {
            ready = Ready::readable();
        }
        if self.may_write() {
            ready = ready | Ready::writable();
        }
        selector.reregister(&self.socket, self.token, ready, PollOpt::level()).expect("Cannot register on poll");
    }

    fn may_read(&self) -> bool {
        // TODO
        true
    }

    fn may_write(&self) -> bool {
        !self.client_to_network.is_empty()
    }

    fn on_ready(&mut self, selector: &mut Selector, event: Event) {
        assert!(!self.closed);
        self.touch();
        let ready = event.readiness();
        if ready.is_writable() {
            self.process_send(selector);
        }
        if !self.closed && ready.is_readable() {
            self.process_receive(selector);
        }
        if !self.closed {
            self.update_interests(selector);
        }
    }

    fn touch(&mut self) {
        self.idle_since = Instant::now();
    }
}

impl Connection for UDPConnection {
    fn id(&self) -> &ConnectionId {
        &self.id
    }

    fn send_to_network(&mut self, selector: &mut Selector, ipv4_packet: &IPv4Packet) {
        match self.client_to_network.read_from(ipv4_packet.payload()) {
            Ok(_) => {
                self.update_interests(selector);
            },
            Err(err) => warn!(target: TAG, "{} Cannot send to network, drop packet: {}", self.id, err),
        }
    }

    fn disconnect(&mut self, selector: &mut Selector) {
        info!(target: TAG, "{} Close", self.id);
        selector.deregister(&self.socket, self.token).unwrap();
        // socket will be closed by RAII
    }

    fn is_expired(&self) -> bool {
        self.idle_since.elapsed().as_secs() > IDLE_TIMEOUT_SECONDS
    }
}
<|endoftext|>


<commit_before>use crypto::digest::Digest;
use crypto::sha1::Sha1;
use num;
use std::fmt;

pub const LENGTH: usize = 160;

fn compact_bytes(data: &[u8]) -> [u32; 5] {
    let mut compacted = [0; 5];
    for (compact, bytes) in compacted.iter_mut().zip(data.chunks(4).rev()) {
        *compact = bytes.iter()
            .rev()
            .enumerate()
            .fold(0u32, |sum, (i, &b)| sum + ((b as u32) << (8 * i)));
    }
    compacted
}

#[derive(Clone,Copy,Eq,Hash,PartialEq)]
pub struct Address {
    data: [u32; 5]
}

impl Address {
    pub fn for_content(content: &str) -> Address {
        let mut hasher = Sha1::new();
        hasher.input_str(content);
        let mut data = [0; 20];
        hasher.result(&mut data);
        Address {
            data: compact_bytes(&data)
        }
    }

    pub fn from_numeric(numeric: num::BigUint) -> Address {
        let data = numeric.to_bytes_be();
        Address {
            data: compact_bytes(data.as_slice())
        }
    }

    pub fn from_str(string: &str) -> Address {
        use rustc_serialize::hex::FromHex;
        let bytes = string.from_hex().unwrap();
        let mut data = [0u8; 20];
        for (place, byte) in data.iter_mut().zip(bytes.iter()) {
            *place = *byte;
        }
        Address {
            data: compact_bytes(&data)
        }
    }

    pub fn null() -> Address {
        Address {
            data: [0; 5]
        }
    }

    pub fn random(min: &num::BigUint, max: &num::BigUint) -> Address {
        use rand;
        use num::bigint::RandBigInt;

        let mut rng = rand::StdRng::new().unwrap();
        let numeric = rng.gen_biguint_range(min, max);
        Self::from_numeric(numeric)
    }

    pub fn as_numeric(&self) -> num::BigUint {
        num::BigUint::new(self.data.to_vec())
    }

    pub fn distance_from(&self, other: &Self) -> num::BigUint {
        use std::ops::BitXor;
        self.as_numeric().bitxor(other.as_numeric())
    }

    pub fn to_str(&self) -> String {
        format!("{:040x}", self.as_numeric())
    }
}

pub trait Addressable {
    fn get_address(&self) -> Address;
}

impl fmt::Debug for Address {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Address {{ {} }}", self.to_str())
    }
}

#[cfg(test)]
mod tests {
    use num;
    use super::{Address, LENGTH};

    #[test]
    fn test_for_content() {
        let address = Address::for_content("some string");
        assert_eq!(address.to_str(), "8b45e4bd1c6acb88bebf6407d16205f567e62a3e");
    }

    #[test]
    fn test_from_numeric() {
        use num::bigint::ToBigUint;

        let numeric = 0x0000000000000000000000000000000000000001.to_biguint().unwrap();
        let address = Address::from_numeric(numeric);
        assert_eq!(address.as_numeric(), 0x0000000000000000000000000000000000000001.to_biguint().unwrap());
        assert_eq!(address.to_str(), "0000000000000000000000000000000000000001");

        let numeric = num::pow(2.to_biguint().unwrap(), 158) -
            num::pow(2.to_biguint().unwrap(), 157) -
            num::pow(2.to_biguint().unwrap(), 156);
        let address = Address::from_numeric(numeric.clone());
        assert_eq!(address.as_numeric(), numeric);
        assert_eq!(address.to_str(), "1000000000000000000000000000000000000000");

        let numeric = num::pow(2.to_biguint().unwrap(), LENGTH) - 1.to_biguint().unwrap();
        let address = Address::from_numeric(numeric);
        assert_eq!(address.as_numeric(), num::pow(2.to_biguint().unwrap(), LENGTH) - 1.to_biguint().unwrap());
        assert_eq!(address.to_str(), "ffffffffffffffffffffffffffffffffffffffff");
    }

    #[test]
    fn test_from_str() {
        let address = Address::from_str("8b45e4bd1c6acb88bebf6407d16205f567e62a3e");
        assert_eq!(address.to_str(), "8b45e4bd1c6acb88bebf6407d16205f567e62a3e");
    }

    #[test]
    fn test_as_numeric() {
        use num::bigint::ToBigUint;

        let address = Address::from_str("000000000000000000000000000000000000000f");
        assert_eq!(address.as_numeric(), 15u8.to_biguint().unwrap());
        let address = Address::from_str("00000000000000000000000000000000000000f0");
        assert_eq!(address.as_numeric(), 240u8.to_biguint().unwrap());
    }

    #[test]
    fn test_equal() {
        let a = Address::from_str("8b45e4bd1c6acb88bebf6407d16205f567e62a3e");
        let b = Address::from_str("8b45e4bd1c6acb88bebf6407d16205f567e62a3e");
        assert_eq!(a, b);
    }

    #[test]
    fn test_not_equal() {
        let a = Address::from_str("8b45e4bd1c6acb88bebf6407d16205f567e62a3e");
        let b = Address::from_str("8b45e4bd1c6acb88bebf6407d16205f567e62a3f");
        assert!(a != b);
    }
}
<commit_msg>Impl Display for address<commit_after>use crypto::digest::Digest;
use crypto::sha1::Sha1;
use num;
use std::fmt;

pub const LENGTH: usize = 160;

fn compact_bytes(data: &[u8]) -> [u32; 5] {
    let mut compacted = [0; 5];
    for (compact, bytes) in compacted.iter_mut().zip(data.chunks(4).rev()) {
        *compact = bytes.iter()
            .rev()
            .enumerate()
            .fold(0u32, |sum, (i, &b)| sum + ((b as u32) << (8 * i)));
    }
    compacted
}

#[derive(Clone,Copy,Eq,Hash,PartialEq)]
pub struct Address {
    data: [u32; 5]
}

impl Address {
    pub fn for_content(content: &str) -> Address {
        let mut hasher = Sha1::new();
        hasher.input_str(content);
        let mut data = [0; 20];
        hasher.result(&mut data);
        Address {
            data: compact_bytes(&data)
        }
    }

    pub fn from_numeric(numeric: num::BigUint) -> Address {
        let data = numeric.to_bytes_be();
        Address {
            data: compact_bytes(data.as_slice())
        }
    }

    pub fn from_str(string: &str) -> Address {
        use rustc_serialize::hex::FromHex;
        let bytes = string.from_hex().unwrap();
        let mut data = [0u8; 20];
        for (place, byte) in data.iter_mut().zip(bytes.iter()) {
            *place = *byte;
        }
        Address {
            data: compact_bytes(&data)
        }
    }

    pub fn null() -> Address {
        Address {
            data: [0; 5]
        }
    }

    pub fn random(min: &num::BigUint, max: &num::BigUint) -> Address {
        use rand;
        use num::bigint::RandBigInt;

        let mut rng = rand::StdRng::new().unwrap();
        let numeric = rng.gen_biguint_range(min, max);
        Self::from_numeric(numeric)
    }

    pub fn as_numeric(&self) -> num::BigUint {
        num::BigUint::new(self.data.to_vec())
    }

    pub fn distance_from(&self, other: &Self) -> num::BigUint {
        use std::ops::BitXor;
        self.as_numeric().bitxor(other.as_numeric())
    }

    pub fn to_str(&self) -> String {
        format!("{:040x}", self.as_numeric())
    }
}

pub trait Addressable {
    fn get_address(&self) -> Address;
}

impl fmt::Debug for Address {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Address {{ {} }}", self.to_str())
    }
}

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

#[cfg(test)]
mod tests {
    use num;
    use super::{Address, LENGTH};

    #[test]
    fn test_for_content() {
        let address = Address::for_content("some string");
        assert_eq!(address.to_str(), "8b45e4bd1c6acb88bebf6407d16205f567e62a3e");
    }

    #[test]
    fn test_from_numeric() {
        use num::bigint::ToBigUint;

        let numeric = 0x0000000000000000000000000000000000000001.to_biguint().unwrap();
        let address = Address::from_numeric(numeric);
        assert_eq!(address.as_numeric(), 0x0000000000000000000000000000000000000001.to_biguint().unwrap());
        assert_eq!(address.to_str(), "0000000000000000000000000000000000000001");

        let numeric = num::pow(2.to_biguint().unwrap(), 158) -
            num::pow(2.to_biguint().unwrap(), 157) -
            num::pow(2.to_biguint().unwrap(), 156);
        let address = Address::from_numeric(numeric.clone());
        assert_eq!(address.as_numeric(), numeric);
        assert_eq!(address.to_str(), "1000000000000000000000000000000000000000");

        let numeric = num::pow(2.to_biguint().unwrap(), LENGTH) - 1.to_biguint().unwrap();
        let address = Address::from_numeric(numeric);
        assert_eq!(address.as_numeric(), num::pow(2.to_biguint().unwrap(), LENGTH) - 1.to_biguint().unwrap());
        assert_eq!(address.to_str(), "ffffffffffffffffffffffffffffffffffffffff");
    }

    #[test]
    fn test_from_str() {
        let address = Address::from_str("8b45e4bd1c6acb88bebf6407d16205f567e62a3e");
        assert_eq!(address.to_str(), "8b45e4bd1c6acb88bebf6407d16205f567e62a3e");
    }

    #[test]
    fn test_as_numeric() {
        use num::bigint::ToBigUint;

        let address = Address::from_str("000000000000000000000000000000000000000f");
        assert_eq!(address.as_numeric(), 15u8.to_biguint().unwrap());
        let address = Address::from_str("00000000000000000000000000000000000000f0");
        assert_eq!(address.as_numeric(), 240u8.to_biguint().unwrap());
    }

    #[test]
    fn test_equal() {
        let a = Address::from_str("8b45e4bd1c6acb88bebf6407d16205f567e62a3e");
        let b = Address::from_str("8b45e4bd1c6acb88bebf6407d16205f567e62a3e");
        assert_eq!(a, b);
    }

    #[test]
    fn test_not_equal() {
        let a = Address::from_str("8b45e4bd1c6acb88bebf6407d16205f567e62a3e");
        let b = Address::from_str("8b45e4bd1c6acb88bebf6407d16205f567e62a3f");
        assert!(a != b);
    }
}
<|endoftext|>


<commit_before>//! Type aliases for common array sizes
//!

use ::{Ix, Array, ArrayView, ArrayViewMut};
use ::dimension::Dim;
use dimension::DimPrivate;

/// Create a zero-dimensional index
#[allow(non_snake_case)]
#[inline(always)]
pub fn Ix0() -> Ix0 { Dim::new([]) }
/// Create a one-dimensional index
#[allow(non_snake_case)]
#[inline(always)]
pub fn Ix1(i0: Ix) -> Ix1 { Dim::new([i0]) }
/// Create a two-dimensional index
#[allow(non_snake_case)]
#[inline(always)]
pub fn Ix2(i0: Ix, i1: Ix) -> Ix2 { Dim::new([i0, i1]) }
/// Create a three-dimensional index
#[allow(non_snake_case)]
#[inline(always)]
pub fn Ix3(i0: Ix, i1: Ix, i2: Ix) -> Ix3 { Dim::new([i0, i1, i2]) }
/// Create a four-dimensional index
#[allow(non_snake_case)]
#[inline(always)]
pub fn Ix4(i0: Ix, i1: Ix, i2: Ix, i3: Ix) -> Ix4 { Dim::new([i0, i1, i2, i3]) }
/// Create a five-dimensional index
#[allow(non_snake_case)]
#[inline(always)]
pub fn Ix5(i0: Ix, i1: Ix, i2: Ix, i3: Ix, i4: Ix) -> Ix5 {
    Dim::new([i0, i1, i2, i3, i4])
}
/// Create a six-dimensional index
#[allow(non_snake_case)]
#[inline(always)]
pub fn Ix6(i0: Ix, i1: Ix, i2: Ix, i3: Ix, i4: Ix, i5: Ix) -> Ix6 {
    Dim::new([i0, i1, i2, i3, i4, i5])
}

/// zero-dimensionial
pub type Ix0 = Dim<[Ix; 0]>;
/// one-dimensional
pub type Ix1 = Dim<[Ix; 1]>;
/// two-dimensional
pub type Ix2 = Dim<[Ix; 2]>;
/// three-dimensional
pub type Ix3 = Dim<[Ix; 3]>;
/// four-dimensional
pub type Ix4 = Dim<[Ix; 4]>;
/// five-dimensional
pub type Ix5 = Dim<[Ix; 5]>;
/// six-dimensional
pub type Ix6 = Dim<[Ix; 6]>;
/// dynamic-dimensional
pub type IxDyn = Dim<Vec<Ix>>;

/// zero-dimensional array
pub type Array0<A> = Array<A, Ix0>;
/// one-dimensional array
pub type Array1<A> = Array<A, Ix1>;
/// two-dimensional array
pub type Array2<A> = Array<A, Ix2>;
/// three-dimensional array
pub type Array3<A> = Array<A, Ix3>;
/// four-dimensional array
pub type Array4<A> = Array<A, Ix4>;
/// five-dimensional array
pub type Array5<A> = Array<A, Ix5>;
/// six-dimensional array
pub type Array6<A> = Array<A, Ix6>;
/// dynamic-dimensional array
pub type ArrayD<A> = Array<A, IxDyn>;

/// zero-dimensional array view
pub type ArrayView0<'a, A> = ArrayView<'a, A, Ix0>;
/// one-dimensional array view
pub type ArrayView1<'a, A> = ArrayView<'a, A, Ix1>;
/// two-dimensional array view
pub type ArrayView2<'a, A> = ArrayView<'a, A, Ix2>;
/// three-dimensional array view
pub type ArrayView3<'a, A> = ArrayView<'a, A, Ix3>;
/// four-dimensional array view
pub type ArrayView4<'a, A> = ArrayView<'a, A, Ix4>;
/// five-dimensional array view
pub type ArrayView5<'a, A> = ArrayView<'a, A, Ix5>;
/// six-dimensional array view
pub type ArrayView6<'a, A> = ArrayView<'a, A, Ix6>;
/// dynamic-dimensional array view
pub type ArrayViewD<'a, A> = ArrayView<'a, A, IxDyn>;

/// zero-dimensional read-write array view
pub type ArrayViewMut0<'a, A> = ArrayViewMut<'a, A, Ix0>;
/// one-dimensional read-write array view
pub type ArrayViewMut1<'a, A> = ArrayViewMut<'a, A, Ix1>;
/// two-dimensional read-write array view
pub type ArrayViewMut2<'a, A> = ArrayViewMut<'a, A, Ix2>;
/// three-dimensional read-write array view
pub type ArrayViewMut3<'a, A> = ArrayViewMut<'a, A, Ix3>;
/// four-dimensional read-write array view
pub type ArrayViewMut4<'a, A> = ArrayViewMut<'a, A, Ix4>;
/// five-dimensional read-write array view
pub type ArrayViewMut5<'a, A> = ArrayViewMut<'a, A, Ix5>;
/// six-dimensional read-write array view
pub type ArrayViewMut6<'a, A> = ArrayViewMut<'a, A, Ix6>;
/// dynamic-dimensional read-write array view
pub type ArrayViewMutD<'a, A> = ArrayViewMut<'a, A, IxDyn>;
<commit_msg>Add RcArray1, RcArray2 aliases<commit_after>//! Type aliases for common array sizes
//!

use ::{Ix, Array, ArrayView, ArrayViewMut, RcArray};
use ::dimension::Dim;
use dimension::DimPrivate;

/// Create a zero-dimensional index
#[allow(non_snake_case)]
#[inline(always)]
pub fn Ix0() -> Ix0 { Dim::new([]) }
/// Create a one-dimensional index
#[allow(non_snake_case)]
#[inline(always)]
pub fn Ix1(i0: Ix) -> Ix1 { Dim::new([i0]) }
/// Create a two-dimensional index
#[allow(non_snake_case)]
#[inline(always)]
pub fn Ix2(i0: Ix, i1: Ix) -> Ix2 { Dim::new([i0, i1]) }
/// Create a three-dimensional index
#[allow(non_snake_case)]
#[inline(always)]
pub fn Ix3(i0: Ix, i1: Ix, i2: Ix) -> Ix3 { Dim::new([i0, i1, i2]) }
/// Create a four-dimensional index
#[allow(non_snake_case)]
#[inline(always)]
pub fn Ix4(i0: Ix, i1: Ix, i2: Ix, i3: Ix) -> Ix4 { Dim::new([i0, i1, i2, i3]) }
/// Create a five-dimensional index
#[allow(non_snake_case)]
#[inline(always)]
pub fn Ix5(i0: Ix, i1: Ix, i2: Ix, i3: Ix, i4: Ix) -> Ix5 {
    Dim::new([i0, i1, i2, i3, i4])
}
/// Create a six-dimensional index
#[allow(non_snake_case)]
#[inline(always)]
pub fn Ix6(i0: Ix, i1: Ix, i2: Ix, i3: Ix, i4: Ix, i5: Ix) -> Ix6 {
    Dim::new([i0, i1, i2, i3, i4, i5])
}

/// zero-dimensionial
pub type Ix0 = Dim<[Ix; 0]>;
/// one-dimensional
pub type Ix1 = Dim<[Ix; 1]>;
/// two-dimensional
pub type Ix2 = Dim<[Ix; 2]>;
/// three-dimensional
pub type Ix3 = Dim<[Ix; 3]>;
/// four-dimensional
pub type Ix4 = Dim<[Ix; 4]>;
/// five-dimensional
pub type Ix5 = Dim<[Ix; 5]>;
/// six-dimensional
pub type Ix6 = Dim<[Ix; 6]>;
/// dynamic-dimensional
pub type IxDyn = Dim<Vec<Ix>>;

/// zero-dimensional array
pub type Array0<A> = Array<A, Ix0>;
/// one-dimensional array
pub type Array1<A> = Array<A, Ix1>;
/// two-dimensional array
pub type Array2<A> = Array<A, Ix2>;
/// three-dimensional array
pub type Array3<A> = Array<A, Ix3>;
/// four-dimensional array
pub type Array4<A> = Array<A, Ix4>;
/// five-dimensional array
pub type Array5<A> = Array<A, Ix5>;
/// six-dimensional array
pub type Array6<A> = Array<A, Ix6>;
/// dynamic-dimensional array
pub type ArrayD<A> = Array<A, IxDyn>;

/// zero-dimensional array view
pub type ArrayView0<'a, A> = ArrayView<'a, A, Ix0>;
/// one-dimensional array view
pub type ArrayView1<'a, A> = ArrayView<'a, A, Ix1>;
/// two-dimensional array view
pub type ArrayView2<'a, A> = ArrayView<'a, A, Ix2>;
/// three-dimensional array view
pub type ArrayView3<'a, A> = ArrayView<'a, A, Ix3>;
/// four-dimensional array view
pub type ArrayView4<'a, A> = ArrayView<'a, A, Ix4>;
/// five-dimensional array view
pub type ArrayView5<'a, A> = ArrayView<'a, A, Ix5>;
/// six-dimensional array view
pub type ArrayView6<'a, A> = ArrayView<'a, A, Ix6>;
/// dynamic-dimensional array view
pub type ArrayViewD<'a, A> = ArrayView<'a, A, IxDyn>;

/// zero-dimensional read-write array view
pub type ArrayViewMut0<'a, A> = ArrayViewMut<'a, A, Ix0>;
/// one-dimensional read-write array view
pub type ArrayViewMut1<'a, A> = ArrayViewMut<'a, A, Ix1>;
/// two-dimensional read-write array view
pub type ArrayViewMut2<'a, A> = ArrayViewMut<'a, A, Ix2>;
/// three-dimensional read-write array view
pub type ArrayViewMut3<'a, A> = ArrayViewMut<'a, A, Ix3>;
/// four-dimensional read-write array view
pub type ArrayViewMut4<'a, A> = ArrayViewMut<'a, A, Ix4>;
/// five-dimensional read-write array view
pub type ArrayViewMut5<'a, A> = ArrayViewMut<'a, A, Ix5>;
/// six-dimensional read-write array view
pub type ArrayViewMut6<'a, A> = ArrayViewMut<'a, A, Ix6>;
/// dynamic-dimensional read-write array view
pub type ArrayViewMutD<'a, A> = ArrayViewMut<'a, A, IxDyn>;

/// one-dimensional shared ownership array
pub type RcArray1<A> = RcArray<A, Ix1>;
/// two-dimensional shared ownership array
pub type RcArray2<A> = RcArray<A, Ix2>;
<|endoftext|>