<commit_before>use std::str;
use std::io::{MemWriter, MemReader};
use std::mem;
use std::vec;

use super::types::Oid;

pub static PROTOCOL_VERSION: i32 = 0x0003_0000;
pub static CANCEL_CODE: i32 = 80877102;
pub static SSL_CODE: i32 = 80877103;

#[deriving(ToStr)]
pub enum BackendMessage {
    AuthenticationOk,
    AuthenticationKerberosV5,
    AuthenticationCleartextPassword,
    AuthenticationMD5Password {
        salt: ~[u8]
    },
    AuthenticationSCMCredential,
    AuthenticationGSS,
    AuthenticationSSPI,
    BackendKeyData {
        process_id: i32,
        secret_key: i32
    },
    BindComplete,
    CloseComplete,
    CommandComplete {
        tag: ~str
    },
    DataRow {
        row: ~[Option<~[u8]>]
    },
    EmptyQueryResponse,
    ErrorResponse {
        fields: ~[(u8, ~str)]
    },
    NoData,
    NoticeResponse {
        fields: ~[(u8, ~str)]
    },
    NotificationResponse {
        pid: i32,
        channel: ~str,
        payload: ~str
    },
    ParameterDescription {
        types: ~[Oid]
    },
    ParameterStatus {
        parameter: ~str,
        value: ~str
    },
    ParseComplete,
    PortalSuspended,
    ReadyForQuery {
        state: u8
    },
    RowDescription {
        descriptions: ~[RowDescriptionEntry]
    }
}

#[deriving(ToStr)]
pub struct RowDescriptionEntry {
    name: ~str,
    table_oid: Oid,
    column_id: i16,
    type_oid: Oid,
    type_size: i16,
    type_modifier: i32,
    format: i16
}

pub enum FrontendMessage<'a> {
    Bind {
        portal: &'a str,
        statement: &'a str,
        formats: &'a [i16],
        values: &'a [Option<~[u8]>],
        result_formats: &'a [i16]
    },
    CancelRequest {
        code: i32,
        process_id: i32,
        secret_key: i32,
    },
    Close {
        variant: u8,
        name: &'a str
    },
    Describe {
        variant: u8,
        name: &'a str
    },
    Execute {
        portal: &'a str,
        max_rows: i32
    },
    Parse {
        name: &'a str,
        query: &'a str,
        param_types: &'a [i32]
    },
    PasswordMessage {
        password: &'a str
    },
    Query {
        query: &'a str
    },
    StartupMessage {
        version: i32,
        parameters: &'a [(~str, ~str)]
    },
    SslRequest {
        code: i32
    },
    Sync,
    Terminate
}

trait WriteCStr {
    fn write_cstr(&mut self, s: &str);
}

impl<W: Writer> WriteCStr for W {
    fn write_cstr(&mut self, s: &str) {
        self.write(s.as_bytes());
        self.write_u8(0);
    }
}

pub trait WriteMessage {
    fn write_message(&mut self, &FrontendMessage);
}

impl<W: Writer> WriteMessage for W {
    fn write_message(&mut self, message: &FrontendMessage) {
        debug!("Writing message {:?}", message);
        let mut buf = MemWriter::new();
        let mut ident = None;

        match *message {
            Bind { portal, statement, formats, values, result_formats } => {
                ident = Some('B');
                buf.write_cstr(portal);
                buf.write_cstr(statement);

                buf.write_be_i16(formats.len() as i16);
                for format in formats.iter() {
                    buf.write_be_i16(*format);
                }

                buf.write_be_i16(values.len() as i16);
                for value in values.iter() {
                    match *value {
                        None => {
                            buf.write_be_i32(-1);
                        }
                        Some(ref value) => {
                            buf.write_be_i32(value.len() as i32);
                            buf.write(*value);
                        }
                    }
                }

                buf.write_be_i16(result_formats.len() as i16);
                for format in result_formats.iter() {
                    buf.write_be_i16(*format);
                }
            }
            CancelRequest { code, process_id, secret_key } => {
                buf.write_be_i32(code);
                buf.write_be_i32(process_id);
                buf.write_be_i32(secret_key);
            }
            Close { variant, name } => {
                ident = Some('C');
                buf.write_u8(variant);
                buf.write_cstr(name);
            }
            Describe { variant, name } => {
                ident = Some('D');
                buf.write_u8(variant);
                buf.write_cstr(name);
            }
            Execute { portal, max_rows } => {
                ident = Some('E');
                buf.write_cstr(portal);
                buf.write_be_i32(max_rows);
            }
            Parse { name, query, param_types } => {
                ident = Some('P');
                buf.write_cstr(name);
                buf.write_cstr(query);
                buf.write_be_i16(param_types.len() as i16);
                for ty in param_types.iter() {
                    buf.write_be_i32(*ty);
                }
            }
            PasswordMessage { password } => {
                ident = Some('p');
                buf.write_cstr(password);
            }
            Query { query } => {
                ident = Some('Q');
                buf.write_cstr(query);
            }
            StartupMessage { version, parameters } => {
                buf.write_be_i32(version);
                for &(ref k, ref v) in parameters.iter() {
                    buf.write_cstr(k.as_slice());
                    buf.write_cstr(v.as_slice());
                }
                buf.write_u8(0);
            }
            SslRequest { code } => buf.write_be_i32(code),
            Sync => {
                ident = Some('S');
            }
            Terminate => {
                ident = Some('X');
            }
        }

        match ident {
            Some(ident) => self.write_u8(ident as u8),
            None => ()
        }

        let buf = buf.unwrap();

        // add size of length value
        self.write_be_i32((buf.len() + mem::size_of::<i32>()) as i32);
        self.write(buf);
    }
}

trait ReadCStr {
    fn read_cstr(&mut self) -> ~str;
}

impl<R: Buffer> ReadCStr for R {
    fn read_cstr(&mut self) -> ~str {
        let mut buf = self.read_until(0).unwrap();
        buf.pop();
        str::from_utf8_owned(buf).unwrap()
    }
}

pub trait ReadMessage {
    fn read_message(&mut self) -> BackendMessage;
}

impl<R: Reader> ReadMessage for R {
    fn read_message(&mut self) -> BackendMessage {
        debug!("Reading message");

        let ident = self.read_u8();
        // subtract size of length value
        let len = self.read_be_i32() as uint - mem::size_of::<i32>();
        let mut buf = MemReader::new(self.read_bytes(len));

        let ret = match ident as char {
            '1' => ParseComplete,
            '2' => BindComplete,
            '3' => CloseComplete,
            'A' => NotificationResponse {
                pid: buf.read_be_i32(),
                channel: buf.read_cstr(),
                payload: buf.read_cstr()
            },
            'C' => CommandComplete { tag: buf.read_cstr() },
            'D' => read_data_row(&mut buf),
            'E' => ErrorResponse { fields: read_fields(&mut buf) },
            'I' => EmptyQueryResponse,
            'K' => BackendKeyData {
                process_id: buf.read_be_i32(),
                secret_key: buf.read_be_i32()
            },
            'n' => NoData,
            'N' => NoticeResponse { fields: read_fields(&mut buf) },
            'R' => read_auth_message(&mut buf),
            's' => PortalSuspended,
            'S' => ParameterStatus {
                parameter: buf.read_cstr(),
                value: buf.read_cstr()
            },
            't' => read_parameter_description(&mut buf),
            'T' => read_row_description(&mut buf),
            'Z' => ReadyForQuery { state: buf.read_u8() },
            ident => fail!("Unknown message identifier `{}`", ident)
        };
        debug!("Read message {:?}", ret);
        ret
    }
}

fn read_fields(buf: &mut MemReader) -> ~[(u8, ~str)] {
    let mut fields = ~[];
    loop {
        let ty = buf.read_u8();
        if ty == 0 {
            break;
        }

        fields.push((ty, buf.read_cstr()));
    }

    fields
}

fn read_data_row(buf: &mut MemReader) -> BackendMessage {
    let len = buf.read_be_i16() as uint;
    let mut values = vec::with_capacity(len);

    for _ in range(0, len) {
        let val = match buf.read_be_i32() {
            -1 => None,
            len => Some(buf.read_bytes(len as uint))
        };
        values.push(val);
    }

    DataRow { row: values }
}

fn read_auth_message(buf: &mut MemReader) -> BackendMessage {
    match buf.read_be_i32() {
        0 => AuthenticationOk,
        2 => AuthenticationKerberosV5,
        3 => AuthenticationCleartextPassword,
        5 => AuthenticationMD5Password { salt: buf.read_bytes(4) },
        6 => AuthenticationSCMCredential,
        7 => AuthenticationGSS,
        9 => AuthenticationSSPI,
        val => fail!("Invalid authentication identifier `{}`", val)
    }
}

fn read_parameter_description(buf: &mut MemReader) -> BackendMessage {
    let len = buf.read_be_i16() as uint;
    let mut types = vec::with_capacity(len);

    for _ in range(0, len) {
        types.push(buf.read_be_u32());
    }

    ParameterDescription { types: types }
}

fn read_row_description(buf: &mut MemReader) -> BackendMessage {
    let len = buf.read_be_i16() as uint;
    let mut types = vec::with_capacity(len);

    for _ in range(0, len) {
        types.push(RowDescriptionEntry {
            name: buf.read_cstr(),
            table_oid: buf.read_be_u32(),
            column_id: buf.read_be_i16(),
            type_oid: buf.read_be_u32(),
            type_size: buf.read_be_i16(),
            type_modifier: buf.read_be_i32(),
            format: buf.read_be_i16()
        });
    }

    RowDescription { descriptions: types }
}
<commit_msg>Remove unneeded ToStr impl on internal types<commit_after>use std::str;
use std::io::{MemWriter, MemReader};
use std::mem;
use std::vec;

use super::types::Oid;

pub static PROTOCOL_VERSION: i32 = 0x0003_0000;
pub static CANCEL_CODE: i32 = 80877102;
pub static SSL_CODE: i32 = 80877103;

pub enum BackendMessage {
    AuthenticationOk,
    AuthenticationKerberosV5,
    AuthenticationCleartextPassword,
    AuthenticationMD5Password {
        salt: ~[u8]
    },
    AuthenticationSCMCredential,
    AuthenticationGSS,
    AuthenticationSSPI,
    BackendKeyData {
        process_id: i32,
        secret_key: i32
    },
    BindComplete,
    CloseComplete,
    CommandComplete {
        tag: ~str
    },
    DataRow {
        row: ~[Option<~[u8]>]
    },
    EmptyQueryResponse,
    ErrorResponse {
        fields: ~[(u8, ~str)]
    },
    NoData,
    NoticeResponse {
        fields: ~[(u8, ~str)]
    },
    NotificationResponse {
        pid: i32,
        channel: ~str,
        payload: ~str
    },
    ParameterDescription {
        types: ~[Oid]
    },
    ParameterStatus {
        parameter: ~str,
        value: ~str
    },
    ParseComplete,
    PortalSuspended,
    ReadyForQuery {
        state: u8
    },
    RowDescription {
        descriptions: ~[RowDescriptionEntry]
    }
}

pub struct RowDescriptionEntry {
    name: ~str,
    table_oid: Oid,
    column_id: i16,
    type_oid: Oid,
    type_size: i16,
    type_modifier: i32,
    format: i16
}

pub enum FrontendMessage<'a> {
    Bind {
        portal: &'a str,
        statement: &'a str,
        formats: &'a [i16],
        values: &'a [Option<~[u8]>],
        result_formats: &'a [i16]
    },
    CancelRequest {
        code: i32,
        process_id: i32,
        secret_key: i32,
    },
    Close {
        variant: u8,
        name: &'a str
    },
    Describe {
        variant: u8,
        name: &'a str
    },
    Execute {
        portal: &'a str,
        max_rows: i32
    },
    Parse {
        name: &'a str,
        query: &'a str,
        param_types: &'a [i32]
    },
    PasswordMessage {
        password: &'a str
    },
    Query {
        query: &'a str
    },
    StartupMessage {
        version: i32,
        parameters: &'a [(~str, ~str)]
    },
    SslRequest {
        code: i32
    },
    Sync,
    Terminate
}

trait WriteCStr {
    fn write_cstr(&mut self, s: &str);
}

impl<W: Writer> WriteCStr for W {
    fn write_cstr(&mut self, s: &str) {
        self.write(s.as_bytes());
        self.write_u8(0);
    }
}

pub trait WriteMessage {
    fn write_message(&mut self, &FrontendMessage);
}

impl<W: Writer> WriteMessage for W {
    fn write_message(&mut self, message: &FrontendMessage) {
        debug!("Writing message {:?}", message);
        let mut buf = MemWriter::new();
        let mut ident = None;

        match *message {
            Bind { portal, statement, formats, values, result_formats } => {
                ident = Some('B');
                buf.write_cstr(portal);
                buf.write_cstr(statement);

                buf.write_be_i16(formats.len() as i16);
                for format in formats.iter() {
                    buf.write_be_i16(*format);
                }

                buf.write_be_i16(values.len() as i16);
                for value in values.iter() {
                    match *value {
                        None => {
                            buf.write_be_i32(-1);
                        }
                        Some(ref value) => {
                            buf.write_be_i32(value.len() as i32);
                            buf.write(*value);
                        }
                    }
                }

                buf.write_be_i16(result_formats.len() as i16);
                for format in result_formats.iter() {
                    buf.write_be_i16(*format);
                }
            }
            CancelRequest { code, process_id, secret_key } => {
                buf.write_be_i32(code);
                buf.write_be_i32(process_id);
                buf.write_be_i32(secret_key);
            }
            Close { variant, name } => {
                ident = Some('C');
                buf.write_u8(variant);
                buf.write_cstr(name);
            }
            Describe { variant, name } => {
                ident = Some('D');
                buf.write_u8(variant);
                buf.write_cstr(name);
            }
            Execute { portal, max_rows } => {
                ident = Some('E');
                buf.write_cstr(portal);
                buf.write_be_i32(max_rows);
            }
            Parse { name, query, param_types } => {
                ident = Some('P');
                buf.write_cstr(name);
                buf.write_cstr(query);
                buf.write_be_i16(param_types.len() as i16);
                for ty in param_types.iter() {
                    buf.write_be_i32(*ty);
                }
            }
            PasswordMessage { password } => {
                ident = Some('p');
                buf.write_cstr(password);
            }
            Query { query } => {
                ident = Some('Q');
                buf.write_cstr(query);
            }
            StartupMessage { version, parameters } => {
                buf.write_be_i32(version);
                for &(ref k, ref v) in parameters.iter() {
                    buf.write_cstr(k.as_slice());
                    buf.write_cstr(v.as_slice());
                }
                buf.write_u8(0);
            }
            SslRequest { code } => buf.write_be_i32(code),
            Sync => {
                ident = Some('S');
            }
            Terminate => {
                ident = Some('X');
            }
        }

        match ident {
            Some(ident) => self.write_u8(ident as u8),
            None => ()
        }

        let buf = buf.unwrap();

        // add size of length value
        self.write_be_i32((buf.len() + mem::size_of::<i32>()) as i32);
        self.write(buf);
    }
}

trait ReadCStr {
    fn read_cstr(&mut self) -> ~str;
}

impl<R: Buffer> ReadCStr for R {
    fn read_cstr(&mut self) -> ~str {
        let mut buf = self.read_until(0).unwrap();
        buf.pop();
        str::from_utf8_owned(buf).unwrap()
    }
}

pub trait ReadMessage {
    fn read_message(&mut self) -> BackendMessage;
}

impl<R: Reader> ReadMessage for R {
    fn read_message(&mut self) -> BackendMessage {
        debug!("Reading message");

        let ident = self.read_u8();
        // subtract size of length value
        let len = self.read_be_i32() as uint - mem::size_of::<i32>();
        let mut buf = MemReader::new(self.read_bytes(len));

        let ret = match ident as char {
            '1' => ParseComplete,
            '2' => BindComplete,
            '3' => CloseComplete,
            'A' => NotificationResponse {
                pid: buf.read_be_i32(),
                channel: buf.read_cstr(),
                payload: buf.read_cstr()
            },
            'C' => CommandComplete { tag: buf.read_cstr() },
            'D' => read_data_row(&mut buf),
            'E' => ErrorResponse { fields: read_fields(&mut buf) },
            'I' => EmptyQueryResponse,
            'K' => BackendKeyData {
                process_id: buf.read_be_i32(),
                secret_key: buf.read_be_i32()
            },
            'n' => NoData,
            'N' => NoticeResponse { fields: read_fields(&mut buf) },
            'R' => read_auth_message(&mut buf),
            's' => PortalSuspended,
            'S' => ParameterStatus {
                parameter: buf.read_cstr(),
                value: buf.read_cstr()
            },
            't' => read_parameter_description(&mut buf),
            'T' => read_row_description(&mut buf),
            'Z' => ReadyForQuery { state: buf.read_u8() },
            ident => fail!("Unknown message identifier `{}`", ident)
        };
        debug!("Read message {:?}", ret);
        ret
    }
}

fn read_fields(buf: &mut MemReader) -> ~[(u8, ~str)] {
    let mut fields = ~[];
    loop {
        let ty = buf.read_u8();
        if ty == 0 {
            break;
        }

        fields.push((ty, buf.read_cstr()));
    }

    fields
}

fn read_data_row(buf: &mut MemReader) -> BackendMessage {
    let len = buf.read_be_i16() as uint;
    let mut values = vec::with_capacity(len);

    for _ in range(0, len) {
        let val = match buf.read_be_i32() {
            -1 => None,
            len => Some(buf.read_bytes(len as uint))
        };
        values.push(val);
    }

    DataRow { row: values }
}

fn read_auth_message(buf: &mut MemReader) -> BackendMessage {
    match buf.read_be_i32() {
        0 => AuthenticationOk,
        2 => AuthenticationKerberosV5,
        3 => AuthenticationCleartextPassword,
        5 => AuthenticationMD5Password { salt: buf.read_bytes(4) },
        6 => AuthenticationSCMCredential,
        7 => AuthenticationGSS,
        9 => AuthenticationSSPI,
        val => fail!("Invalid authentication identifier `{}`", val)
    }
}

fn read_parameter_description(buf: &mut MemReader) -> BackendMessage {
    let len = buf.read_be_i16() as uint;
    let mut types = vec::with_capacity(len);

    for _ in range(0, len) {
        types.push(buf.read_be_u32());
    }

    ParameterDescription { types: types }
}

fn read_row_description(buf: &mut MemReader) -> BackendMessage {
    let len = buf.read_be_i16() as uint;
    let mut types = vec::with_capacity(len);

    for _ in range(0, len) {
        types.push(RowDescriptionEntry {
            name: buf.read_cstr(),
            table_oid: buf.read_be_u32(),
            column_id: buf.read_be_i16(),
            type_oid: buf.read_be_u32(),
            type_size: buf.read_be_i16(),
            type_modifier: buf.read_be_i32(),
            format: buf.read_be_i16()
        });
    }

    RowDescription { descriptions: types }
}
<|endoftext|>


<commit_before>pub use self::interface::*;
pub use self::packet_batch::PacketBatch;
pub use self::packet_batch::ParsedBatch;
pub use self::packet_batch::TransformBatch;
pub use self::packet_batch::ReplaceBatch;
pub use self::packet_batch::ReceiveBatch;
pub use self::packet_batch::SendBatch;
// pub use self::packet_batch::Act;
pub use self::packet_batch::Batch;
pub use self::pmd::*;
mod interface;
mod mbuf;
mod packet_batch;
mod pmd;
<commit_msg>packet_batch is no longer publicly visible<commit_after>pub use self::interface::*;
pub use self::packet_batch::ParsedBatch;
pub use self::packet_batch::TransformBatch;
pub use self::packet_batch::ReplaceBatch;
pub use self::packet_batch::ReceiveBatch;
pub use self::packet_batch::SendBatch;
pub use self::packet_batch::Batch;
pub use self::pmd::*;
mod interface;
mod mbuf;
mod packet_batch;
mod pmd;
<|endoftext|>


<commit_before>// Copyright 2012-2013 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.

//! Types that provide interior mutability.

use clone::Clone;
use cmp::Eq;
use kinds::{marker, Copy};
use ops::{Deref, DerefMut, Drop};
use option::{None, Option, Some};
use ty::Unsafe;

/// A mutable memory location that admits only `Copy` data.
pub struct Cell<T> {
    value: Unsafe<T>,
    noshare: marker::NoShare,
}

impl<T:Copy> Cell<T> {
    /// Creates a new `Cell` containing the given value.
    pub fn new(value: T) -> Cell<T> {
        Cell {
            value: Unsafe::new(value),
            noshare: marker::NoShare,
        }
    }

    /// Returns a copy of the contained value.
    #[inline]
    pub fn get(&self) -> T {
        unsafe{ *self.value.get() }
    }

    /// Sets the contained value.
    #[inline]
    pub fn set(&self, value: T) {
        unsafe {
            *self.value.get() = value;
        }
    }
}

impl<T:Copy> Clone for Cell<T> {
    fn clone(&self) -> Cell<T> {
        Cell::new(self.get())
    }
}

impl<T:Eq + Copy> Eq for Cell<T> {
    fn eq(&self, other: &Cell<T>) -> bool {
        self.get() == other.get()
    }
}

/// A mutable memory location with dynamically checked borrow rules
pub struct RefCell<T> {
    value: Unsafe<T>,
    borrow: Cell<BorrowFlag>,
    nocopy: marker::NoCopy,
    noshare: marker::NoShare,
}

// Values [1, MAX-1] represent the number of `Ref` active
// (will not outgrow its range since `uint` is the size of the address space)
type BorrowFlag = uint;
static UNUSED: BorrowFlag = 0;
static WRITING: BorrowFlag = -1;

impl<T> RefCell<T> {
    /// Create a new `RefCell` containing `value`
    pub fn new(value: T) -> RefCell<T> {
        RefCell {
            value: Unsafe::new(value),
            borrow: Cell::new(UNUSED),
            nocopy: marker::NoCopy,
            noshare: marker::NoShare,
        }
    }

    /// Consumes the `RefCell`, returning the wrapped value.
    pub fn unwrap(self) -> T {
        debug_assert!(self.borrow.get() == UNUSED);
        unsafe{self.value.unwrap()}
    }

    /// Attempts to immutably borrow the wrapped value.
    ///
    /// The borrow lasts until the returned `Ref` exits scope. Multiple
    /// immutable borrows can be taken out at the same time.
    ///
    /// Returns `None` if the value is currently mutably borrowed.
    pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> {
        match self.borrow.get() {
            WRITING => None,
            borrow => {
                self.borrow.set(borrow + 1);
                Some(Ref { parent: self })
            }
        }
    }

    /// Immutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `Ref` exits scope. Multiple
    /// immutable borrows can be taken out at the same time.
    ///
    /// # Failure
    ///
    /// Fails if the value is currently mutably borrowed.
    pub fn borrow<'a>(&'a self) -> Ref<'a, T> {
        match self.try_borrow() {
            Some(ptr) => ptr,
            None => fail!("RefCell<T> already mutably borrowed")
        }
    }

    /// Mutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `RefMut` exits scope. The value
    /// cannot be borrowed while this borrow is active.
    ///
    /// Returns `None` if the value is currently borrowed.
    pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> {
        match self.borrow.get() {
            UNUSED => {
                self.borrow.set(WRITING);
                Some(RefMut { parent: self })
            },
            _ => None
        }
    }

    /// Mutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `RefMut` exits scope. The value
    /// cannot be borrowed while this borrow is active.
    ///
    /// # Failure
    ///
    /// Fails if the value is currently borrowed.
    pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, T> {
        match self.try_borrow_mut() {
            Some(ptr) => ptr,
            None => fail!("RefCell<T> already borrowed")
        }
    }
}

impl<T: Clone> Clone for RefCell<T> {
    fn clone(&self) -> RefCell<T> {
        RefCell::new(self.borrow().clone())
    }
}

impl<T: Eq> Eq for RefCell<T> {
    fn eq(&self, other: &RefCell<T>) -> bool {
        *self.borrow() == *other.borrow()
    }
}

/// Wraps a borrowed reference to a value in a `RefCell` box.
pub struct Ref<'b, T> {
    parent: &'b RefCell<T>
}

#[unsafe_destructor]
impl<'b, T> Drop for Ref<'b, T> {
    fn drop(&mut self) {
        let borrow = self.parent.borrow.get();
        debug_assert!(borrow != WRITING && borrow != UNUSED);
        self.parent.borrow.set(borrow - 1);
    }
}

impl<'b, T> Deref<T> for Ref<'b, T> {
    #[inline]
    fn deref<'a>(&'a self) -> &'a T {
        unsafe { &*self.parent.value.get() }
    }
}

/// Wraps a mutable borrowed reference to a value in a `RefCell` box.
pub struct RefMut<'b, T> {
    parent: &'b RefCell<T>
}

#[unsafe_destructor]
impl<'b, T> Drop for RefMut<'b, T> {
    fn drop(&mut self) {
        let borrow = self.parent.borrow.get();
        debug_assert!(borrow == WRITING);
        self.parent.borrow.set(UNUSED);
    }
}

impl<'b, T> Deref<T> for RefMut<'b, T> {
    #[inline]
    fn deref<'a>(&'a self) -> &'a T {
        unsafe { &*self.parent.value.get() }
    }
}

impl<'b, T> DerefMut<T> for RefMut<'b, T> {
    #[inline]
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        unsafe { &mut *self.parent.value.get() }
    }
}

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

    #[test]
    fn smoketest_cell() {
        let x = Cell::new(10);
        assert!(x == Cell::new(10));
        assert!(x.get() == 10);
        x.set(20);
        assert!(x == Cell::new(20));
        assert!(x.get() == 20);

        let y = Cell::new((30, 40));
        assert!(y == Cell::new((30, 40)));
        assert!(y.get() == (30, 40));
    }

    #[test]
    fn cell_has_sensible_show() {
        use str::StrSlice;

        let x = ::realcore::cell::Cell::new("foo bar");
        assert!(format!("{}", x).contains(x.get()));

        x.set("baz qux");
        assert!(format!("{}", x).contains(x.get()));
    }

    #[test]
    fn double_imm_borrow() {
        let x = RefCell::new(0);
        let _b1 = x.borrow();
        x.borrow();
    }

    #[test]
    fn no_mut_then_imm_borrow() {
        let x = RefCell::new(0);
        let _b1 = x.borrow_mut();
        assert!(x.try_borrow().is_none());
    }

    #[test]
    fn no_imm_then_borrow_mut() {
        let x = RefCell::new(0);
        let _b1 = x.borrow();
        assert!(x.try_borrow_mut().is_none());
    }

    #[test]
    fn no_double_borrow_mut() {
        let x = RefCell::new(0);
        let _b1 = x.borrow_mut();
        assert!(x.try_borrow_mut().is_none());
    }

    #[test]
    fn imm_release_borrow_mut() {
        let x = RefCell::new(0);
        {
            let _b1 = x.borrow();
        }
        x.borrow_mut();
    }

    #[test]
    fn mut_release_borrow_mut() {
        let x = RefCell::new(0);
        {
            let _b1 = x.borrow_mut();
        }
        x.borrow();
    }

    #[test]
    fn double_borrow_single_release_no_borrow_mut() {
        let x = RefCell::new(0);
        let _b1 = x.borrow();
        {
            let _b2 = x.borrow();
        }
        assert!(x.try_borrow_mut().is_none());
    }

    #[test]
    #[should_fail]
    fn discard_doesnt_unborrow() {
        let x = RefCell::new(0);
        let _b = x.borrow();
        let _ = _b;
        let _b = x.borrow_mut();
    }
}
<commit_msg>Implement cell::clone_ref<commit_after>// Copyright 2012-2013 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.

//! Types that provide interior mutability.

use clone::Clone;
use cmp::Eq;
use kinds::{marker, Copy};
use ops::{Deref, DerefMut, Drop};
use option::{None, Option, Some};
use ty::Unsafe;

/// A mutable memory location that admits only `Copy` data.
pub struct Cell<T> {
    value: Unsafe<T>,
    noshare: marker::NoShare,
}

impl<T:Copy> Cell<T> {
    /// Creates a new `Cell` containing the given value.
    pub fn new(value: T) -> Cell<T> {
        Cell {
            value: Unsafe::new(value),
            noshare: marker::NoShare,
        }
    }

    /// Returns a copy of the contained value.
    #[inline]
    pub fn get(&self) -> T {
        unsafe{ *self.value.get() }
    }

    /// Sets the contained value.
    #[inline]
    pub fn set(&self, value: T) {
        unsafe {
            *self.value.get() = value;
        }
    }
}

impl<T:Copy> Clone for Cell<T> {
    fn clone(&self) -> Cell<T> {
        Cell::new(self.get())
    }
}

impl<T:Eq + Copy> Eq for Cell<T> {
    fn eq(&self, other: &Cell<T>) -> bool {
        self.get() == other.get()
    }
}

/// A mutable memory location with dynamically checked borrow rules
pub struct RefCell<T> {
    value: Unsafe<T>,
    borrow: Cell<BorrowFlag>,
    nocopy: marker::NoCopy,
    noshare: marker::NoShare,
}

// Values [1, MAX-1] represent the number of `Ref` active
// (will not outgrow its range since `uint` is the size of the address space)
type BorrowFlag = uint;
static UNUSED: BorrowFlag = 0;
static WRITING: BorrowFlag = -1;

impl<T> RefCell<T> {
    /// Create a new `RefCell` containing `value`
    pub fn new(value: T) -> RefCell<T> {
        RefCell {
            value: Unsafe::new(value),
            borrow: Cell::new(UNUSED),
            nocopy: marker::NoCopy,
            noshare: marker::NoShare,
        }
    }

    /// Consumes the `RefCell`, returning the wrapped value.
    pub fn unwrap(self) -> T {
        debug_assert!(self.borrow.get() == UNUSED);
        unsafe{self.value.unwrap()}
    }

    /// Attempts to immutably borrow the wrapped value.
    ///
    /// The borrow lasts until the returned `Ref` exits scope. Multiple
    /// immutable borrows can be taken out at the same time.
    ///
    /// Returns `None` if the value is currently mutably borrowed.
    pub fn try_borrow<'a>(&'a self) -> Option<Ref<'a, T>> {
        match self.borrow.get() {
            WRITING => None,
            borrow => {
                self.borrow.set(borrow + 1);
                Some(Ref { parent: self })
            }
        }
    }

    /// Immutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `Ref` exits scope. Multiple
    /// immutable borrows can be taken out at the same time.
    ///
    /// # Failure
    ///
    /// Fails if the value is currently mutably borrowed.
    pub fn borrow<'a>(&'a self) -> Ref<'a, T> {
        match self.try_borrow() {
            Some(ptr) => ptr,
            None => fail!("RefCell<T> already mutably borrowed")
        }
    }

    /// Mutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `RefMut` exits scope. The value
    /// cannot be borrowed while this borrow is active.
    ///
    /// Returns `None` if the value is currently borrowed.
    pub fn try_borrow_mut<'a>(&'a self) -> Option<RefMut<'a, T>> {
        match self.borrow.get() {
            UNUSED => {
                self.borrow.set(WRITING);
                Some(RefMut { parent: self })
            },
            _ => None
        }
    }

    /// Mutably borrows the wrapped value.
    ///
    /// The borrow lasts until the returned `RefMut` exits scope. The value
    /// cannot be borrowed while this borrow is active.
    ///
    /// # Failure
    ///
    /// Fails if the value is currently borrowed.
    pub fn borrow_mut<'a>(&'a self) -> RefMut<'a, T> {
        match self.try_borrow_mut() {
            Some(ptr) => ptr,
            None => fail!("RefCell<T> already borrowed")
        }
    }
}

impl<T: Clone> Clone for RefCell<T> {
    fn clone(&self) -> RefCell<T> {
        RefCell::new(self.borrow().clone())
    }
}

impl<T: Eq> Eq for RefCell<T> {
    fn eq(&self, other: &RefCell<T>) -> bool {
        *self.borrow() == *other.borrow()
    }
}

/// Wraps a borrowed reference to a value in a `RefCell` box.
pub struct Ref<'b, T> {
    parent: &'b RefCell<T>
}

#[unsafe_destructor]
impl<'b, T> Drop for Ref<'b, T> {
    fn drop(&mut self) {
        let borrow = self.parent.borrow.get();
        debug_assert!(borrow != WRITING && borrow != UNUSED);
        self.parent.borrow.set(borrow - 1);
    }
}

impl<'b, T> Deref<T> for Ref<'b, T> {
    #[inline]
    fn deref<'a>(&'a self) -> &'a T {
        unsafe { &*self.parent.value.get() }
    }
}

/// Copy a `Ref`.
///
/// The `RefCell` is already immutably borrowed, so this cannot fail.
///
/// A `Clone` implementation would interfere with the widespread
/// use of `r.borrow().clone()` to clone the contents of a `RefCell`.
#[experimental]
pub fn clone_ref<'b, T>(orig: &Ref<'b, T>) -> Ref<'b, T> {
    // Since this Ref exists, we know the borrow flag
    // is not set to WRITING.
    let borrow = orig.parent.borrow.get();
    debug_assert!(borrow != WRITING && borrow != UNUSED);
    orig.parent.borrow.set(borrow + 1);

    Ref {
        parent: orig.parent,
    }
}

/// Wraps a mutable borrowed reference to a value in a `RefCell` box.
pub struct RefMut<'b, T> {
    parent: &'b RefCell<T>
}

#[unsafe_destructor]
impl<'b, T> Drop for RefMut<'b, T> {
    fn drop(&mut self) {
        let borrow = self.parent.borrow.get();
        debug_assert!(borrow == WRITING);
        self.parent.borrow.set(UNUSED);
    }
}

impl<'b, T> Deref<T> for RefMut<'b, T> {
    #[inline]
    fn deref<'a>(&'a self) -> &'a T {
        unsafe { &*self.parent.value.get() }
    }
}

impl<'b, T> DerefMut<T> for RefMut<'b, T> {
    #[inline]
    fn deref_mut<'a>(&'a mut self) -> &'a mut T {
        unsafe { &mut *self.parent.value.get() }
    }
}

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

    #[test]
    fn smoketest_cell() {
        let x = Cell::new(10);
        assert!(x == Cell::new(10));
        assert!(x.get() == 10);
        x.set(20);
        assert!(x == Cell::new(20));
        assert!(x.get() == 20);

        let y = Cell::new((30, 40));
        assert!(y == Cell::new((30, 40)));
        assert!(y.get() == (30, 40));
    }

    #[test]
    fn cell_has_sensible_show() {
        use str::StrSlice;

        let x = ::realcore::cell::Cell::new("foo bar");
        assert!(format!("{}", x).contains(x.get()));

        x.set("baz qux");
        assert!(format!("{}", x).contains(x.get()));
    }

    #[test]
    fn double_imm_borrow() {
        let x = RefCell::new(0);
        let _b1 = x.borrow();
        x.borrow();
    }

    #[test]
    fn no_mut_then_imm_borrow() {
        let x = RefCell::new(0);
        let _b1 = x.borrow_mut();
        assert!(x.try_borrow().is_none());
    }

    #[test]
    fn no_imm_then_borrow_mut() {
        let x = RefCell::new(0);
        let _b1 = x.borrow();
        assert!(x.try_borrow_mut().is_none());
    }

    #[test]
    fn no_double_borrow_mut() {
        let x = RefCell::new(0);
        let _b1 = x.borrow_mut();
        assert!(x.try_borrow_mut().is_none());
    }

    #[test]
    fn imm_release_borrow_mut() {
        let x = RefCell::new(0);
        {
            let _b1 = x.borrow();
        }
        x.borrow_mut();
    }

    #[test]
    fn mut_release_borrow_mut() {
        let x = RefCell::new(0);
        {
            let _b1 = x.borrow_mut();
        }
        x.borrow();
    }

    #[test]
    fn double_borrow_single_release_no_borrow_mut() {
        let x = RefCell::new(0);
        let _b1 = x.borrow();
        {
            let _b2 = x.borrow();
        }
        assert!(x.try_borrow_mut().is_none());
    }

    #[test]
    #[should_fail]
    fn discard_doesnt_unborrow() {
        let x = RefCell::new(0);
        let _b = x.borrow();
        let _ = _b;
        let _b = x.borrow_mut();
    }

    #[test]
    fn clone_ref_updates_flag() {
        let x = RefCell::new(0);
        {
            let b1 = x.borrow();
            assert!(x.try_borrow_mut().is_none());
            {
                let _b2 = clone_ref(&b1);
                assert!(x.try_borrow_mut().is_none());
            }
            assert!(x.try_borrow_mut().is_none());
        }
        assert!(x.try_borrow_mut().is_some());
    }
}
<|endoftext|>


<commit_before>use core::fmt::{self, Display};

use ser::{self, Serialize, Serializer, SerializeMap, SerializeStruct, Impossible};

#[cfg(any(feature = "std", feature = "collections"))]
use ser::content::{SerializeTupleVariantAsMapValue, SerializeStructVariantAsMapValue};

/// Not public API.
pub fn serialize_tagged_newtype<S, T>(serializer: S,
                                      type_ident: &'static str,
                                      variant_ident: &'static str,
                                      tag: &'static str,
                                      variant_name: &'static str,
                                      value: T)
                                      -> Result<S::Ok, S::Error>
    where S: Serializer,
          T: Serialize
{
    value.serialize(TaggedSerializer {
        type_ident: type_ident,
        variant_ident: variant_ident,
        tag: tag,
        variant_name: variant_name,
        delegate: serializer,
    })
}

struct TaggedSerializer<S> {
    type_ident: &'static str,
    variant_ident: &'static str,
    tag: &'static str,
    variant_name: &'static str,
    delegate: S,
}

enum Unsupported {
    Boolean,
    Integer,
    Float,
    Char,
    String,
    ByteArray,
    Optional,
    Unit,
    UnitStruct,
    Sequence,
    Tuple,
    TupleStruct,
    #[cfg(not(any(feature = "std", feature = "collections")))]
    Enum,
}

impl Display for Unsupported {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Unsupported::Boolean => formatter.write_str("a boolean"),
            Unsupported::Integer => formatter.write_str("an integer"),
            Unsupported::Float => formatter.write_str("a float"),
            Unsupported::Char => formatter.write_str("a char"),
            Unsupported::String => formatter.write_str("a string"),
            Unsupported::ByteArray => formatter.write_str("a byte array"),
            Unsupported::Optional => formatter.write_str("an optional"),
            Unsupported::Unit => formatter.write_str("unit"),
            Unsupported::UnitStruct => formatter.write_str("a unit struct"),
            Unsupported::Sequence => formatter.write_str("a sequence"),
            Unsupported::Tuple => formatter.write_str("a tuple"),
            Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
            #[cfg(not(any(feature = "std", feature = "collections")))]
            Unsupported::Enum => formatter.write_str("an enum"),
        }
    }
}

struct Error {
    type_ident: &'static str,
    variant_ident: &'static str,
    ty: Unsupported,
}

impl Display for Error {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter,
               "cannot serialize tagged newtype variant {}::{} containing {}",
               self.type_ident, self.variant_ident, self.ty)
    }
}

impl<S> TaggedSerializer<S>
    where S: Serializer
{
    fn bad_type(self, what: Unsupported) -> S::Error {
        ser::Error::custom(Error {
            type_ident: self.type_ident,
            variant_ident: self.variant_ident,
            ty: what,
        })
    }
}

impl<S> Serializer for TaggedSerializer<S>
    where S: Serializer
{
    type Ok = S::Ok;
    type Error = S::Error;

    type SerializeSeq = Impossible<S::Ok, S::Error>;
    type SerializeTuple = Impossible<S::Ok, S::Error>;
    type SerializeTupleStruct = Impossible<S::Ok, S::Error>;
    type SerializeMap = S::SerializeMap;
    type SerializeStruct = S::SerializeStruct;

    #[cfg(not(any(feature = "std", feature = "collections")))]
    type SerializeTupleVariant = Impossible<S::Ok, S::Error>;
    #[cfg(any(feature = "std", feature = "collections"))]
    type SerializeTupleVariant = SerializeTupleVariantAsMapValue<S::SerializeMap>;

    #[cfg(not(any(feature = "std", feature = "collections")))]
    type SerializeStructVariant = Impossible<S::Ok, S::Error>;
    #[cfg(any(feature = "std", feature = "collections"))]
    type SerializeStructVariant = SerializeStructVariantAsMapValue<S::SerializeMap>;

    fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Boolean))
    }

    fn serialize_i8(self, _: i8) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Integer))
    }

    fn serialize_i16(self, _: i16) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Integer))
    }

    fn serialize_i32(self, _: i32) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Integer))
    }

    fn serialize_i64(self, _: i64) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Integer))
    }

    fn serialize_u8(self, _: u8) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Integer))
    }

    fn serialize_u16(self, _: u16) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Integer))
    }

    fn serialize_u32(self, _: u32) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Integer))
    }

    fn serialize_u64(self, _: u64) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Integer))
    }

    fn serialize_f32(self, _: f32) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Float))
    }

    fn serialize_f64(self, _: f64) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Float))
    }

    fn serialize_char(self, _: char) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Char))
    }

    fn serialize_str(self, _: &str) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::String))
    }

    fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::ByteArray))
    }

    fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Optional))
    }

    fn serialize_some<T: ?Sized>(self, _: &T) -> Result<Self::Ok, Self::Error>
        where T: Serialize
    {
        Err(self.bad_type(Unsupported::Optional))
    }

    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Unit))
    }

    fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::UnitStruct))
    }

    fn serialize_unit_variant(self,
                              _: &'static str,
                              _: usize,
                              inner_variant: &'static str)
                              -> Result<Self::Ok, Self::Error> {
        let mut map = try!(self.delegate.serialize_map(Some(2)));
        try!(map.serialize_entry(self.tag, self.variant_name));
        try!(map.serialize_entry(inner_variant, &()));
        map.end()
    }

    fn serialize_newtype_struct<T: ?Sized>(self,
                                           _: &'static str,
                                           value: &T)
                                           -> Result<Self::Ok, Self::Error>
        where T: Serialize
    {
        value.serialize(self)
    }

    fn serialize_newtype_variant<T: ?Sized>(self,
                                            _: &'static str,
                                            _: usize,
                                            inner_variant: &'static str,
                                            inner_value: &T)
                                            -> Result<Self::Ok, Self::Error>
        where T: Serialize
    {
        let mut map = try!(self.delegate.serialize_map(Some(2)));
        try!(map.serialize_entry(self.tag, self.variant_name));
        try!(map.serialize_entry(inner_variant, inner_value));
        map.end()
    }

    fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
        Err(self.bad_type(Unsupported::Sequence))
    }

    fn serialize_seq_fixed_size(self, _: usize) -> Result<Self::SerializeSeq, Self::Error> {
        Err(self.bad_type(Unsupported::Sequence))
    }

    fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Self::Error> {
        Err(self.bad_type(Unsupported::Tuple))
    }

    fn serialize_tuple_struct(self,
                              _: &'static str,
                              _: usize)
                              -> Result<Self::SerializeTupleStruct, Self::Error> {
        Err(self.bad_type(Unsupported::TupleStruct))
    }

    #[cfg(not(any(feature = "std", feature = "collections")))]
    fn serialize_tuple_variant(self,
                               _: &'static str,
                               _: usize,
                               _: &'static str,
                               _: usize)
                               -> Result<Self::SerializeTupleVariant, Self::Error> {
        // Lack of push-based serialization means we need to buffer the content
        // of the tuple variant, so it requires std.
        Err(self.bad_type(Unsupported::Enum))
    }

    #[cfg(any(feature = "std", feature = "collections"))]
    fn serialize_tuple_variant(self,
                               _: &'static str,
                               _: usize,
                               inner_variant: &'static str,
                               len: usize)
                               -> Result<Self::SerializeTupleVariant, Self::Error> {
        let mut map = try!(self.delegate.serialize_map(Some(2)));
        try!(map.serialize_entry(self.tag, self.variant_name));
        try!(map.serialize_key(inner_variant));
        Ok(SerializeTupleVariantAsMapValue::new(map, inner_variant, len))
    }

    fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
        let mut map = try!(self.delegate.serialize_map(len.map(|len| len + 1)));
        try!(map.serialize_entry(self.tag, self.variant_name));
        Ok(map)
    }

    fn serialize_struct(self,
                        name: &'static str,
                        len: usize)
                        -> Result<Self::SerializeStruct, Self::Error> {
        let mut state = try!(self.delegate.serialize_struct(name, len + 1));
        try!(state.serialize_field(self.tag, self.variant_name));
        Ok(state)
    }

    #[cfg(not(any(feature = "std", feature = "collections")))]
    fn serialize_struct_variant(self,
                                _: &'static str,
                                _: usize,
                                _: &'static str,
                                _: usize)
                                -> Result<Self::SerializeStructVariant, Self::Error> {
        // Lack of push-based serialization means we need to buffer the content
        // of the struct variant, so it requires std.
        Err(self.bad_type(Unsupported::Enum))
    }

    #[cfg(any(feature = "std", feature = "collections"))]
    fn serialize_struct_variant(self,
                                _: &'static str,
                                _: usize,
                                inner_variant: &'static str,
                                len: usize)
                                -> Result<Self::SerializeStructVariant, Self::Error> {
        let mut map = try!(self.delegate.serialize_map(Some(2)));
        try!(map.serialize_entry(self.tag, self.variant_name));
        try!(map.serialize_key(inner_variant));
        Ok(SerializeStructVariantAsMapValue::new(map, inner_variant, len))
    }
}
<commit_msg>Fix needless_pass_by_value lint<commit_after>use core::fmt::{self, Display};

use ser::{self, Serialize, Serializer, SerializeMap, SerializeStruct, Impossible};

#[cfg(any(feature = "std", feature = "collections"))]
use ser::content::{SerializeTupleVariantAsMapValue, SerializeStructVariantAsMapValue};

/// Not public API.
pub fn serialize_tagged_newtype<S, T>(serializer: S,
                                      type_ident: &'static str,
                                      variant_ident: &'static str,
                                      tag: &'static str,
                                      variant_name: &'static str,
                                      value: &T)
                                      -> Result<S::Ok, S::Error>
    where S: Serializer,
          T: Serialize
{
    value.serialize(TaggedSerializer {
        type_ident: type_ident,
        variant_ident: variant_ident,
        tag: tag,
        variant_name: variant_name,
        delegate: serializer,
    })
}

struct TaggedSerializer<S> {
    type_ident: &'static str,
    variant_ident: &'static str,
    tag: &'static str,
    variant_name: &'static str,
    delegate: S,
}

enum Unsupported {
    Boolean,
    Integer,
    Float,
    Char,
    String,
    ByteArray,
    Optional,
    Unit,
    UnitStruct,
    Sequence,
    Tuple,
    TupleStruct,
    #[cfg(not(any(feature = "std", feature = "collections")))]
    Enum,
}

impl Display for Unsupported {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Unsupported::Boolean => formatter.write_str("a boolean"),
            Unsupported::Integer => formatter.write_str("an integer"),
            Unsupported::Float => formatter.write_str("a float"),
            Unsupported::Char => formatter.write_str("a char"),
            Unsupported::String => formatter.write_str("a string"),
            Unsupported::ByteArray => formatter.write_str("a byte array"),
            Unsupported::Optional => formatter.write_str("an optional"),
            Unsupported::Unit => formatter.write_str("unit"),
            Unsupported::UnitStruct => formatter.write_str("a unit struct"),
            Unsupported::Sequence => formatter.write_str("a sequence"),
            Unsupported::Tuple => formatter.write_str("a tuple"),
            Unsupported::TupleStruct => formatter.write_str("a tuple struct"),
            #[cfg(not(any(feature = "std", feature = "collections")))]
            Unsupported::Enum => formatter.write_str("an enum"),
        }
    }
}

struct Error {
    type_ident: &'static str,
    variant_ident: &'static str,
    ty: Unsupported,
}

impl Display for Error {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter,
               "cannot serialize tagged newtype variant {}::{} containing {}",
               self.type_ident, self.variant_ident, self.ty)
    }
}

impl<S> TaggedSerializer<S>
    where S: Serializer
{
    fn bad_type(self, what: Unsupported) -> S::Error {
        ser::Error::custom(Error {
            type_ident: self.type_ident,
            variant_ident: self.variant_ident,
            ty: what,
        })
    }
}

impl<S> Serializer for TaggedSerializer<S>
    where S: Serializer
{
    type Ok = S::Ok;
    type Error = S::Error;

    type SerializeSeq = Impossible<S::Ok, S::Error>;
    type SerializeTuple = Impossible<S::Ok, S::Error>;
    type SerializeTupleStruct = Impossible<S::Ok, S::Error>;
    type SerializeMap = S::SerializeMap;
    type SerializeStruct = S::SerializeStruct;

    #[cfg(not(any(feature = "std", feature = "collections")))]
    type SerializeTupleVariant = Impossible<S::Ok, S::Error>;
    #[cfg(any(feature = "std", feature = "collections"))]
    type SerializeTupleVariant = SerializeTupleVariantAsMapValue<S::SerializeMap>;

    #[cfg(not(any(feature = "std", feature = "collections")))]
    type SerializeStructVariant = Impossible<S::Ok, S::Error>;
    #[cfg(any(feature = "std", feature = "collections"))]
    type SerializeStructVariant = SerializeStructVariantAsMapValue<S::SerializeMap>;

    fn serialize_bool(self, _: bool) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Boolean))
    }

    fn serialize_i8(self, _: i8) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Integer))
    }

    fn serialize_i16(self, _: i16) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Integer))
    }

    fn serialize_i32(self, _: i32) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Integer))
    }

    fn serialize_i64(self, _: i64) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Integer))
    }

    fn serialize_u8(self, _: u8) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Integer))
    }

    fn serialize_u16(self, _: u16) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Integer))
    }

    fn serialize_u32(self, _: u32) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Integer))
    }

    fn serialize_u64(self, _: u64) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Integer))
    }

    fn serialize_f32(self, _: f32) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Float))
    }

    fn serialize_f64(self, _: f64) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Float))
    }

    fn serialize_char(self, _: char) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Char))
    }

    fn serialize_str(self, _: &str) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::String))
    }

    fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::ByteArray))
    }

    fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Optional))
    }

    fn serialize_some<T: ?Sized>(self, _: &T) -> Result<Self::Ok, Self::Error>
        where T: Serialize
    {
        Err(self.bad_type(Unsupported::Optional))
    }

    fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::Unit))
    }

    fn serialize_unit_struct(self, _: &'static str) -> Result<Self::Ok, Self::Error> {
        Err(self.bad_type(Unsupported::UnitStruct))
    }

    fn serialize_unit_variant(self,
                              _: &'static str,
                              _: usize,
                              inner_variant: &'static str)
                              -> Result<Self::Ok, Self::Error> {
        let mut map = try!(self.delegate.serialize_map(Some(2)));
        try!(map.serialize_entry(self.tag, self.variant_name));
        try!(map.serialize_entry(inner_variant, &()));
        map.end()
    }

    fn serialize_newtype_struct<T: ?Sized>(self,
                                           _: &'static str,
                                           value: &T)
                                           -> Result<Self::Ok, Self::Error>
        where T: Serialize
    {
        value.serialize(self)
    }

    fn serialize_newtype_variant<T: ?Sized>(self,
                                            _: &'static str,
                                            _: usize,
                                            inner_variant: &'static str,
                                            inner_value: &T)
                                            -> Result<Self::Ok, Self::Error>
        where T: Serialize
    {
        let mut map = try!(self.delegate.serialize_map(Some(2)));
        try!(map.serialize_entry(self.tag, self.variant_name));
        try!(map.serialize_entry(inner_variant, inner_value));
        map.end()
    }

    fn serialize_seq(self, _: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
        Err(self.bad_type(Unsupported::Sequence))
    }

    fn serialize_seq_fixed_size(self, _: usize) -> Result<Self::SerializeSeq, Self::Error> {
        Err(self.bad_type(Unsupported::Sequence))
    }

    fn serialize_tuple(self, _: usize) -> Result<Self::SerializeTuple, Self::Error> {
        Err(self.bad_type(Unsupported::Tuple))
    }

    fn serialize_tuple_struct(self,
                              _: &'static str,
                              _: usize)
                              -> Result<Self::SerializeTupleStruct, Self::Error> {
        Err(self.bad_type(Unsupported::TupleStruct))
    }

    #[cfg(not(any(feature = "std", feature = "collections")))]
    fn serialize_tuple_variant(self,
                               _: &'static str,
                               _: usize,
                               _: &'static str,
                               _: usize)
                               -> Result<Self::SerializeTupleVariant, Self::Error> {
        // Lack of push-based serialization means we need to buffer the content
        // of the tuple variant, so it requires std.
        Err(self.bad_type(Unsupported::Enum))
    }

    #[cfg(any(feature = "std", feature = "collections"))]
    fn serialize_tuple_variant(self,
                               _: &'static str,
                               _: usize,
                               inner_variant: &'static str,
                               len: usize)
                               -> Result<Self::SerializeTupleVariant, Self::Error> {
        let mut map = try!(self.delegate.serialize_map(Some(2)));
        try!(map.serialize_entry(self.tag, self.variant_name));
        try!(map.serialize_key(inner_variant));
        Ok(SerializeTupleVariantAsMapValue::new(map, inner_variant, len))
    }

    fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
        let mut map = try!(self.delegate.serialize_map(len.map(|len| len + 1)));
        try!(map.serialize_entry(self.tag, self.variant_name));
        Ok(map)
    }

    fn serialize_struct(self,
                        name: &'static str,
                        len: usize)
                        -> Result<Self::SerializeStruct, Self::Error> {
        let mut state = try!(self.delegate.serialize_struct(name, len + 1));
        try!(state.serialize_field(self.tag, self.variant_name));
        Ok(state)
    }

    #[cfg(not(any(feature = "std", feature = "collections")))]
    fn serialize_struct_variant(self,
                                _: &'static str,
                                _: usize,
                                _: &'static str,
                                _: usize)
                                -> Result<Self::SerializeStructVariant, Self::Error> {
        // Lack of push-based serialization means we need to buffer the content
        // of the struct variant, so it requires std.
        Err(self.bad_type(Unsupported::Enum))
    }

    #[cfg(any(feature = "std", feature = "collections"))]
    fn serialize_struct_variant(self,
                                _: &'static str,
                                _: usize,
                                inner_variant: &'static str,
                                len: usize)
                                -> Result<Self::SerializeStructVariant, Self::Error> {
        let mut map = try!(self.delegate.serialize_map(Some(2)));
        try!(map.serialize_entry(self.tag, self.variant_name));
        try!(map.serialize_key(inner_variant));
        Ok(SerializeStructVariantAsMapValue::new(map, inner_variant, len))
    }
}
<|endoftext|>


<commit_before>//! This is code from [Tungstenite project](https://github.com/snapview/tungstenite-rs)

/// Mask/unmask a frame.
#[inline]
pub fn apply_mask(buf: &mut [u8], mask: [u8; 4]) {
    apply_mask_fast32(buf, mask)
}

/// A safe unoptimized mask application.
#[inline]
fn apply_mask_fallback(buf: &mut [u8], mask: [u8; 4]) {
    for (i, byte) in buf.iter_mut().enumerate() {
        *byte ^= mask[i & 3];
    }
}

/// Faster version of `apply_mask()` which operates on 4-byte blocks.
#[inline]
pub fn apply_mask_fast32(buf: &mut [u8], mask: [u8; 4]) {
    let mask_u32 = u32::from_ne_bytes(mask);

    // SAFETY:
    //
    // buf is a valid slice borrowed mutably from bytes::BytesMut.
    //
    // un aligned prefix and suffix would be mask/unmask per byte.
    // proper aligned middle slice goes into fast path and operates on 4-byte blocks.
    let (prefix, words, suffix) = unsafe { buf.align_to_mut::<u32>() };
    apply_mask_fallback(prefix, mask);
    let head = prefix.len() & 3;
    let mask_u32 = if head > 0 {
        if cfg!(target_endian = "big") {
            mask_u32.rotate_left(8 * head as u32)
        } else {
            mask_u32.rotate_right(8 * head as u32)
        }
    } else {
        mask_u32
    };
    for word in words.iter_mut() {
        *word ^= mask_u32;
    }
    apply_mask_fallback(suffix, mask_u32.to_ne_bytes());
}

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

    // legacy test from old apply mask test. kept for now for back compat test.
    // TODO: remove it and favor the other test.
    #[test]
    fn test_apply_mask_legacy() {
        let mask = [0x6d, 0xb6, 0xb2, 0x80];

        let unmasked = vec![
            0xf3, 0x00, 0x01, 0x02, 0x03, 0x80, 0x81, 0x82, 0xff, 0xfe, 0x00, 0x17, 0x74, 0xf9,
            0x12, 0x03,
        ];

        // Check masking with proper alignment.
        {
            let mut masked = unmasked.clone();
            apply_mask_fallback(&mut masked, mask);

            let mut masked_fast = unmasked.clone();
            apply_mask(&mut masked_fast, mask);

            assert_eq!(masked, masked_fast);
        }

        // Check masking without alignment.
        {
            let mut masked = unmasked.clone();
            apply_mask_fallback(&mut masked[1..], mask);

            let mut masked_fast = unmasked;
            apply_mask(&mut masked_fast[1..], mask);

            assert_eq!(masked, masked_fast);
        }
    }

    #[test]
    fn test_apply_mask() {
        let mask = [0x6d, 0xb6, 0xb2, 0x80];
        let unmasked = vec![
            0xf3, 0x00, 0x01, 0x02, 0x03, 0x80, 0x81, 0x82, 0xff, 0xfe, 0x00, 0x17, 0x74, 0xf9,
            0x12, 0x03,
        ];

        for data_len in 0..=unmasked.len() {
            let unmasked = &unmasked[0..data_len];
            // Check masking with different alignment.
            for off in 0..=3 {
                if unmasked.len() < off {
                    continue;
                }
                let mut masked = unmasked.to_vec();
                apply_mask_fallback(&mut masked[off..], mask);

                let mut masked_fast = unmasked.to_vec();
                apply_mask_fast32(&mut masked_fast[off..], mask);

                assert_eq!(masked, masked_fast);
            }
        }
    }
}
<commit_msg>remove legacy ws test<commit_after>//! This is code from [Tungstenite project](https://github.com/snapview/tungstenite-rs)

/// Mask/unmask a frame.
#[inline]
pub fn apply_mask(buf: &mut [u8], mask: [u8; 4]) {
    apply_mask_fast32(buf, mask)
}

/// A safe unoptimized mask application.
#[inline]
fn apply_mask_fallback(buf: &mut [u8], mask: [u8; 4]) {
    for (i, byte) in buf.iter_mut().enumerate() {
        *byte ^= mask[i & 3];
    }
}

/// Faster version of `apply_mask()` which operates on 4-byte blocks.
#[inline]
pub fn apply_mask_fast32(buf: &mut [u8], mask: [u8; 4]) {
    let mask_u32 = u32::from_ne_bytes(mask);

    // SAFETY:
    //
    // buf is a valid slice borrowed mutably from bytes::BytesMut.
    //
    // un aligned prefix and suffix would be mask/unmask per byte.
    // proper aligned middle slice goes into fast path and operates on 4-byte blocks.
    let (prefix, words, suffix) = unsafe { buf.align_to_mut::<u32>() };
    apply_mask_fallback(prefix, mask);
    let head = prefix.len() & 3;
    let mask_u32 = if head > 0 {
        if cfg!(target_endian = "big") {
            mask_u32.rotate_left(8 * head as u32)
        } else {
            mask_u32.rotate_right(8 * head as u32)
        }
    } else {
        mask_u32
    };
    for word in words.iter_mut() {
        *word ^= mask_u32;
    }
    apply_mask_fallback(suffix, mask_u32.to_ne_bytes());
}

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

    #[test]
    fn test_apply_mask() {
        let mask = [0x6d, 0xb6, 0xb2, 0x80];
        let unmasked = vec![
            0xf3, 0x00, 0x01, 0x02, 0x03, 0x80, 0x81, 0x82, 0xff, 0xfe, 0x00, 0x17, 0x74, 0xf9,
            0x12, 0x03,
        ];

        for data_len in 0..=unmasked.len() {
            let unmasked = &unmasked[0..data_len];
            // Check masking with different alignment.
            for off in 0..=3 {
                if unmasked.len() < off {
                    continue;
                }
                let mut masked = unmasked.to_vec();
                apply_mask_fallback(&mut masked[off..], mask);

                let mut masked_fast = unmasked.to_vec();
                apply_mask_fast32(&mut masked_fast[off..], mask);

                assert_eq!(masked, masked_fast);
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate winapi;

use std::{env, mem};
use std::os::windows::io::AsRawHandle;
use std::path::PathBuf;
use std::process::{Child, Command, abort, exit};

use self::winapi::ctypes::c_void;
use self::winapi::shared::minwindef::{BOOL, DWORD, LPVOID, TRUE};
use self::winapi::um::consoleapi::SetConsoleCtrlHandler;
use self::winapi::um::jobapi2::{
    AssignProcessToJobObject, CreateJobObjectW, QueryInformationJobObject,
    SetInformationJobObject};
use self::winapi::um::wincon::{CTRL_C_EVENT, GenerateConsoleCtrlEvent};
use self::winapi::um::winnt::{
    JOBOBJECT_EXTENDED_LIMIT_INFORMATION,
    JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK,
    JobObjectExtendedLimitInformation};

static mut PID: u32 = 0;

unsafe extern "system" fn handle_ctrl(etype: DWORD) -> BOOL {
    if etype == CTRL_C_EVENT && PID != 0 {
        GenerateConsoleCtrlEvent(PID, CTRL_C_EVENT);
    }
    TRUE
}

unsafe fn setup_child(child: &mut Child) -> Result<(), &'static str> {
    PID = child.id();

    let job = CreateJobObjectW(0 as *mut _, 0 as *const _);
    let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION = mem::zeroed();

    let mut ok;

    ok = QueryInformationJobObject(
        job, JobObjectExtendedLimitInformation,
        &mut info as *mut _ as LPVOID,
        mem::size_of_val(&info) as DWORD,
        0 as *mut _,
    );
    if ok != TRUE {
        return Err("job information query error");
    }

    info.BasicLimitInformation.LimitFlags =
        info.BasicLimitInformation.LimitFlags |
        JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE |
        JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
    ok = SetInformationJobObject(
        job, JobObjectExtendedLimitInformation,
        &mut info as *mut _ as LPVOID,
        mem::size_of_val(&info) as DWORD,
    );
    if ok != TRUE {
        return Err("job information set error");
    }

    AssignProcessToJobObject(job, child.as_raw_handle() as *mut c_void);

    Ok(())
}

pub fn run(exe: PathBuf, args: Vec<&str>, with_own_args: bool)
        -> Result<i32, String> {

    let mut cmd = Command::new(exe);
    cmd.args(&args);

    // Hand over arguments passed to the shim (args[0] not included).
    if with_own_args {
        cmd.args(env::args().skip(1));
    }

    let mut child = try!(cmd.spawn().map_err(|e| {
        format!("failed to spawn child: {}", e)
    }));

    unsafe { try!(setup_child(&mut child)) };

    let result = try!(child.wait().map_err(|e| {
        format!("failed to wait for child: {}", e)
    }));

    // Doc seems to suggest this won't happen on Windows, but I'm not sure.
    // 137 is a common value seen with SIGKILL terminated programs.
    Ok(result.code().unwrap_or(137))
}

pub fn run_and_end(exe: PathBuf, args: Vec<&str>, own_args: bool) {
    let code = run(exe, args, own_args).unwrap_or_else(|e| {
        eprintln!("{}", e);
        abort();
    });
    exit(code);
    // Won't reach here.
}

pub fn setup() -> Result<(), &'static str> {
    unsafe {
        let ok = SetConsoleCtrlHandler(Some(handle_ctrl), TRUE);
        if ok == TRUE {
            Ok(())
        } else {
            Err("control handler set error")
        }
    }
}
<commit_msg>Make unsafe block more specific<commit_after>extern crate winapi;

use std::{env, mem};
use std::os::windows::io::AsRawHandle;
use std::path::PathBuf;
use std::process::{Child, Command, abort, exit};

use self::winapi::ctypes::c_void;
use self::winapi::shared::minwindef::{BOOL, DWORD, LPVOID, TRUE};
use self::winapi::um::consoleapi::SetConsoleCtrlHandler;
use self::winapi::um::jobapi2::{
    AssignProcessToJobObject, CreateJobObjectW, QueryInformationJobObject,
    SetInformationJobObject};
use self::winapi::um::wincon::{CTRL_C_EVENT, GenerateConsoleCtrlEvent};
use self::winapi::um::winnt::{
    JOBOBJECT_EXTENDED_LIMIT_INFORMATION,
    JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK,
    JobObjectExtendedLimitInformation};

static mut PID: u32 = 0;

unsafe extern "system" fn handle_ctrl(etype: DWORD) -> BOOL {
    if etype == CTRL_C_EVENT && PID != 0 {
        GenerateConsoleCtrlEvent(PID, CTRL_C_EVENT);
    }
    TRUE
}

unsafe fn setup_child(child: &mut Child) -> Result<(), &'static str> {
    PID = child.id();

    let job = CreateJobObjectW(0 as *mut _, 0 as *const _);
    let mut info: JOBOBJECT_EXTENDED_LIMIT_INFORMATION = mem::zeroed();

    let mut ok;

    ok = QueryInformationJobObject(
        job, JobObjectExtendedLimitInformation,
        &mut info as *mut _ as LPVOID,
        mem::size_of_val(&info) as DWORD,
        0 as *mut _,
    );
    if ok != TRUE {
        return Err("job information query error");
    }

    info.BasicLimitInformation.LimitFlags =
        info.BasicLimitInformation.LimitFlags |
        JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE |
        JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK;
    ok = SetInformationJobObject(
        job, JobObjectExtendedLimitInformation,
        &mut info as *mut _ as LPVOID,
        mem::size_of_val(&info) as DWORD,
    );
    if ok != TRUE {
        return Err("job information set error");
    }

    AssignProcessToJobObject(job, child.as_raw_handle() as *mut c_void);

    Ok(())
}

pub fn run(exe: PathBuf, args: Vec<&str>, with_own_args: bool)
        -> Result<i32, String> {

    let mut cmd = Command::new(exe);
    cmd.args(&args);

    // Hand over arguments passed to the shim (args[0] not included).
    if with_own_args {
        cmd.args(env::args().skip(1));
    }

    let mut child = try!(cmd.spawn().map_err(|e| {
        format!("failed to spawn child: {}", e)
    }));

    unsafe { try!(setup_child(&mut child)) };

    let result = try!(child.wait().map_err(|e| {
        format!("failed to wait for child: {}", e)
    }));

    // Doc seems to suggest this won't happen on Windows, but I'm not sure.
    // 137 is a common value seen with SIGKILL terminated programs.
    Ok(result.code().unwrap_or(137))
}

pub fn run_and_end(exe: PathBuf, args: Vec<&str>, own_args: bool) {
    let code = run(exe, args, own_args).unwrap_or_else(|e| {
        eprintln!("{}", e);
        abort();
    });
    exit(code);
    // Won't reach here.
}

pub fn setup() -> Result<(), &'static str> {
    let ok = unsafe { SetConsoleCtrlHandler(Some(handle_ctrl), TRUE) };
    if ok == TRUE {
        Ok(())
    } else {
        Err("control handler set error")
    }
}
<|endoftext|>


<commit_before>use rustc_middle::mir;

use crate::*;
use helpers::check_arg_count;
use shims::posix::fs::EvalContextExt as _;
use shims::posix::thread::EvalContextExt as _;

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn emulate_foreign_item_by_name(
        &mut self,
        link_name: &str,
        args: &[OpTy<'tcx, Tag>],
        dest: PlaceTy<'tcx, Tag>,
        _ret: mir::BasicBlock,
    ) -> InterpResult<'tcx, bool> {
        let this = self.eval_context_mut();

        match link_name {
            // errno
            "__error" => {
                let &[] = check_arg_count(args)?;
                let errno_place = this.last_error_place()?;
                this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?;
            }

            // File related shims
            "close$NOCANCEL" => {
                let &[result] = check_arg_count(args)?;
                let result = this.close(result)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }
            "stat$INODE64" => {
                let &[path, buf] = check_arg_count(args)?;
                let result = this.macos_stat(path, buf)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }
            "lstat$INODE64" => {
                let &[path, buf] = check_arg_count(args)?;
                let result = this.macos_lstat(path, buf)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }
            "fstat$INODE64" => {
                let &[fd, buf] = check_arg_count(args)?;
                let result = this.macos_fstat(fd, buf)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }
            "opendir$INODE64" => {
                let &[name] = check_arg_count(args)?;
                let result = this.opendir(name)?;
                this.write_scalar(result, dest)?;
            }
            "readdir_r$INODE64" => {
                let &[dirp, entry, result] = check_arg_count(args)?;
                let result = this.macos_readdir_r(dirp, entry, result)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }
            "ftruncate" => {
                let &[fd, length] = check_arg_count(args)?;
                let result = this.ftruncate64(fd, length)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }

            // Environment related shims
            "_NSGetEnviron" => {
                let &[] = check_arg_count(args)?;
                this.write_scalar(this.machine.env_vars.environ.unwrap().ptr, dest)?;
            }

            // Time related shims
            "gettimeofday" => {
                let &[tv, tz] = check_arg_count(args)?;
                let result = this.gettimeofday(tv, tz)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }
            "mach_absolute_time" => {
                let &[] = check_arg_count(args)?;
                let result = this.mach_absolute_time()?;
                this.write_scalar(Scalar::from_u64(result), dest)?;
            }

            "mach_timebase_info" => {
                let &[info] = check_arg_count(args)?;
                let result = this.mach_timebase_info(info)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            },

            // Access to command-line arguments
            "_NSGetArgc" => {
                let &[] = check_arg_count(args)?;
                this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?;
            }
            "_NSGetArgv" => {
                let &[] = check_arg_count(args)?;
                this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?;
            }

            // Thread-local storage
            "_tlv_atexit" => {
                let &[dtor, data] = check_arg_count(args)?;
                let dtor = this.read_scalar(dtor)?.check_init()?;
                let dtor = this.memory.get_fn(dtor)?.as_instance()?;
                let data = this.read_scalar(data)?.check_init()?;
                let active_thread = this.get_active_thread();
                this.machine.tls.set_macos_thread_dtor(active_thread, dtor, data)?;
            }

            // Querying system information
            "pthread_get_stackaddr_np" => {
                let &[thread] = check_arg_count(args)?;
                this.read_scalar(thread)?.to_machine_usize(this)?;
                let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size());
                this.write_scalar(stack_addr, dest)?;
            }
            "pthread_get_stacksize_np" => {
                let &[thread] = check_arg_count(args)?;
                this.read_scalar(thread)?.to_machine_usize(this)?;
                let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size());
                this.write_scalar(stack_size, dest)?;
            }

            // Threading
            "pthread_setname_np" => {
                let &[name] = check_arg_count(args)?;
                let name = this.read_scalar(name)?.check_init()?;
                this.pthread_setname_np(name)?;
            }

            // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
            // These shims are enabled only when the caller is in the standard library.
            "mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => {
                // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value.
                let &[addr, _, _, _, _, _] = check_arg_count(args)?;
                let addr = this.read_scalar(addr)?.check_init()?;
                this.write_scalar(addr, dest)?;
            }

            _ => throw_unsup_format!("can't call foreign function: {}", link_name),
        };

        Ok(true)
    }
}

<commit_msg>macos: support aarch64 link names<commit_after>use rustc_middle::mir;

use crate::*;
use helpers::check_arg_count;
use shims::posix::fs::EvalContextExt as _;
use shims::posix::thread::EvalContextExt as _;

impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {}
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> {
    fn emulate_foreign_item_by_name(
        &mut self,
        link_name: &str,
        args: &[OpTy<'tcx, Tag>],
        dest: PlaceTy<'tcx, Tag>,
        _ret: mir::BasicBlock,
    ) -> InterpResult<'tcx, bool> {
        let this = self.eval_context_mut();

        match link_name {
            // errno
            "__error" => {
                let &[] = check_arg_count(args)?;
                let errno_place = this.last_error_place()?;
                this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?;
            }

            // File related shims
            "close" | "close$NOCANCEL" => {
                let &[result] = check_arg_count(args)?;
                let result = this.close(result)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }
            "stat" | "stat$INODE64" => {
                let &[path, buf] = check_arg_count(args)?;
                let result = this.macos_stat(path, buf)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }
            "lstat" | "lstat$INODE64" => {
                let &[path, buf] = check_arg_count(args)?;
                let result = this.macos_lstat(path, buf)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }
            "fstat" | "fstat$INODE64" => {
                let &[fd, buf] = check_arg_count(args)?;
                let result = this.macos_fstat(fd, buf)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }
            "opendir" | "opendir$INODE64" => {
                let &[name] = check_arg_count(args)?;
                let result = this.opendir(name)?;
                this.write_scalar(result, dest)?;
            }
            "readdir_r" | "readdir_r$INODE64" => {
                let &[dirp, entry, result] = check_arg_count(args)?;
                let result = this.macos_readdir_r(dirp, entry, result)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }
            "ftruncate" => {
                let &[fd, length] = check_arg_count(args)?;
                let result = this.ftruncate64(fd, length)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }

            // Environment related shims
            "_NSGetEnviron" => {
                let &[] = check_arg_count(args)?;
                this.write_scalar(this.machine.env_vars.environ.unwrap().ptr, dest)?;
            }

            // Time related shims
            "gettimeofday" => {
                let &[tv, tz] = check_arg_count(args)?;
                let result = this.gettimeofday(tv, tz)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            }
            "mach_absolute_time" => {
                let &[] = check_arg_count(args)?;
                let result = this.mach_absolute_time()?;
                this.write_scalar(Scalar::from_u64(result), dest)?;
            }

            "mach_timebase_info" => {
                let &[info] = check_arg_count(args)?;
                let result = this.mach_timebase_info(info)?;
                this.write_scalar(Scalar::from_i32(result), dest)?;
            },

            // Access to command-line arguments
            "_NSGetArgc" => {
                let &[] = check_arg_count(args)?;
                this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?;
            }
            "_NSGetArgv" => {
                let &[] = check_arg_count(args)?;
                this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?;
            }

            // Thread-local storage
            "_tlv_atexit" => {
                let &[dtor, data] = check_arg_count(args)?;
                let dtor = this.read_scalar(dtor)?.check_init()?;
                let dtor = this.memory.get_fn(dtor)?.as_instance()?;
                let data = this.read_scalar(data)?.check_init()?;
                let active_thread = this.get_active_thread();
                this.machine.tls.set_macos_thread_dtor(active_thread, dtor, data)?;
            }

            // Querying system information
            "pthread_get_stackaddr_np" => {
                let &[thread] = check_arg_count(args)?;
                this.read_scalar(thread)?.to_machine_usize(this)?;
                let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size());
                this.write_scalar(stack_addr, dest)?;
            }
            "pthread_get_stacksize_np" => {
                let &[thread] = check_arg_count(args)?;
                this.read_scalar(thread)?.to_machine_usize(this)?;
                let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size());
                this.write_scalar(stack_size, dest)?;
            }

            // Threading
            "pthread_setname_np" => {
                let &[name] = check_arg_count(args)?;
                let name = this.read_scalar(name)?.check_init()?;
                this.pthread_setname_np(name)?;
            }

            // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
            // These shims are enabled only when the caller is in the standard library.
            "mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => {
                // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value.
                let &[addr, _, _, _, _, _] = check_arg_count(args)?;
                let addr = this.read_scalar(addr)?.check_init()?;
                this.write_scalar(addr, dest)?;
            }

            _ => throw_unsup_format!("can't call foreign function: {}", link_name),
        };

        Ok(true)
    }
}

<|endoftext|>


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

//! Provides implementations of the AEAD primitive.
//!
//! AEAD encryption assures the confidentiality and authenticity of the data. This primitive is CPA
//! secure.

#![deny(broken_intra_doc_links)]

use std::sync::Once;
use tink_core::registry::register_key_manager;

mod aead_factory;
pub use aead_factory::*;
mod aead_key_templates;
pub use aead_key_templates::*;
mod aes_ctr_hmac_aead_key_manager;
pub use aes_ctr_hmac_aead_key_manager::*;
mod aes_gcm_key_manager;
pub use aes_gcm_key_manager::*;
mod aes_gcm_siv_key_manager;
pub use aes_gcm_siv_key_manager::*;
mod chacha20poly1305_key_manager;
pub use chacha20poly1305_key_manager::*;
mod kms_envelope_aead;
pub use kms_envelope_aead::*;
mod kms_envelope_aead_key_manager;
pub use kms_envelope_aead_key_manager::*;
mod xchacha20poly1305_key_manager;
pub use xchacha20poly1305_key_manager::*;

pub mod subtle;

/// The [upstream Tink](https://github.com/google/tink) version that this Rust
/// port is based on.
pub const UPSTREAM_VERSION: &str = "1.6.0";

static INIT: Once = Once::new();

/// Initialize the `tink-aead` crate, registering its primitives so they are available via
/// tink-core.
pub fn init() {
    INIT.call_once(|| {
        register_key_manager(std::sync::Arc::new(AesCtrHmacAeadKeyManager::default()))
            .expect("tink_aead::init() failed"); // safe: init
        register_key_manager(std::sync::Arc::new(AesGcmKeyManager::default()))
            .expect("tink_aead::init() failed"); // safe: init
        register_key_manager(std::sync::Arc::new(AesGcmSivKeyManager::default()))
            .expect("tink_aead::init() failed"); // safe: init
        register_key_manager(std::sync::Arc::new(ChaCha20Poly1305KeyManager::default()))
            .expect("tink_aead::init() failed"); // safe: init
        register_key_manager(std::sync::Arc::new(XChaCha20Poly1305KeyManager::default()))
            .expect("tink_aead::init() failed"); // safe: init
        register_key_manager(std::sync::Arc::new(KmsEnvelopeAeadKeyManager::default()))
            .expect("tink_aead::init() failed"); // safe:init

        tink_core::registry::register_template_generator("AES128_GCM", aes128_gcm_key_template);
        tink_core::registry::register_template_generator("AES256_GCM", aes256_gcm_key_template);
        tink_core::registry::register_template_generator(
            "AES128_GCM_SIV",
            aes128_gcm_siv_key_template,
        );
        tink_core::registry::register_template_generator(
            "AES256_GCM_SIV",
            aes256_gcm_siv_key_template,
        );
        tink_core::registry::register_template_generator(
            "AES128_CTR_HMAC_SHA256",
            aes128_ctr_hmac_sha256_key_template,
        );
        tink_core::registry::register_template_generator(
            "AES256_CTR_HMAC_SHA256",
            aes256_ctr_hmac_sha256_key_template,
        );
        tink_core::registry::register_template_generator(
            "CHACHA20_POLY1305",
            cha_cha20_poly1305_key_template,
        );
        tink_core::registry::register_template_generator(
            "XCHACHA20_POLY1305",
            x_cha_cha20_poly1305_key_template,
        );
    });
}
<commit_msg>tink-aead: register extra key templates<commit_after>// Copyright 2020 The Tink-Rust Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////

//! Provides implementations of the AEAD primitive.
//!
//! AEAD encryption assures the confidentiality and authenticity of the data. This primitive is CPA
//! secure.

#![deny(broken_intra_doc_links)]

use std::sync::Once;
use tink_core::registry::register_key_manager;

mod aead_factory;
pub use aead_factory::*;
mod aead_key_templates;
pub use aead_key_templates::*;
mod aes_ctr_hmac_aead_key_manager;
pub use aes_ctr_hmac_aead_key_manager::*;
mod aes_gcm_key_manager;
pub use aes_gcm_key_manager::*;
mod aes_gcm_siv_key_manager;
pub use aes_gcm_siv_key_manager::*;
mod chacha20poly1305_key_manager;
pub use chacha20poly1305_key_manager::*;
mod kms_envelope_aead;
pub use kms_envelope_aead::*;
mod kms_envelope_aead_key_manager;
pub use kms_envelope_aead_key_manager::*;
mod xchacha20poly1305_key_manager;
pub use xchacha20poly1305_key_manager::*;

pub mod subtle;

/// The [upstream Tink](https://github.com/google/tink) version that this Rust
/// port is based on.
pub const UPSTREAM_VERSION: &str = "1.6.0";

static INIT: Once = Once::new();

/// Initialize the `tink-aead` crate, registering its primitives so they are available via
/// tink-core.
pub fn init() {
    INIT.call_once(|| {
        register_key_manager(std::sync::Arc::new(AesCtrHmacAeadKeyManager::default()))
            .expect("tink_aead::init() failed"); // safe: init
        register_key_manager(std::sync::Arc::new(AesGcmKeyManager::default()))
            .expect("tink_aead::init() failed"); // safe: init
        register_key_manager(std::sync::Arc::new(AesGcmSivKeyManager::default()))
            .expect("tink_aead::init() failed"); // safe: init
        register_key_manager(std::sync::Arc::new(ChaCha20Poly1305KeyManager::default()))
            .expect("tink_aead::init() failed"); // safe: init
        register_key_manager(std::sync::Arc::new(XChaCha20Poly1305KeyManager::default()))
            .expect("tink_aead::init() failed"); // safe: init
        register_key_manager(std::sync::Arc::new(KmsEnvelopeAeadKeyManager::default()))
            .expect("tink_aead::init() failed"); // safe:init

        tink_core::registry::register_template_generator("AES128_GCM", aes128_gcm_key_template);
        tink_core::registry::register_template_generator("AES256_GCM", aes256_gcm_key_template);
        tink_core::registry::register_template_generator(
            "AES256_GCM_NO_PREFIX",
            aes256_gcm_no_prefix_key_template,
        );
        tink_core::registry::register_template_generator(
            "AES128_GCM_SIV",
            aes128_gcm_siv_key_template,
        );
        tink_core::registry::register_template_generator(
            "AES256_GCM_SIV",
            aes256_gcm_siv_key_template,
        );
        tink_core::registry::register_template_generator(
            "AES256_GCM_SIV_NO_PREFIX",
            aes256_gcm_siv_no_prefix_key_template,
        );
        tink_core::registry::register_template_generator(
            "AES128_CTR_HMAC_SHA256",
            aes128_ctr_hmac_sha256_key_template,
        );
        tink_core::registry::register_template_generator(
            "AES256_CTR_HMAC_SHA256",
            aes256_ctr_hmac_sha256_key_template,
        );
        tink_core::registry::register_template_generator(
            "CHACHA20_POLY1305",
            cha_cha20_poly1305_key_template,
        );
        tink_core::registry::register_template_generator(
            "XCHACHA20_POLY1305",
            x_cha_cha20_poly1305_key_template,
        );
    });
}
<|endoftext|>