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

use super::binary;
use super::client::Client;
use super::connection::{self, Connection, ConnectionId};
use super::ipv4_header::IPv4Header;
use super::ipv4_packet::{IPv4Packet, MAX_PACKET_LENGTH};
use super::packetizer::Packetizer;
use super::selector::Selector;
use super::stream_buffer::StreamBuffer;
use super::tcp_header::{self, TCPHeader};
use super::transport_header::{TransportHeader, TransportHeaderMut};

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

const MAX_PAYLOAD_LENGTH: u16 = 1400;

pub struct TCPConnection {
    id: ConnectionId,
    client: Weak<RefCell<Client>>,
    stream: TcpStream,
    token: Token,
    client_to_network: StreamBuffer,
    network_to_client: Packetizer,
    packet_for_client_length: Option<u16>,
    closed: bool,
    tcb: TCB,
}

struct TCB {
    state: TCPState,
    syn_sequence_number: u32,
    sequence_number: u32,
    acknowledgement_number: u32,
    their_acknowledgement_number: u32,
    client_window: u16,
    remote_closed: bool,
}

#[derive(PartialEq, Eq)]
enum TCPState {
    Init,
    SynSent,
//    SynReceived,
    Established,
    CloseWait,
    LastAck,
}

impl TCB {
    fn new() -> Self {
        Self {
            state: TCPState::Init,
            syn_sequence_number: 0,
            sequence_number: 0,
            acknowledgement_number: 0,
            their_acknowledgement_number: 0,
            client_window: 0,
            remote_closed: false,
        }
    }

    fn numbers(&self) -> String {
        format!("(seq={}, ack={})", self.sequence_number, self.acknowledgement_number)
    }
}

impl TCPConnection {
    pub fn new(selector: &mut Selector, id: ConnectionId, client: Weak<RefCell<Client>>, ipv4_header: &IPv4Header, transport_header: &TransportHeader) -> io::Result<Rc<RefCell<Self>>> {
        let stream = TCPConnection::create_stream(&id)?;

        if let TransportHeader::TCP(ref tcp_header) = *transport_header {
            // shrink the TCP options to pass a minimal refrence header to the packetizer
            let mut shrinked_tcp_header_raw = [0u8; 20];
            shrinked_tcp_header_raw.copy_from_slice(&tcp_header.raw()[..20]);
            let mut shrinked_tcp_header_data = tcp_header.data().clone();
            {
                let mut shrinked_tcp_header = shrinked_tcp_header_data.bind_mut(&mut shrinked_tcp_header_raw);
                shrinked_tcp_header.shrink_options();
                assert_eq!(20, shrinked_tcp_header.header_length());
            }

            let shrinked_transport_header = shrinked_tcp_header_data.bind(&shrinked_tcp_header_raw).into();

            let packetizer = Packetizer::new(&ipv4_header, &shrinked_transport_header);

            let rc = Rc::new(RefCell::new(Self {
                id: id,
                client: client,
                stream: stream,
                token: Token(0), // default value, will be set afterwards
                client_to_network: StreamBuffer::new(4 * MAX_PACKET_LENGTH),
                network_to_client: packetizer,
                packet_for_client_length: None,
                closed: false,
                tcb: TCB::new(),
            }));

            {
                let rc_clone = rc.clone();
                let handler = move |selector: &mut Selector, ready| {
                    let mut self_ref = rc_clone.borrow_mut();
                    self_ref.on_ready(selector, ready);
                };
                let mut self_ref = rc.borrow_mut();
                let token = selector.register(&self_ref.stream, handler, Ready::readable(), PollOpt::level())?;
                self_ref.token = token;
            }
            Ok(rc)
        } else {
            panic!("Not a TCP header");
        }
    }

    fn create_stream(id: &ConnectionId) -> io::Result<TcpStream> {
        let rewritten_destination = connection::rewritten_destination(id.destination_ip(), id.destination_port()).into();
        TcpStream::connect(&rewritten_destination)
    }

    fn close(&mut self, selector: &mut Selector) {

    }

    fn process_send(&mut self, selector: &mut Selector) {
        match self.client_to_network.write_to(&mut self.stream) {
            Ok(w) => if w == 0 {
                self.close(selector);
            },
            Err(err) => {
                error!(target: TAG, "{} Cannot write: {}", self.id, err);
                self.reset_connection(selector);
            }
        }
    }

    fn process_receive(&mut self, selector: &mut Selector) {
        assert!(self.packet_for_client_length.is_none(), "A pending packet was not sent");
        let remaining_client_window = self.get_remaining_client_window();
        assert!(remaining_client_window > 0, "process_received() must not be called when window == 0");
        let max_payload_length = cmp::min(remaining_client_window, MAX_PAYLOAD_LENGTH) as usize;
        TCPConnection::update_headers(&mut self.network_to_client, &self.tcb, tcp_header::FLAG_ACK | tcp_header::FLAG_PSH);
        // the packet is bound to the lifetime of self, so we cannot borrow self to call methods
        // defer the other branches in a separate match-block
        let non_lexical_lifetime_workaround = match self.network_to_client.packetize_read(&mut self.stream, Some(max_payload_length)) {
            Ok(Some(ipv4_packet)) => {
                // TODO send packet
                Ok(Some(()))
            },
            Ok(None) => Ok(None),
            Err(err) => Err(err),
        };
        match non_lexical_lifetime_workaround {
            Ok(None) => self.eof(selector),
            Err(err) => {
                error!(target: TAG, "{} Cannot read: {}", self.id, err);
                self.reset_connection(selector);
            },
            Ok(Some(_)) => () // already handled
        }
        // TODO
    }

    fn send_to_client(client: &Weak<RefCell<Client>>, selector: &mut Selector, ipv4_packet: &IPv4Packet) -> io::Result<()> {
        let client_rc = client.upgrade().expect("expected client not found");
        let mut client = client_rc.borrow_mut();
        client.send_to_client(selector, &ipv4_packet)
    }

    fn eof(&mut self, selector: &mut Selector) {
        self.tcb.remote_closed = true;
        if self.tcb.state == TCPState::CloseWait {
            let ipv4_packet = TCPConnection::create_empty_response_packet(&self.id, &mut self.network_to_client, &self.tcb, tcp_header::FLAG_FIN);
            self.tcb.sequence_number += 1; // FIN counts for 1 byte

            if let Err(err) = TCPConnection::send_to_client(&self.client, selector, &ipv4_packet) {
                warn!(target: TAG, "{} Cannot send packet to client: {}", &self.id, err);
            }
        }
    }

    fn update_headers(packetizer: &mut Packetizer, tcb: &TCB, flags: u16) {
        if let TransportHeaderMut::TCP(ref mut tcp_header) = packetizer.transport_header_mut() {
            tcp_header.set_sequence_number(tcb.sequence_number);
            tcp_header.set_acknowledgement_number(tcb.acknowledgement_number);
            tcp_header.set_flags(flags);
        } else {
            panic!("Not a TCP header");
        }
    }

    fn create_empty_response_packet<'a>(id: &ConnectionId, packetizer: &'a mut Packetizer, tcb: &TCB, flags: u16) -> IPv4Packet<'a> {
        TCPConnection::update_headers(packetizer, tcb, flags);
        debug!(target: TAG, "{} Forging empty response (flags={}) {}", id, flags, tcb.numbers());
        if (flags & tcp_header::FLAG_ACK) != 0 {
            debug!(target: TAG, "{} Acking {}", id, tcb.numbers());
        }
        let ipv4_packet = packetizer.packetize_empty_payload();
        if log_enabled!(target: TAG, LogLevel::Trace) {
            binary::to_string(ipv4_packet.raw());
        }
        ipv4_packet
    }

    fn reset_connection(&mut self, selector: &mut Selector) {
        // TODO
    }

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

    fn may_read(&self) -> bool {
        !self.tcb.remote_closed &&
                self.packet_for_client_length.is_some() &&
                self.get_remaining_client_window() > 0
    }

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

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

    fn get_remaining_client_window(&self) -> u16 {
        // TODO
        42
    }
}

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

    fn send_to_network(&mut self, selector: &mut Selector, ipv4_packet: &IPv4Packet) {
        // TODO
    }

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

    fn is_expired(&self) -> bool {
        // no external timeout expiration
        false
    }
}
<commit_msg>Send packet to client on process_receive()<commit_after>use std::cell::RefCell;
use std::cmp;
use std::io;
use std::net::{Ipv4Addr, SocketAddr};
use std::rc::{Rc, Weak};
use log::LogLevel;
use mio::{Event, PollOpt, Ready, Token};
use mio::net::TcpStream;

use super::binary;
use super::client::Client;
use super::connection::{self, Connection, ConnectionId};
use super::ipv4_header::IPv4Header;
use super::ipv4_packet::{IPv4Packet, MAX_PACKET_LENGTH};
use super::packetizer::Packetizer;
use super::selector::Selector;
use super::stream_buffer::StreamBuffer;
use super::tcp_header::{self, TCPHeader};
use super::transport_header::{TransportHeader, TransportHeaderMut};

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

const MAX_PAYLOAD_LENGTH: u16 = 1400;

pub struct TCPConnection {
    id: ConnectionId,
    client: Weak<RefCell<Client>>,
    stream: TcpStream,
    token: Token,
    client_to_network: StreamBuffer,
    network_to_client: Packetizer,
    packet_for_client_length: Option<u16>,
    closed: bool,
    tcb: TCB,
}

struct TCB {
    state: TCPState,
    syn_sequence_number: u32,
    sequence_number: u32,
    acknowledgement_number: u32,
    their_acknowledgement_number: u32,
    client_window: u16,
    remote_closed: bool,
}

#[derive(PartialEq, Eq)]
enum TCPState {
    Init,
    SynSent,
//    SynReceived,
    Established,
    CloseWait,
    LastAck,
}

impl TCB {
    fn new() -> Self {
        Self {
            state: TCPState::Init,
            syn_sequence_number: 0,
            sequence_number: 0,
            acknowledgement_number: 0,
            their_acknowledgement_number: 0,
            client_window: 0,
            remote_closed: false,
        }
    }

    fn numbers(&self) -> String {
        format!("(seq={}, ack={})", self.sequence_number, self.acknowledgement_number)
    }
}

impl TCPConnection {
    pub fn new(selector: &mut Selector, id: ConnectionId, client: Weak<RefCell<Client>>, ipv4_header: &IPv4Header, transport_header: &TransportHeader) -> io::Result<Rc<RefCell<Self>>> {
        let stream = TCPConnection::create_stream(&id)?;

        if let TransportHeader::TCP(ref tcp_header) = *transport_header {
            // shrink the TCP options to pass a minimal refrence header to the packetizer
            let mut shrinked_tcp_header_raw = [0u8; 20];
            shrinked_tcp_header_raw.copy_from_slice(&tcp_header.raw()[..20]);
            let mut shrinked_tcp_header_data = tcp_header.data().clone();
            {
                let mut shrinked_tcp_header = shrinked_tcp_header_data.bind_mut(&mut shrinked_tcp_header_raw);
                shrinked_tcp_header.shrink_options();
                assert_eq!(20, shrinked_tcp_header.header_length());
            }

            let shrinked_transport_header = shrinked_tcp_header_data.bind(&shrinked_tcp_header_raw).into();

            let packetizer = Packetizer::new(&ipv4_header, &shrinked_transport_header);

            let rc = Rc::new(RefCell::new(Self {
                id: id,
                client: client,
                stream: stream,
                token: Token(0), // default value, will be set afterwards
                client_to_network: StreamBuffer::new(4 * MAX_PACKET_LENGTH),
                network_to_client: packetizer,
                packet_for_client_length: None,
                closed: false,
                tcb: TCB::new(),
            }));

            {
                let rc_clone = rc.clone();
                let handler = move |selector: &mut Selector, ready| {
                    let mut self_ref = rc_clone.borrow_mut();
                    self_ref.on_ready(selector, ready);
                };
                let mut self_ref = rc.borrow_mut();
                let token = selector.register(&self_ref.stream, handler, Ready::readable(), PollOpt::level())?;
                self_ref.token = token;
            }
            Ok(rc)
        } else {
            panic!("Not a TCP header");
        }
    }

    fn create_stream(id: &ConnectionId) -> io::Result<TcpStream> {
        let rewritten_destination = connection::rewritten_destination(id.destination_ip(), id.destination_port()).into();
        TcpStream::connect(&rewritten_destination)
    }

    fn close(&mut self, selector: &mut Selector) {

    }

    fn process_send(&mut self, selector: &mut Selector) {
        match self.client_to_network.write_to(&mut self.stream) {
            Ok(w) => if w == 0 {
                self.close(selector);
            },
            Err(err) => {
                error!(target: TAG, "{} Cannot write: {}", self.id, err);
                self.reset_connection(selector);
            }
        }
    }

    fn process_receive(&mut self, selector: &mut Selector) {
        assert!(self.packet_for_client_length.is_none(), "A pending packet was not sent");
        let remaining_client_window = self.get_remaining_client_window();
        assert!(remaining_client_window > 0, "process_received() must not be called when window == 0");
        let max_payload_length = cmp::min(remaining_client_window, MAX_PAYLOAD_LENGTH) as usize;
        TCPConnection::update_headers(&mut self.network_to_client, &self.tcb, tcp_header::FLAG_ACK | tcp_header::FLAG_PSH);
        // the packet is bound to the lifetime of self, so we cannot borrow self to call methods
        // defer the other branches in a separate match-block
        let non_lexical_lifetime_workaround = match self.network_to_client.packetize_read(&mut self.stream, Some(max_payload_length)) {
            Ok(Some(ipv4_packet)) => {
                // TODO packet source pull
                if let Err(err) = TCPConnection::send_to_client(&self.client, selector, &ipv4_packet) {
                    warn!(target: TAG, "{} Cannot send packet to client: {}", &self.id, err);
                }
                Ok(Some(()))
            },
            Ok(None) => Ok(None),
            Err(err) => Err(err),
        };
        match non_lexical_lifetime_workaround {
            Ok(None) => self.eof(selector),
            Err(err) => {
                error!(target: TAG, "{} Cannot read: {}", self.id, err);
                self.reset_connection(selector);
            },
            Ok(Some(_)) => () // already handled
        }
    }

    fn send_to_client(client: &Weak<RefCell<Client>>, selector: &mut Selector, ipv4_packet: &IPv4Packet) -> io::Result<()> {
        let client_rc = client.upgrade().expect("expected client not found");
        let mut client = client_rc.borrow_mut();
        client.send_to_client(selector, &ipv4_packet)
    }

    fn eof(&mut self, selector: &mut Selector) {
        self.tcb.remote_closed = true;
        if self.tcb.state == TCPState::CloseWait {
            let ipv4_packet = TCPConnection::create_empty_response_packet(&self.id, &mut self.network_to_client, &self.tcb, tcp_header::FLAG_FIN);
            self.tcb.sequence_number += 1; // FIN counts for 1 byte

            if let Err(err) = TCPConnection::send_to_client(&self.client, selector, &ipv4_packet) {
                warn!(target: TAG, "{} Cannot send packet to client: {}", &self.id, err);
            }
        }
    }

    fn update_headers(packetizer: &mut Packetizer, tcb: &TCB, flags: u16) {
        if let TransportHeaderMut::TCP(ref mut tcp_header) = packetizer.transport_header_mut() {
            tcp_header.set_sequence_number(tcb.sequence_number);
            tcp_header.set_acknowledgement_number(tcb.acknowledgement_number);
            tcp_header.set_flags(flags);
        } else {
            panic!("Not a TCP header");
        }
    }

    fn create_empty_response_packet<'a>(id: &ConnectionId, packetizer: &'a mut Packetizer, tcb: &TCB, flags: u16) -> IPv4Packet<'a> {
        TCPConnection::update_headers(packetizer, tcb, flags);
        debug!(target: TAG, "{} Forging empty response (flags={}) {}", id, flags, tcb.numbers());
        if (flags & tcp_header::FLAG_ACK) != 0 {
            debug!(target: TAG, "{} Acking {}", id, tcb.numbers());
        }
        let ipv4_packet = packetizer.packetize_empty_payload();
        if log_enabled!(target: TAG, LogLevel::Trace) {
            binary::to_string(ipv4_packet.raw());
        }
        ipv4_packet
    }

    fn reset_connection(&mut self, selector: &mut Selector) {
        // TODO
    }

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

    fn may_read(&self) -> bool {
        !self.tcb.remote_closed &&
                self.packet_for_client_length.is_some() &&
                self.get_remaining_client_window() > 0
    }

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

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

    fn get_remaining_client_window(&self) -> u16 {
        // TODO
        42
    }
}

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

    fn send_to_network(&mut self, selector: &mut Selector, ipv4_packet: &IPv4Packet) {
        // TODO
    }

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

    fn is_expired(&self) -> bool {
        // no external timeout expiration
        false
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Utilities for the implementation of JSAPI proxy handlers.

#![deny(missing_docs)]

use dom::bindings::conversions::is_dom_proxy;
use dom::bindings::utils::delete_property_by_id;
use js::glue::{GetProxyHandler, GetProxyHandlerFamily, SetProxyExtra};
use js::glue::GetProxyExtra;
use js::glue::InvokeGetOwnPropertyDescriptor;
use js::jsapi::{DOMProxyShadowsResult, JSContext, JSObject, JSPROP_GETTER, PropertyDescriptor};
use js::jsapi::{Handle, HandleId, HandleObject, MutableHandle, ObjectOpResult};
use js::jsapi::{JSErrNum, JS_AlreadyHasOwnPropertyById, JS_StrictPropertyStub};
use js::jsapi::{JS_DefinePropertyById, JS_NewObjectWithGivenProto, SetDOMProxyInformation};
use js::jsapi::GetObjectProto;
use js::jsapi::GetStaticPrototype;
use js::jsapi::JS_GetPropertyDescriptorById;
use js::jsapi::MutableHandleObject;
use js::jsval::ObjectValue;
use libc;
use std::{mem, ptr};

static JSPROXYSLOT_EXPANDO: u32 = 0;

/// Determine if this id shadows any existing properties for this proxy.
pub unsafe extern "C" fn shadow_check_callback(cx: *mut JSContext,
                                               object: HandleObject,
                                               id: HandleId)
                                               -> DOMProxyShadowsResult {
    // TODO: support OverrideBuiltins when #12978 is fixed.

    rooted!(in(cx) let mut expando = ptr::null_mut());
    get_expando_object(object, expando.handle_mut());
    if !expando.get().is_null() {
        let mut has_own = false;
        if !JS_AlreadyHasOwnPropertyById(cx, expando.handle(), id, &mut has_own) {
            return DOMProxyShadowsResult::ShadowCheckFailed;
        }

        if has_own {
            return DOMProxyShadowsResult::ShadowsViaDirectExpando;
        }
    }

    // Our expando, if any, didn't shadow, so we're not shadowing at all.
    DOMProxyShadowsResult::DoesntShadow
}

/// Initialize the infrastructure for DOM proxy objects.
pub unsafe fn init() {
    SetDOMProxyInformation(GetProxyHandlerFamily(),
                           JSPROXYSLOT_EXPANDO,
                           Some(shadow_check_callback));
}

/// Invoke the [[GetOwnProperty]] trap (`getOwnPropertyDescriptor`) on `proxy`,
/// with argument `id` and return the result, if it is not `undefined`.
/// Otherwise, walk along the prototype chain to find a property with that
/// name.
pub unsafe extern "C" fn get_property_descriptor(cx: *mut JSContext,
                                                 proxy: HandleObject,
                                                 id: HandleId,
                                                 desc: MutableHandle<PropertyDescriptor>)
                                                 -> bool {
    let handler = GetProxyHandler(proxy.get());
    if !InvokeGetOwnPropertyDescriptor(handler, cx, proxy, id, desc) {
        return false;
    }
    if !desc.obj.is_null() {
        return true;
    }

    rooted!(in(cx) let mut proto = ptr::null_mut());
    if !GetObjectProto(cx, proxy, proto.handle_mut()) {
        // FIXME(#11868) Should assign to desc.obj, desc.get() is a copy.
        desc.get().obj = ptr::null_mut();
        return true;
    }

    JS_GetPropertyDescriptorById(cx, proto.handle(), id, desc)
}

/// Defines an expando on the given `proxy`.
pub unsafe extern "C" fn define_property(cx: *mut JSContext,
                                         proxy: HandleObject,
                                         id: HandleId,
                                         desc: Handle<PropertyDescriptor>,
                                         result: *mut ObjectOpResult)
                                         -> bool {
    // FIXME: Workaround for https://github.com/rust-lang/rfcs/issues/718
    let setter: *const libc::c_void = mem::transmute(desc.get().setter);
    let setter_stub: unsafe extern fn(_, _, _, _, _) -> _ = JS_StrictPropertyStub;
    let setter_stub: *const libc::c_void = mem::transmute(setter_stub);
    if (desc.get().attrs & JSPROP_GETTER) != 0 && setter == setter_stub {
        (*result).code_ = JSErrNum::JSMSG_GETTER_ONLY as ::libc::uintptr_t;
        return true;
    }

    rooted!(in(cx) let mut expando = ptr::null_mut());
    ensure_expando_object(cx, proxy, expando.handle_mut());
    JS_DefinePropertyById(cx, expando.handle(), id, desc, result)
}

/// Deletes an expando off the given `proxy`.
pub unsafe extern "C" fn delete(cx: *mut JSContext,
                                proxy: HandleObject,
                                id: HandleId,
                                bp: *mut ObjectOpResult)
                                -> bool {
    rooted!(in(cx) let mut expando = ptr::null_mut());
    get_expando_object(proxy, expando.handle_mut());
    if expando.is_null() {
        (*bp).code_ = 0 /* OkCode */;
        return true;
    }

    delete_property_by_id(cx, expando.handle(), id, bp)
}

/// Controls whether the Extensible bit can be changed
pub unsafe extern "C" fn prevent_extensions(_cx: *mut JSContext,
                                            _proxy: HandleObject,
                                            result: *mut ObjectOpResult)
                                            -> bool {
    (*result).code_ = JSErrNum::JSMSG_CANT_PREVENT_EXTENSIONS as ::libc::uintptr_t;
    true
}

/// Reports whether the object is Extensible
pub unsafe extern "C" fn is_extensible(_cx: *mut JSContext,
                                       _proxy: HandleObject,
                                       succeeded: *mut bool)
                                       -> bool {
    *succeeded = true;
    true
}

/// If `proxy` (underneath any functionally-transparent wrapper proxies) has as
/// its `[[GetPrototypeOf]]` trap the ordinary `[[GetPrototypeOf]]` behavior
/// defined for ordinary objects, set `*is_ordinary` to true and store `obj`'s
/// prototype in `proto`.  Otherwise set `*isOrdinary` to false. In case of
/// error, both outparams have unspecified value.
///
/// This implementation always handles the case of the ordinary
/// `[[GetPrototypeOf]]` behavior. An alternative implementation will be
/// necessary for the Location object.
pub unsafe extern "C" fn get_prototype_if_ordinary(_: *mut JSContext,
                                                   proxy: HandleObject,
                                                   is_ordinary: *mut bool,
                                                   proto: MutableHandleObject)
                                                   -> bool {
    *is_ordinary = true;
    proto.set(GetStaticPrototype(proxy.get()));
    true
}

/// Get the expando object, or null if there is none.
pub unsafe fn get_expando_object(obj: HandleObject, expando: MutableHandleObject) {
    assert!(is_dom_proxy(obj.get()));
    let val = GetProxyExtra(obj.get(), JSPROXYSLOT_EXPANDO);
    expando.set(if val.is_undefined() {
        ptr::null_mut()
    } else {
        val.to_object()
    });
}

/// Get the expando object, or create it if it doesn't exist yet.
/// Fails on JSAPI failure.
pub unsafe fn ensure_expando_object(cx: *mut JSContext, obj: HandleObject, expando: MutableHandleObject) {
    assert!(is_dom_proxy(obj.get()));
    get_expando_object(obj, expando);
    if expando.is_null() {
        expando.set(JS_NewObjectWithGivenProto(cx, ptr::null_mut(), HandleObject::null()));
        assert!(!expando.is_null());

        SetProxyExtra(obj.get(), JSPROXYSLOT_EXPANDO, &ObjectValue(expando.get()));
    }
}

/// Set the property descriptor's object to `obj` and set it to enumerable,
/// and writable if `readonly` is true.
pub fn fill_property_descriptor(mut desc: MutableHandle<PropertyDescriptor>,
                                obj: *mut JSObject,
                                attrs: u32) {
    desc.obj = obj;
    desc.attrs = attrs;
    desc.getter = None;
    desc.setter = None;
}
<commit_msg>Auto merge of #19082 - Eijebong:fixme_issue_718, r=jdm<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Utilities for the implementation of JSAPI proxy handlers.

#![deny(missing_docs)]

use dom::bindings::conversions::is_dom_proxy;
use dom::bindings::utils::delete_property_by_id;
use js::glue::{GetProxyHandler, GetProxyHandlerFamily, SetProxyExtra};
use js::glue::GetProxyExtra;
use js::glue::InvokeGetOwnPropertyDescriptor;
use js::jsapi::{DOMProxyShadowsResult, JSContext, JSObject, JSPROP_GETTER, PropertyDescriptor};
use js::jsapi::{Handle, HandleId, HandleObject, MutableHandle, ObjectOpResult};
use js::jsapi::{JSErrNum, JS_AlreadyHasOwnPropertyById, JS_StrictPropertyStub};
use js::jsapi::{JS_DefinePropertyById, JS_NewObjectWithGivenProto, SetDOMProxyInformation};
use js::jsapi::GetObjectProto;
use js::jsapi::GetStaticPrototype;
use js::jsapi::JS_GetPropertyDescriptorById;
use js::jsapi::MutableHandleObject;
use js::jsval::ObjectValue;
use std::ptr;

static JSPROXYSLOT_EXPANDO: u32 = 0;

/// Determine if this id shadows any existing properties for this proxy.
pub unsafe extern "C" fn shadow_check_callback(cx: *mut JSContext,
                                               object: HandleObject,
                                               id: HandleId)
                                               -> DOMProxyShadowsResult {
    // TODO: support OverrideBuiltins when #12978 is fixed.

    rooted!(in(cx) let mut expando = ptr::null_mut());
    get_expando_object(object, expando.handle_mut());
    if !expando.get().is_null() {
        let mut has_own = false;
        if !JS_AlreadyHasOwnPropertyById(cx, expando.handle(), id, &mut has_own) {
            return DOMProxyShadowsResult::ShadowCheckFailed;
        }

        if has_own {
            return DOMProxyShadowsResult::ShadowsViaDirectExpando;
        }
    }

    // Our expando, if any, didn't shadow, so we're not shadowing at all.
    DOMProxyShadowsResult::DoesntShadow
}

/// Initialize the infrastructure for DOM proxy objects.
pub unsafe fn init() {
    SetDOMProxyInformation(GetProxyHandlerFamily(),
                           JSPROXYSLOT_EXPANDO,
                           Some(shadow_check_callback));
}

/// Invoke the [[GetOwnProperty]] trap (`getOwnPropertyDescriptor`) on `proxy`,
/// with argument `id` and return the result, if it is not `undefined`.
/// Otherwise, walk along the prototype chain to find a property with that
/// name.
pub unsafe extern "C" fn get_property_descriptor(cx: *mut JSContext,
                                                 proxy: HandleObject,
                                                 id: HandleId,
                                                 desc: MutableHandle<PropertyDescriptor>)
                                                 -> bool {
    let handler = GetProxyHandler(proxy.get());
    if !InvokeGetOwnPropertyDescriptor(handler, cx, proxy, id, desc) {
        return false;
    }
    if !desc.obj.is_null() {
        return true;
    }

    rooted!(in(cx) let mut proto = ptr::null_mut());
    if !GetObjectProto(cx, proxy, proto.handle_mut()) {
        // FIXME(#11868) Should assign to desc.obj, desc.get() is a copy.
        desc.get().obj = ptr::null_mut();
        return true;
    }

    JS_GetPropertyDescriptorById(cx, proto.handle(), id, desc)
}

/// Defines an expando on the given `proxy`.
pub unsafe extern "C" fn define_property(cx: *mut JSContext,
                                         proxy: HandleObject,
                                         id: HandleId,
                                         desc: Handle<PropertyDescriptor>,
                                         result: *mut ObjectOpResult)
                                         -> bool {
    if (desc.get().attrs & JSPROP_GETTER) != 0 && desc.get().setter == Some(JS_StrictPropertyStub) {
        (*result).code_ = JSErrNum::JSMSG_GETTER_ONLY as ::libc::uintptr_t;
        return true;
    }

    rooted!(in(cx) let mut expando = ptr::null_mut());
    ensure_expando_object(cx, proxy, expando.handle_mut());
    JS_DefinePropertyById(cx, expando.handle(), id, desc, result)
}

/// Deletes an expando off the given `proxy`.
pub unsafe extern "C" fn delete(cx: *mut JSContext,
                                proxy: HandleObject,
                                id: HandleId,
                                bp: *mut ObjectOpResult)
                                -> bool {
    rooted!(in(cx) let mut expando = ptr::null_mut());
    get_expando_object(proxy, expando.handle_mut());
    if expando.is_null() {
        (*bp).code_ = 0 /* OkCode */;
        return true;
    }

    delete_property_by_id(cx, expando.handle(), id, bp)
}

/// Controls whether the Extensible bit can be changed
pub unsafe extern "C" fn prevent_extensions(_cx: *mut JSContext,
                                            _proxy: HandleObject,
                                            result: *mut ObjectOpResult)
                                            -> bool {
    (*result).code_ = JSErrNum::JSMSG_CANT_PREVENT_EXTENSIONS as ::libc::uintptr_t;
    true
}

/// Reports whether the object is Extensible
pub unsafe extern "C" fn is_extensible(_cx: *mut JSContext,
                                       _proxy: HandleObject,
                                       succeeded: *mut bool)
                                       -> bool {
    *succeeded = true;
    true
}

/// If `proxy` (underneath any functionally-transparent wrapper proxies) has as
/// its `[[GetPrototypeOf]]` trap the ordinary `[[GetPrototypeOf]]` behavior
/// defined for ordinary objects, set `*is_ordinary` to true and store `obj`'s
/// prototype in `proto`.  Otherwise set `*isOrdinary` to false. In case of
/// error, both outparams have unspecified value.
///
/// This implementation always handles the case of the ordinary
/// `[[GetPrototypeOf]]` behavior. An alternative implementation will be
/// necessary for the Location object.
pub unsafe extern "C" fn get_prototype_if_ordinary(_: *mut JSContext,
                                                   proxy: HandleObject,
                                                   is_ordinary: *mut bool,
                                                   proto: MutableHandleObject)
                                                   -> bool {
    *is_ordinary = true;
    proto.set(GetStaticPrototype(proxy.get()));
    true
}

/// Get the expando object, or null if there is none.
pub unsafe fn get_expando_object(obj: HandleObject, expando: MutableHandleObject) {
    assert!(is_dom_proxy(obj.get()));
    let val = GetProxyExtra(obj.get(), JSPROXYSLOT_EXPANDO);
    expando.set(if val.is_undefined() {
        ptr::null_mut()
    } else {
        val.to_object()
    });
}

/// Get the expando object, or create it if it doesn't exist yet.
/// Fails on JSAPI failure.
pub unsafe fn ensure_expando_object(cx: *mut JSContext, obj: HandleObject, expando: MutableHandleObject) {
    assert!(is_dom_proxy(obj.get()));
    get_expando_object(obj, expando);
    if expando.is_null() {
        expando.set(JS_NewObjectWithGivenProto(cx, ptr::null_mut(), HandleObject::null()));
        assert!(!expando.is_null());

        SetProxyExtra(obj.get(), JSPROXYSLOT_EXPANDO, &ObjectValue(expando.get()));
    }
}

/// Set the property descriptor's object to `obj` and set it to enumerable,
/// and writable if `readonly` is true.
pub fn fill_property_descriptor(mut desc: MutableHandle<PropertyDescriptor>,
                                obj: *mut JSObject,
                                attrs: u32) {
    desc.obj = obj;
    desc.attrs = attrs;
    desc.getter = None;
    desc.setter = None;
}
<|endoftext|>


<commit_before>//! The Rust Prelude.
//!
//! Rust comes with a variety of things in its standard library. However, if
//! you had to manually import every single thing that you used, it would be
//! very verbose. But importing a lot of things that a program never uses isn't
//! good either. A balance needs to be struck.
//!
//! The *prelude* is the list of things that Rust automatically imports into
//! every Rust program. It's kept as small as possible, and is focused on
//! things, particularly traits, which are used in almost every single Rust
//! program.
//!
//! # Other preludes
//!
//! Preludes can be seen as a pattern to make using multiple types more
//! convenient. As such, you'll find other preludes in the standard library,
//! such as [`std::io::prelude`]. Various libraries in the Rust ecosystem may
//! also define their own preludes.
//!
//! [`std::io::prelude`]: crate::io::prelude
//!
//! The difference between 'the prelude' and these other preludes is that they
//! are not automatically `use`'d, and must be imported manually. This is still
//! easier than importing all of their constituent components.
//!
//! # Prelude contents
//!
//! The current version of the prelude (version 1) lives in
//! [`std::prelude::v1`], and re-exports the following.
//!
//! * [`std::marker`]::{[`Copy`], [`Send`], [`Sized`], [`Sync`], [`Unpin`]}. The
//!   marker traits indicate fundamental properties of types.
//! * [`std::ops`]::{[`Drop`], [`Fn`], [`FnMut`], [`FnOnce`]}. Various
//!   operations for both destructors and overloading `()`.
//! * [`std::mem`]::[`drop`][`mem::drop`], a convenience function for explicitly
//!   dropping a value.
//! * [`std::boxed`]::[`Box`], a way to allocate values on the heap.
//! * [`std::borrow`]::[`ToOwned`], The conversion trait that defines
//!   [`to_owned`], the generic method for creating an owned type from a
//!   borrowed type.
//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines
//!   [`clone`][`Clone::clone`], the method for producing a copy of a value.
//! * [`std::cmp`]::{[`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] }. The
//!   comparison traits, which implement the comparison operators and are often
//!   seen in trait bounds.
//! * [`std::convert`]::{[`AsRef`], [`AsMut`], [`Into`], [`From`]}. Generic
//!   conversions, used by savvy API authors to create overloaded methods.
//! * [`std::default`]::[`Default`], types that have default values.
//! * [`std::iter`]::{[`Iterator`], [`Extend`], [`IntoIterator`],
//!   [`DoubleEndedIterator`], [`ExactSizeIterator`]}. Iterators of various
//!   kinds.
//! * [`std::option`]::[`Option`]::{[`self`][`Option`], [`Some`], [`None`]}. A
//!   type which expresses the presence or absence of a value. This type is so
//!   commonly used, its variants are also exported.
//! * [`std::result`]::[`Result`]::{[`self`][`Result`], [`Ok`], [`Err`]}. A type
//!   for functions that may succeed or fail. Like [`Option`], its variants are
//!   exported as well.
//! * [`std::string`]::{[`String`], [`ToString`]}, heap allocated strings.
//! * [`std::vec`]::[`Vec`], a growable, heap-allocated
//!   vector.
//!
//! [`mem::drop`]: crate::mem::drop
//! [`std::borrow`]: crate::borrow
//! [`std::boxed`]: crate::boxed
//! [`std::clone`]: crate::clone
//! [`std::cmp`]: crate::cmp
//! [`std::convert`]: crate::convert
//! [`std::default`]: crate::default
//! [`std::iter`]: crate::iter
//! [`std::marker`]: crate::marker
//! [`std::mem`]: crate::mem
//! [`std::ops`]: crate::ops
//! [`std::option`]: crate::option
//! [`std::prelude::v1`]: v1
//! [`std::result`]: crate::result
//! [`std::slice`]: crate::slice
//! [`std::string`]: crate::string
//! [`std::vec`]: mod@crate::vec
//! [`to_owned`]: crate::borrow::ToOwned::to_owned
//! [book-closures]: ../../book/ch13-01-closures.html
//! [book-dtor]: ../../book/ch15-03-drop.html
//! [book-enums]: ../../book/ch06-01-defining-an-enum.html
//! [book-iter]: ../../book/ch13-02-iterators.html

#![stable(feature = "rust1", since = "1.0.0")]

pub mod v1;
<commit_msg>Edit formatting in Rust Prelude docs<commit_after>//! The Rust Prelude.
//!
//! Rust comes with a variety of things in its standard library. However, if
//! you had to manually import every single thing that you used, it would be
//! very verbose. But importing a lot of things that a program never uses isn't
//! good either. A balance needs to be struck.
//!
//! The *prelude* is the list of things that Rust automatically imports into
//! every Rust program. It's kept as small as possible, and is focused on
//! things, particularly traits, which are used in almost every single Rust
//! program.
//!
//! # Other preludes
//!
//! Preludes can be seen as a pattern to make using multiple types more
//! convenient. As such, you'll find other preludes in the standard library,
//! such as [`std::io::prelude`]. Various libraries in the Rust ecosystem may
//! also define their own preludes.
//!
//! [`std::io::prelude`]: crate::io::prelude
//!
//! The difference between 'the prelude' and these other preludes is that they
//! are not automatically `use`'d, and must be imported manually. This is still
//! easier than importing all of their constituent components.
//!
//! # Prelude contents
//!
//! The current version of the prelude (version 1) lives in
//! [`std::prelude::v1`], and re-exports the following:
//!
//! * [`std::marker`]::{[`Copy`], [`Send`], [`Sized`], [`Sync`], [`Unpin`]},
//!   marker traits that indicate fundamental properties of types.
//! * [`std::ops`]::{[`Drop`], [`Fn`], [`FnMut`], [`FnOnce`]}, various
//!   operations for both destructors and overloading `()`.
//! * [`std::mem`]::[`drop`][`mem::drop`], a convenience function for explicitly
//!   dropping a value.
//! * [`std::boxed`]::[`Box`], a way to allocate values on the heap.
//! * [`std::borrow`]::[`ToOwned`], the conversion trait that defines
//!   [`to_owned`], the generic method for creating an owned type from a
//!   borrowed type.
//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines
//!   [`clone`][`Clone::clone`], the method for producing a copy of a value.
//! * [`std::cmp`]::{[`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] }, the
//!   comparison traits, which implement the comparison operators and are often
//!   seen in trait bounds.
//! * [`std::convert`]::{[`AsRef`], [`AsMut`], [`Into`], [`From`]}, generic
//!   conversions, used by savvy API authors to create overloaded methods.
//! * [`std::default`]::[`Default`], types that have default values.
//! * [`std::iter`]::{[`Iterator`], [`Extend`], [`IntoIterator`]
//!   [`DoubleEndedIterator`], [`ExactSizeIterator`]}, iterators of various
//!   kinds.
//! * [`std::option`]::[`Option`]::{[`self`][`Option`], [`Some`], [`None`]}, a
//!   type which expresses the presence or absence of a value. This type is so
//!   commonly used, its variants are also exported.
//! * [`std::result`]::[`Result`]::{[`self`][`Result`], [`Ok`], [`Err`]}, a type
//!   for functions that may succeed or fail. Like [`Option`], its variants are
//!   exported as well.
//! * [`std::string`]::{[`String`], [`ToString`]}, heap allocated strings.
//! * [`std::vec`]::[`Vec`], a growable, heap-allocated vector.
//!
//! [`mem::drop`]: crate::mem::drop
//! [`std::borrow`]: crate::borrow
//! [`std::boxed`]: crate::boxed
//! [`std::clone`]: crate::clone
//! [`std::cmp`]: crate::cmp
//! [`std::convert`]: crate::convert
//! [`std::default`]: crate::default
//! [`std::iter`]: crate::iter
//! [`std::marker`]: crate::marker
//! [`std::mem`]: crate::mem
//! [`std::ops`]: crate::ops
//! [`std::option`]: crate::option
//! [`std::prelude::v1`]: v1
//! [`std::result`]: crate::result
//! [`std::slice`]: crate::slice
//! [`std::string`]: crate::string
//! [`std::vec`]: mod@crate::vec
//! [`to_owned`]: crate::borrow::ToOwned::to_owned
//! [book-closures]: ../../book/ch13-01-closures.html
//! [book-dtor]: ../../book/ch15-03-drop.html
//! [book-enums]: ../../book/ch06-01-defining-an-enum.html
//! [book-iter]: ../../book/ch13-02-iterators.html

#![stable(feature = "rust1", since = "1.0.0")]

pub mod v1;
<|endoftext|>


<commit_before>#![unstable(reason = "not public", issue = "none", feature = "fd")]

use crate::cmp;
use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read};
use crate::mem;
#[cfg(not(any(target_os = "redox", target_env = "newlib")))]
use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::sys::cvt;
use crate::sys_common::AsInner;

use libc::{c_int, c_void};

#[derive(Debug)]
pub struct FileDesc {
    fd: c_int,
}

// The maximum read limit on most POSIX-like systems is `SSIZE_MAX`,
// with the man page quoting that if the count of bytes to read is
// greater than `SSIZE_MAX` the result is "unspecified".
//
// On macOS, however, apparently the 64-bit libc is either buggy or
// intentionally showing odd behavior by rejecting any read with a size
// larger than or equal to INT_MAX. To handle both of these the read
// size is capped on both platforms.
#[cfg(target_os = "macos")]
const READ_LIMIT: usize = c_int::MAX as usize - 1;
#[cfg(not(target_os = "macos"))]
const READ_LIMIT: usize = libc::ssize_t::MAX as usize;

#[cfg(not(any(target_os = "redox", target_env = "newlib")))]
fn max_iov() -> usize {
    static LIM: AtomicUsize = AtomicUsize::new(0);

    let mut lim = LIM.load(Ordering::Relaxed);
    if lim == 0 {
        let ret = unsafe { libc::sysconf(libc::_SC_IOV_MAX) };

        // 16 is the minimum value required by POSIX.
        lim = if ret > 0 { ret as usize } else { 16 };
        LIM.store(lim, Ordering::Relaxed);
    }

    lim
}

#[cfg(any(target_os = "redox", target_env = "newlib"))]
fn max_iov() -> usize {
    16 // The minimum value required by POSIX.
}

impl FileDesc {
    pub fn new(fd: c_int) -> FileDesc {
        FileDesc { fd }
    }

    pub fn raw(&self) -> c_int {
        self.fd
    }

    /// Extracts the actual file descriptor without closing it.
    pub fn into_raw(self) -> c_int {
        let fd = self.fd;
        mem::forget(self);
        fd
    }

    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT))
        })?;
        Ok(ret as usize)
    }

    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::readv(
                self.fd,
                bufs.as_ptr() as *const libc::iovec,
                cmp::min(bufs.len(), max_iov()) as c_int,
            )
        })?;
        Ok(ret as usize)
    }

    #[inline]
    pub fn is_read_vectored(&self) -> bool {
        true
    }

    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
        let mut me = self;
        (&mut me).read_to_end(buf)
    }

    pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
        #[cfg(target_os = "android")]
        use super::android::cvt_pread64;

        #[cfg(not(target_os = "android"))]
        unsafe fn cvt_pread64(
            fd: c_int,
            buf: *mut c_void,
            count: usize,
            offset: i64,
        ) -> io::Result<isize> {
            #[cfg(not(target_os = "linux"))]
            use libc::pread as pread64;
            #[cfg(target_os = "linux")]
            use libc::pread64;
            cvt(pread64(fd, buf, count, offset))
        }

        unsafe {
            cvt_pread64(
                self.fd,
                buf.as_mut_ptr() as *mut c_void,
                cmp::min(buf.len(), READ_LIMIT),
                offset as i64,
            )
            .map(|n| n as usize)
        }
    }

    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT))
        })?;
        Ok(ret as usize)
    }

    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::writev(
                self.fd,
                bufs.as_ptr() as *const libc::iovec,
                cmp::min(bufs.len(), max_iov()) as c_int,
            )
        })?;
        Ok(ret as usize)
    }

    #[inline]
    pub fn is_write_vectored(&self) -> bool {
        true
    }

    pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
        #[cfg(target_os = "android")]
        use super::android::cvt_pwrite64;

        #[cfg(not(target_os = "android"))]
        unsafe fn cvt_pwrite64(
            fd: c_int,
            buf: *const c_void,
            count: usize,
            offset: i64,
        ) -> io::Result<isize> {
            #[cfg(not(target_os = "linux"))]
            use libc::pwrite as pwrite64;
            #[cfg(target_os = "linux")]
            use libc::pwrite64;
            cvt(pwrite64(fd, buf, count, offset))
        }

        unsafe {
            cvt_pwrite64(
                self.fd,
                buf.as_ptr() as *const c_void,
                cmp::min(buf.len(), READ_LIMIT),
                offset as i64,
            )
            .map(|n| n as usize)
        }
    }

    #[cfg(target_os = "linux")]
    pub fn get_cloexec(&self) -> io::Result<bool> {
        unsafe { Ok((cvt(libc::fcntl(self.fd, libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) }
    }

    #[cfg(not(any(
        target_env = "newlib",
        target_os = "solaris",
        target_os = "illumos",
        target_os = "emscripten",
        target_os = "fuchsia",
        target_os = "l4re",
        target_os = "linux",
        target_os = "haiku",
        target_os = "redox"
    )))]
    pub fn set_cloexec(&self) -> io::Result<()> {
        unsafe {
            cvt(libc::ioctl(self.fd, libc::FIOCLEX))?;
            Ok(())
        }
    }
    #[cfg(any(
        target_env = "newlib",
        target_os = "solaris",
        target_os = "illumos",
        target_os = "emscripten",
        target_os = "fuchsia",
        target_os = "l4re",
        target_os = "linux",
        target_os = "haiku",
        target_os = "redox"
    ))]
    pub fn set_cloexec(&self) -> io::Result<()> {
        unsafe {
            let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?;
            let new = previous | libc::FD_CLOEXEC;
            if new != previous {
                cvt(libc::fcntl(self.fd, libc::F_SETFD, new))?;
            }
            Ok(())
        }
    }

    #[cfg(target_os = "linux")]
    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
        unsafe {
            let v = nonblocking as c_int;
            cvt(libc::ioctl(self.fd, libc::FIONBIO, &v))?;
            Ok(())
        }
    }

    #[cfg(not(target_os = "linux"))]
    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
        unsafe {
            let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL))?;
            let new = if nonblocking {
                previous | libc::O_NONBLOCK
            } else {
                previous & !libc::O_NONBLOCK
            };
            if new != previous {
                cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?;
            }
            Ok(())
        }
    }

    pub fn duplicate(&self) -> io::Result<FileDesc> {
        // We want to atomically duplicate this file descriptor and set the
        // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
        // is a POSIX flag that was added to Linux in 2.6.24.
        let fd = cvt(unsafe { libc::fcntl(self.raw(), libc::F_DUPFD_CLOEXEC, 0) })?;
        Ok(FileDesc::new(fd))
    }
}

impl<'a> Read for &'a FileDesc {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (**self).read(buf)
    }

    #[inline]
    unsafe fn initializer(&self) -> Initializer {
        Initializer::nop()
    }
}

impl AsInner<c_int> for FileDesc {
    fn as_inner(&self) -> &c_int {
        &self.fd
    }
}

impl Drop for FileDesc {
    fn drop(&mut self) {
        // Note that errors are ignored when closing a file descriptor. The
        // reason for this is that if an error occurs we don't actually know if
        // the file descriptor was closed or not, and if we retried (for
        // something like EINTR), we might close another valid file descriptor
        // opened after we closed ours.
        let _ = unsafe { libc::close(self.fd) };
    }
}

#[cfg(test)]
mod tests {
    use super::{FileDesc, IoSlice};

    #[test]
    fn limit_vector_count() {
        let stdout = FileDesc { fd: 1 };
        let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::<Vec<_>>();

        assert!(stdout.write_vectored(&bufs).is_ok());
    }
}
<commit_msg>Keep stdout open in limit_vector_count test<commit_after>#![unstable(reason = "not public", issue = "none", feature = "fd")]

use crate::cmp;
use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read};
use crate::mem;
#[cfg(not(any(target_os = "redox", target_env = "newlib")))]
use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::sys::cvt;
use crate::sys_common::AsInner;

use libc::{c_int, c_void};

#[derive(Debug)]
pub struct FileDesc {
    fd: c_int,
}

// The maximum read limit on most POSIX-like systems is `SSIZE_MAX`,
// with the man page quoting that if the count of bytes to read is
// greater than `SSIZE_MAX` the result is "unspecified".
//
// On macOS, however, apparently the 64-bit libc is either buggy or
// intentionally showing odd behavior by rejecting any read with a size
// larger than or equal to INT_MAX. To handle both of these the read
// size is capped on both platforms.
#[cfg(target_os = "macos")]
const READ_LIMIT: usize = c_int::MAX as usize - 1;
#[cfg(not(target_os = "macos"))]
const READ_LIMIT: usize = libc::ssize_t::MAX as usize;

#[cfg(not(any(target_os = "redox", target_env = "newlib")))]
fn max_iov() -> usize {
    static LIM: AtomicUsize = AtomicUsize::new(0);

    let mut lim = LIM.load(Ordering::Relaxed);
    if lim == 0 {
        let ret = unsafe { libc::sysconf(libc::_SC_IOV_MAX) };

        // 16 is the minimum value required by POSIX.
        lim = if ret > 0 { ret as usize } else { 16 };
        LIM.store(lim, Ordering::Relaxed);
    }

    lim
}

#[cfg(any(target_os = "redox", target_env = "newlib"))]
fn max_iov() -> usize {
    16 // The minimum value required by POSIX.
}

impl FileDesc {
    pub fn new(fd: c_int) -> FileDesc {
        FileDesc { fd }
    }

    pub fn raw(&self) -> c_int {
        self.fd
    }

    /// Extracts the actual file descriptor without closing it.
    pub fn into_raw(self) -> c_int {
        let fd = self.fd;
        mem::forget(self);
        fd
    }

    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT))
        })?;
        Ok(ret as usize)
    }

    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::readv(
                self.fd,
                bufs.as_ptr() as *const libc::iovec,
                cmp::min(bufs.len(), max_iov()) as c_int,
            )
        })?;
        Ok(ret as usize)
    }

    #[inline]
    pub fn is_read_vectored(&self) -> bool {
        true
    }

    pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
        let mut me = self;
        (&mut me).read_to_end(buf)
    }

    pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
        #[cfg(target_os = "android")]
        use super::android::cvt_pread64;

        #[cfg(not(target_os = "android"))]
        unsafe fn cvt_pread64(
            fd: c_int,
            buf: *mut c_void,
            count: usize,
            offset: i64,
        ) -> io::Result<isize> {
            #[cfg(not(target_os = "linux"))]
            use libc::pread as pread64;
            #[cfg(target_os = "linux")]
            use libc::pread64;
            cvt(pread64(fd, buf, count, offset))
        }

        unsafe {
            cvt_pread64(
                self.fd,
                buf.as_mut_ptr() as *mut c_void,
                cmp::min(buf.len(), READ_LIMIT),
                offset as i64,
            )
            .map(|n| n as usize)
        }
    }

    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT))
        })?;
        Ok(ret as usize)
    }

    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
        let ret = cvt(unsafe {
            libc::writev(
                self.fd,
                bufs.as_ptr() as *const libc::iovec,
                cmp::min(bufs.len(), max_iov()) as c_int,
            )
        })?;
        Ok(ret as usize)
    }

    #[inline]
    pub fn is_write_vectored(&self) -> bool {
        true
    }

    pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
        #[cfg(target_os = "android")]
        use super::android::cvt_pwrite64;

        #[cfg(not(target_os = "android"))]
        unsafe fn cvt_pwrite64(
            fd: c_int,
            buf: *const c_void,
            count: usize,
            offset: i64,
        ) -> io::Result<isize> {
            #[cfg(not(target_os = "linux"))]
            use libc::pwrite as pwrite64;
            #[cfg(target_os = "linux")]
            use libc::pwrite64;
            cvt(pwrite64(fd, buf, count, offset))
        }

        unsafe {
            cvt_pwrite64(
                self.fd,
                buf.as_ptr() as *const c_void,
                cmp::min(buf.len(), READ_LIMIT),
                offset as i64,
            )
            .map(|n| n as usize)
        }
    }

    #[cfg(target_os = "linux")]
    pub fn get_cloexec(&self) -> io::Result<bool> {
        unsafe { Ok((cvt(libc::fcntl(self.fd, libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) }
    }

    #[cfg(not(any(
        target_env = "newlib",
        target_os = "solaris",
        target_os = "illumos",
        target_os = "emscripten",
        target_os = "fuchsia",
        target_os = "l4re",
        target_os = "linux",
        target_os = "haiku",
        target_os = "redox"
    )))]
    pub fn set_cloexec(&self) -> io::Result<()> {
        unsafe {
            cvt(libc::ioctl(self.fd, libc::FIOCLEX))?;
            Ok(())
        }
    }
    #[cfg(any(
        target_env = "newlib",
        target_os = "solaris",
        target_os = "illumos",
        target_os = "emscripten",
        target_os = "fuchsia",
        target_os = "l4re",
        target_os = "linux",
        target_os = "haiku",
        target_os = "redox"
    ))]
    pub fn set_cloexec(&self) -> io::Result<()> {
        unsafe {
            let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?;
            let new = previous | libc::FD_CLOEXEC;
            if new != previous {
                cvt(libc::fcntl(self.fd, libc::F_SETFD, new))?;
            }
            Ok(())
        }
    }

    #[cfg(target_os = "linux")]
    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
        unsafe {
            let v = nonblocking as c_int;
            cvt(libc::ioctl(self.fd, libc::FIONBIO, &v))?;
            Ok(())
        }
    }

    #[cfg(not(target_os = "linux"))]
    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
        unsafe {
            let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL))?;
            let new = if nonblocking {
                previous | libc::O_NONBLOCK
            } else {
                previous & !libc::O_NONBLOCK
            };
            if new != previous {
                cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?;
            }
            Ok(())
        }
    }

    pub fn duplicate(&self) -> io::Result<FileDesc> {
        // We want to atomically duplicate this file descriptor and set the
        // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
        // is a POSIX flag that was added to Linux in 2.6.24.
        let fd = cvt(unsafe { libc::fcntl(self.raw(), libc::F_DUPFD_CLOEXEC, 0) })?;
        Ok(FileDesc::new(fd))
    }
}

impl<'a> Read for &'a FileDesc {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (**self).read(buf)
    }

    #[inline]
    unsafe fn initializer(&self) -> Initializer {
        Initializer::nop()
    }
}

impl AsInner<c_int> for FileDesc {
    fn as_inner(&self) -> &c_int {
        &self.fd
    }
}

impl Drop for FileDesc {
    fn drop(&mut self) {
        // Note that errors are ignored when closing a file descriptor. The
        // reason for this is that if an error occurs we don't actually know if
        // the file descriptor was closed or not, and if we retried (for
        // something like EINTR), we might close another valid file descriptor
        // opened after we closed ours.
        let _ = unsafe { libc::close(self.fd) };
    }
}

#[cfg(test)]
mod tests {
    use super::{FileDesc, IoSlice};
    use core::mem::ManuallyDrop;

    #[test]
    fn limit_vector_count() {
        let stdout = ManuallyDrop::new(FileDesc { fd: 1 });
        let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::<Vec<_>>();
        assert!(stdout.write_vectored(&bufs).is_ok());
    }
}
<|endoftext|>


<commit_before>/// Application Program Status Register
pub struct APSR;

#[cfg(any(not(target_feature = thumb-mode), target_feature = "v6t2"))]
rsr!(APSR);
<commit_msg>oh, they both need double quotes, okay<commit_after>/// Application Program Status Register
pub struct APSR;

#[cfg(any(not(target_feature = "thumb-mode"), target_feature = "v6t2"))]
rsr!(APSR);
<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

pub mod config;
pub mod git;
pub mod keys;
#[cfg(test)]
mod tests;

use crate::{
    common::{
        types::{CliError, CliTypedResult, PromptOptions},
        utils::{check_if_file_exists, write_to_file},
    },
    genesis::{
        config::{Layout, StringValidatorConfiguration, ValidatorConfiguration},
        git::{Client, GitOptions, LAYOUT_NAME},
    },
    CliCommand, CliResult,
};
use aptos_config::config::{RocksdbConfig, NO_OP_STORAGE_PRUNER_CONFIG};
use aptos_crypto::{ed25519::Ed25519PublicKey, x25519, ValidCryptoMaterialStringExt};
use aptos_temppath::TempPath;
use aptos_types::{account_address::AccountAddress, chain_id::ChainId, transaction::Transaction};
use aptos_vm::AptosVM;
use aptosdb::AptosDB;
use async_trait::async_trait;
use clap::Parser;
use std::{convert::TryInto, path::PathBuf, str::FromStr};
use storage_interface::DbReaderWriter;
use vm_genesis::Validator;

const MIN_PRICE_PER_GAS_UNIT: u64 = 1;
const WAYPOINT_FILE: &str = "waypoint.txt";
const GENESIS_FILE: &str = "genesis.blob";

/// Tool for setting up and building the Genesis transaction
///
#[derive(Parser)]
pub enum GenesisTool {
    GenerateGenesis(GenerateGenesis),
    GenerateKeys(keys::GenerateKeys),
    SetupGit(git::SetupGit),
    SetValidatorConfiguration(keys::SetValidatorConfiguration),
}

impl GenesisTool {
    pub async fn execute(self) -> CliResult {
        match self {
            GenesisTool::GenerateGenesis(tool) => tool.execute_serialized().await,
            GenesisTool::GenerateKeys(tool) => tool.execute_serialized().await,
            GenesisTool::SetupGit(tool) => tool.execute_serialized_success().await,
            GenesisTool::SetValidatorConfiguration(tool) => tool.execute_serialized_success().await,
        }
    }
}

/// Generate genesis from a git repository
#[derive(Parser)]
pub struct GenerateGenesis {
    #[clap(flatten)]
    prompt_options: PromptOptions,
    #[clap(flatten)]
    git_options: GitOptions,
    #[clap(long, parse(from_os_str), default_value = ".")]
    output_dir: PathBuf,
}

impl GenerateGenesis {
    fn generate_genesis_txn(git_options: GitOptions) -> CliTypedResult<Transaction> {
        let genesis_info = fetch_genesis_info(git_options)?;

        Ok(vm_genesis::encode_genesis_transaction(
            genesis_info.root_key.clone(),
            &genesis_info.validators,
            &genesis_info.modules,
            genesis_info.chain_id,
            MIN_PRICE_PER_GAS_UNIT,
        ))
    }
}

#[async_trait]
impl CliCommand<Vec<PathBuf>> for GenerateGenesis {
    fn command_name(&self) -> &'static str {
        "GenerateGenesis"
    }

    async fn execute(self) -> CliTypedResult<Vec<PathBuf>> {
        let genesis_file = self.output_dir.join(GENESIS_FILE);
        let waypoint_file = self.output_dir.join(WAYPOINT_FILE);
        check_if_file_exists(genesis_file.as_path(), self.prompt_options)?;
        check_if_file_exists(waypoint_file.as_path(), self.prompt_options)?;

        // Generate genesis file
        let genesis = Self::generate_genesis_txn(self.git_options)?;
        write_to_file(
            genesis_file.as_path(),
            GENESIS_FILE,
            &bcs::to_bytes(&genesis).map_err(|e| CliError::BCS(GENESIS_FILE, e))?,
        )?;

        // Generate waypoint file
        let path = TempPath::new();
        let aptosdb = AptosDB::open(
            &path,
            false,
            NO_OP_STORAGE_PRUNER_CONFIG,
            RocksdbConfig::default(),
        )
        .map_err(|e| CliError::UnexpectedError(e.to_string()))?;
        let db_rw = DbReaderWriter::new(aptosdb);
        let waypoint = executor::db_bootstrapper::generate_waypoint::<AptosVM>(&db_rw, &genesis)
            .map_err(|e| CliError::UnexpectedError(e.to_string()))?;
        write_to_file(
            waypoint_file.as_path(),
            WAYPOINT_FILE,
            waypoint.to_string().as_bytes(),
        )?;
        Ok(vec![genesis_file, waypoint_file])
    }
}

/// Retrieves all information for genesis from the Git repository
pub fn fetch_genesis_info(git_options: GitOptions) -> CliTypedResult<GenesisInfo> {
    let client = git_options.get_client()?;
    let layout: Layout = client.get(LAYOUT_NAME)?;

    let mut validators = Vec::new();
    let mut errors = Vec::new();
    for user in &layout.users {
        match get_config(&client, user) {
            Ok(validator) => {
                validators.push(validator);
            }
            Err(failure) => {
                if let CliError::UnexpectedError(failure) = failure {
                    errors.push(format!("{}: {}", user, failure));
                } else {
                    errors.push(format!("{}: {:?}", user, failure));
                }
            }
        }
    }

    // Collect errors, and print out failed inputs
    if !errors.is_empty() {
        eprintln!(
            "Failed to parse genesis inputs:\n{}",
            serde_yaml::to_string(&errors).unwrap()
        );
        return Err(CliError::UnexpectedError(
            "Failed to parse genesis inputs".to_string(),
        ));
    }

    let modules = client.get_modules("framework")?;

    Ok(GenesisInfo {
        chain_id: layout.chain_id,
        root_key: layout.root_key,
        validators,
        modules,
    })
}

/// Do proper parsing so more information is known about failures
fn get_config(client: &Client, user: &str) -> CliTypedResult<Validator> {
    let config = client.get::<StringValidatorConfiguration>(user)?;

    // Convert each individually
    let account_address = AccountAddress::from_str(&config.account_address)
        .map_err(|_| CliError::UnexpectedError("account_address invalid".to_string()))?;
    let account_key = Ed25519PublicKey::from_encoded_string(&config.account_public_key)
        .map_err(|_| CliError::UnexpectedError("account_key invalid".to_string()))?;
    let consensus_key = Ed25519PublicKey::from_encoded_string(&config.consensus_public_key)
        .map_err(|_| CliError::UnexpectedError("consensus_key invalid".to_string()))?;
    let validator_network_key =
        x25519::PublicKey::from_encoded_string(&config.validator_network_public_key)
            .map_err(|_| CliError::UnexpectedError("validator_network_key invalid".to_string()))?;
    let validator_host = config.validator_host.clone();
    let full_node_network_key =
        if let Some(ref full_node_network_key) = config.full_node_network_public_key {
            Some(
                x25519::PublicKey::from_encoded_string(full_node_network_key).map_err(|_| {
                    CliError::UnexpectedError("full_node_network_key invalid".to_string())
                })?,
            )
        } else {
            None
        };
    let full_node_host = config.full_node_host;

    let config = ValidatorConfiguration {
        account_address,
        consensus_public_key: consensus_key,
        account_public_key: account_key,
        validator_network_public_key: validator_network_key,
        validator_host,
        full_node_network_public_key: full_node_network_key,
        full_node_host,
        stake_amount: 0,
    };
    config.try_into()
}

/// Holder object for all pieces needed to generate a genesis transaction
#[derive(Clone)]
pub struct GenesisInfo {
    chain_id: ChainId,
    root_key: Ed25519PublicKey,
    validators: Vec<Validator>,
    modules: Vec<Vec<u8>>,
}
<commit_msg>[config] fix the stake amount in genesis tool<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

pub mod config;
pub mod git;
pub mod keys;
#[cfg(test)]
mod tests;

use crate::{
    common::{
        types::{CliError, CliTypedResult, PromptOptions},
        utils::{check_if_file_exists, write_to_file},
    },
    genesis::{
        config::{Layout, StringValidatorConfiguration, ValidatorConfiguration},
        git::{Client, GitOptions, LAYOUT_NAME},
    },
    CliCommand, CliResult,
};
use aptos_config::config::{RocksdbConfig, NO_OP_STORAGE_PRUNER_CONFIG};
use aptos_crypto::{ed25519::Ed25519PublicKey, x25519, ValidCryptoMaterialStringExt};
use aptos_temppath::TempPath;
use aptos_types::{account_address::AccountAddress, chain_id::ChainId, transaction::Transaction};
use aptos_vm::AptosVM;
use aptosdb::AptosDB;
use async_trait::async_trait;
use clap::Parser;
use std::{convert::TryInto, path::PathBuf, str::FromStr};
use storage_interface::DbReaderWriter;
use vm_genesis::Validator;

const MIN_PRICE_PER_GAS_UNIT: u64 = 1;
const WAYPOINT_FILE: &str = "waypoint.txt";
const GENESIS_FILE: &str = "genesis.blob";

/// Tool for setting up and building the Genesis transaction
///
#[derive(Parser)]
pub enum GenesisTool {
    GenerateGenesis(GenerateGenesis),
    GenerateKeys(keys::GenerateKeys),
    SetupGit(git::SetupGit),
    SetValidatorConfiguration(keys::SetValidatorConfiguration),
}

impl GenesisTool {
    pub async fn execute(self) -> CliResult {
        match self {
            GenesisTool::GenerateGenesis(tool) => tool.execute_serialized().await,
            GenesisTool::GenerateKeys(tool) => tool.execute_serialized().await,
            GenesisTool::SetupGit(tool) => tool.execute_serialized_success().await,
            GenesisTool::SetValidatorConfiguration(tool) => tool.execute_serialized_success().await,
        }
    }
}

/// Generate genesis from a git repository
#[derive(Parser)]
pub struct GenerateGenesis {
    #[clap(flatten)]
    prompt_options: PromptOptions,
    #[clap(flatten)]
    git_options: GitOptions,
    #[clap(long, parse(from_os_str), default_value = ".")]
    output_dir: PathBuf,
}

impl GenerateGenesis {
    fn generate_genesis_txn(git_options: GitOptions) -> CliTypedResult<Transaction> {
        let genesis_info = fetch_genesis_info(git_options)?;

        Ok(vm_genesis::encode_genesis_transaction(
            genesis_info.root_key.clone(),
            &genesis_info.validators,
            &genesis_info.modules,
            genesis_info.chain_id,
            MIN_PRICE_PER_GAS_UNIT,
        ))
    }
}

#[async_trait]
impl CliCommand<Vec<PathBuf>> for GenerateGenesis {
    fn command_name(&self) -> &'static str {
        "GenerateGenesis"
    }

    async fn execute(self) -> CliTypedResult<Vec<PathBuf>> {
        let genesis_file = self.output_dir.join(GENESIS_FILE);
        let waypoint_file = self.output_dir.join(WAYPOINT_FILE);
        check_if_file_exists(genesis_file.as_path(), self.prompt_options)?;
        check_if_file_exists(waypoint_file.as_path(), self.prompt_options)?;

        // Generate genesis file
        let genesis = Self::generate_genesis_txn(self.git_options)?;
        write_to_file(
            genesis_file.as_path(),
            GENESIS_FILE,
            &bcs::to_bytes(&genesis).map_err(|e| CliError::BCS(GENESIS_FILE, e))?,
        )?;

        // Generate waypoint file
        let path = TempPath::new();
        let aptosdb = AptosDB::open(
            &path,
            false,
            NO_OP_STORAGE_PRUNER_CONFIG,
            RocksdbConfig::default(),
        )
        .map_err(|e| CliError::UnexpectedError(e.to_string()))?;
        let db_rw = DbReaderWriter::new(aptosdb);
        let waypoint = executor::db_bootstrapper::generate_waypoint::<AptosVM>(&db_rw, &genesis)
            .map_err(|e| CliError::UnexpectedError(e.to_string()))?;
        write_to_file(
            waypoint_file.as_path(),
            WAYPOINT_FILE,
            waypoint.to_string().as_bytes(),
        )?;
        Ok(vec![genesis_file, waypoint_file])
    }
}

/// Retrieves all information for genesis from the Git repository
pub fn fetch_genesis_info(git_options: GitOptions) -> CliTypedResult<GenesisInfo> {
    let client = git_options.get_client()?;
    let layout: Layout = client.get(LAYOUT_NAME)?;

    let mut validators = Vec::new();
    let mut errors = Vec::new();
    for user in &layout.users {
        match get_config(&client, user) {
            Ok(validator) => {
                validators.push(validator);
            }
            Err(failure) => {
                if let CliError::UnexpectedError(failure) = failure {
                    errors.push(format!("{}: {}", user, failure));
                } else {
                    errors.push(format!("{}: {:?}", user, failure));
                }
            }
        }
    }

    // Collect errors, and print out failed inputs
    if !errors.is_empty() {
        eprintln!(
            "Failed to parse genesis inputs:\n{}",
            serde_yaml::to_string(&errors).unwrap()
        );
        return Err(CliError::UnexpectedError(
            "Failed to parse genesis inputs".to_string(),
        ));
    }

    let modules = client.get_modules("framework")?;

    Ok(GenesisInfo {
        chain_id: layout.chain_id,
        root_key: layout.root_key,
        validators,
        modules,
    })
}

/// Do proper parsing so more information is known about failures
fn get_config(client: &Client, user: &str) -> CliTypedResult<Validator> {
    let config = client.get::<StringValidatorConfiguration>(user)?;

    // Convert each individually
    let account_address = AccountAddress::from_str(&config.account_address)
        .map_err(|_| CliError::UnexpectedError("account_address invalid".to_string()))?;
    let account_key = Ed25519PublicKey::from_encoded_string(&config.account_public_key)
        .map_err(|_| CliError::UnexpectedError("account_key invalid".to_string()))?;
    let consensus_key = Ed25519PublicKey::from_encoded_string(&config.consensus_public_key)
        .map_err(|_| CliError::UnexpectedError("consensus_key invalid".to_string()))?;
    let validator_network_key =
        x25519::PublicKey::from_encoded_string(&config.validator_network_public_key)
            .map_err(|_| CliError::UnexpectedError("validator_network_key invalid".to_string()))?;
    let validator_host = config.validator_host.clone();
    let full_node_network_key =
        if let Some(ref full_node_network_key) = config.full_node_network_public_key {
            Some(
                x25519::PublicKey::from_encoded_string(full_node_network_key).map_err(|_| {
                    CliError::UnexpectedError("full_node_network_key invalid".to_string())
                })?,
            )
        } else {
            None
        };
    let full_node_host = config.full_node_host;

    let config = ValidatorConfiguration {
        account_address,
        consensus_public_key: consensus_key,
        account_public_key: account_key,
        validator_network_public_key: validator_network_key,
        validator_host,
        full_node_network_public_key: full_node_network_key,
        full_node_host,
        stake_amount: config.stake_amount,
    };
    config.try_into()
}

/// Holder object for all pieces needed to generate a genesis transaction
#[derive(Clone)]
pub struct GenesisInfo {
    chain_id: ChainId,
    root_key: Ed25519PublicKey,
    validators: Vec<Validator>,
    modules: Vec<Vec<u8>>,
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std;
use std::iter::{Iterator, Zip};
use std::mem;
use std::mem::ManuallyDrop;
use std::ptr;
use std::slice;
use std::sync::Arc;

use node;
use node::Node;
use text_info::TextInfo;

const MAX_LEN: usize = node::MAX_CHILDREN;

#[derive(Debug)]
pub(crate) struct ChildArray {
    nodes: ManuallyDrop<[Arc<Node>; MAX_LEN]>,
    info: [TextInfo; MAX_LEN],
    len: u8,
}

impl ChildArray {
    /// Creates a new empty array.
    pub fn new() -> ChildArray {
        ChildArray {
            nodes: ManuallyDrop::new(unsafe { std::mem::uninitialized() }),
            info: unsafe { std::mem::uninitialized() },
            len: 0,
        }
    }

    /// Current length of the array.
    pub fn len(&self) -> usize {
        self.len as usize
    }

    /// Returns whether the array is full or not.
    pub fn is_full(&self) -> bool {
        (self.len as usize) == MAX_LEN
    }

    /// Returns a slice to the nodes array.
    pub fn nodes(&self) -> &[Arc<Node>] {
        &self.nodes[..(self.len as usize)]
    }

    /// Returns a mutable slice to the nodes array.
    pub fn nodes_mut(&mut self) -> &mut [Arc<Node>] {
        &mut self.nodes[..(self.len as usize)]
    }

    /// Returns a slice to the info array.
    pub fn info(&self) -> &[TextInfo] {
        &self.info[..(self.len as usize)]
    }

    /// Returns a mutable slice to the info array.
    pub fn info_mut(&mut self) -> &mut [TextInfo] {
        &mut self.info[..(self.len as usize)]
    }

    /// Returns mutable slices to both the nodes and info arrays.
    pub fn info_and_nodes_mut(&mut self) -> (&mut [TextInfo], &mut [Arc<Node>]) {
        (
            &mut self.info[..(self.len as usize)],
            &mut self.nodes[..(self.len as usize)],
        )
    }

    /// Pushes an item into the end of the array.
    ///
    /// Increases length by one.  Panics if already full.
    pub fn push(&mut self, item: (TextInfo, Arc<Node>)) {
        assert!((self.len as usize) < MAX_LEN);
        self.info[self.len as usize] = item.0;
        mem::forget(mem::replace(&mut self.nodes[self.len as usize], item.1));
        self.len += 1;
    }

    /// Pushes an element onto the end of the array, and then splits it in half,
    /// returning the right half.
    ///
    /// This works even when the array is full.
    pub fn push_split(&mut self, new_child: (TextInfo, Arc<Node>)) -> ChildArray {
        let mut right = ChildArray::new();

        let r_count = (self.len() + 1) / 2;
        let l_count = (self.len() + 1) - r_count;

        for _ in l_count..self.len() {
            right.push(self.remove(l_count));
        }
        right.push(new_child);

        right
    }

    /// Pops an item off the end of the array and returns it.
    ///
    /// Decreases length by one.  Panics if already empty.
    pub fn pop(&mut self) -> (TextInfo, Arc<Node>) {
        assert!(self.len > 0);
        self.len -= 1;
        let item = (self.info[self.len as usize], unsafe {
            ptr::read(&self.nodes[self.len as usize])
        });
        item
    }

    /// Inserts an item into the the array at the given index.
    ///
    /// Increases length by one.  Panics if already full.  Preserves ordering
    /// of the other items.
    pub fn insert(&mut self, idx: usize, item: (TextInfo, Arc<Node>)) {
        assert!(idx <= (self.len as usize));
        assert!((self.len as usize) < MAX_LEN);

        let len = self.len as usize;
        unsafe {
            ptr::copy(
                self.nodes.as_ptr().offset(idx as isize),
                self.nodes.as_mut_ptr().offset((idx + 1) as isize),
                len - idx,
            );
            ptr::copy(
                self.info.as_ptr().offset(idx as isize),
                self.info.as_mut_ptr().offset((idx + 1) as isize),
                len - idx,
            );
        }

        self.info[idx] = item.0;
        mem::forget(mem::replace(&mut self.nodes[idx], item.1));

        self.len += 1;
    }

    /// Inserts an element into a the array, and then splits it in half, returning
    /// the right half.
    ///
    /// This works even when the array is full.
    pub fn insert_split(&mut self, idx: usize, item: (TextInfo, Arc<Node>)) -> ChildArray {
        assert!(self.len() > 0);
        let extra = if idx < self.len() {
            let extra = self.pop();
            self.insert(idx, item);
            extra
        } else {
            item
        };

        self.push_split(extra)
    }

    /// Removes the item at the given index from the the array.
    ///
    /// Decreases length by one.  Preserves ordering of the other items.
    pub fn remove(&mut self, idx: usize) -> (TextInfo, Arc<Node>) {
        assert!(idx < (self.len as usize));

        let item = (self.info[idx], unsafe { ptr::read(&self.nodes[idx]) });

        let len = self.len as usize;
        unsafe {
            ptr::copy(
                self.nodes.as_ptr().offset(idx as isize + 1),
                self.nodes.as_mut_ptr().offset(idx as isize),
                len - idx - 1,
            );
            ptr::copy(
                self.info.as_ptr().offset(idx as isize + 1),
                self.info.as_mut_ptr().offset(idx as isize),
                len - idx - 1,
            );
        }

        self.len -= 1;
        return item;
    }

    /// Gets references to the nth item's node and info.
    pub fn i(&self, n: usize) -> (&TextInfo, &Arc<Node>) {
        assert!(n < self.len as usize);
        (
            &self.info[self.len as usize],
            &self.nodes[self.len as usize],
        )
    }

    /// Gets mut references to the nth item's node and info.
    pub fn i_mut(&mut self, n: usize) -> (&mut TextInfo, &mut Arc<Node>) {
        assert!(n < self.len as usize);
        (
            &mut self.info[self.len as usize],
            &mut self.nodes[self.len as usize],
        )
    }

    /// Creates an iterator over the array's items.
    pub fn iter(&self) -> Zip<slice::Iter<TextInfo>, slice::Iter<Arc<Node>>> {
        Iterator::zip(
            (&self.info[..(self.len as usize)]).iter(),
            (&self.nodes[..(self.len as usize)]).iter(),
        )
    }

    /// Creates an iterator over the array's items.
    pub fn iter_mut(&mut self) -> Zip<slice::IterMut<TextInfo>, slice::IterMut<Arc<Node>>> {
        Iterator::zip(
            (&mut self.info[..(self.len as usize)]).iter_mut(),
            (&mut self.nodes[..(self.len as usize)]).iter_mut(),
        )
    }

    pub fn combined_info(&self) -> TextInfo {
        self.info[..self.len()].iter().fold(
            TextInfo::new(),
            |a, b| a.combine(b),
        )
    }

    pub fn search_combine_info<F: Fn(&TextInfo) -> bool>(&self, pred: F) -> (usize, TextInfo) {
        let mut accum = TextInfo::new();
        for (idx, inf) in self.info[..self.len()].iter().enumerate() {
            if pred(&accum.combine(inf)) {
                return (idx, accum);
            } else {
                accum = accum.combine(inf);
            }
        }
        panic!("Predicate is mal-formed and never evaluated true.")
    }
}

impl Drop for ChildArray {
    fn drop(&mut self) {
        for node in &mut self.nodes[..self.len as usize] {
            let mptr: *mut Arc<Node> = node; // Make sure we have the right dereference
            unsafe { ptr::drop_in_place(mptr) };
        }
    }
}

impl Clone for ChildArray {
    fn clone(&self) -> ChildArray {
        let mut clone_array = ChildArray::new();

        // Copy nodes... carefully.
        for (clone_arc, arc) in Iterator::zip(
            clone_array.nodes[..self.len()].iter_mut(),
            self.nodes[..self.len()].iter(),
        )
        {
            mem::forget(mem::replace(clone_arc, arc.clone()));
        }

        // Copy TextInfo
        for (clone_info, info) in
            Iterator::zip(
                clone_array.info[..self.len()].iter_mut(),
                self.info[..self.len()].iter(),
            )
        {
            *clone_info = *info;
        }

        // Set length
        clone_array.len = self.len;

        // Some sanity checks for debug builds
        #[cfg(debug_assertions)]
        {
            for (a, b) in Iterator::zip(clone_array.iter(), self.iter()) {
                assert_eq!(a.0, b.0);
                assert!(Arc::ptr_eq(a.1, b.1));
            }
        }

        clone_array
    }
}
<commit_msg>Manual Debug implementation for ChildArray.<commit_after>#![allow(dead_code)]

use std;
use std::fmt;
use std::iter::{Iterator, Zip};
use std::mem;
use std::mem::ManuallyDrop;
use std::ptr;
use std::slice;
use std::sync::Arc;

use node;
use node::Node;
use text_info::TextInfo;

const MAX_LEN: usize = node::MAX_CHILDREN;

pub(crate) struct ChildArray {
    nodes: ManuallyDrop<[Arc<Node>; MAX_LEN]>,
    info: [TextInfo; MAX_LEN],
    len: u8,
}

impl ChildArray {
    /// Creates a new empty array.
    pub fn new() -> ChildArray {
        ChildArray {
            nodes: ManuallyDrop::new(unsafe { std::mem::uninitialized() }),
            info: unsafe { std::mem::uninitialized() },
            len: 0,
        }
    }

    /// Current length of the array.
    pub fn len(&self) -> usize {
        self.len as usize
    }

    /// Returns whether the array is full or not.
    pub fn is_full(&self) -> bool {
        (self.len as usize) == MAX_LEN
    }

    /// Returns a slice to the nodes array.
    pub fn nodes(&self) -> &[Arc<Node>] {
        &self.nodes[..(self.len as usize)]
    }

    /// Returns a mutable slice to the nodes array.
    pub fn nodes_mut(&mut self) -> &mut [Arc<Node>] {
        &mut self.nodes[..(self.len as usize)]
    }

    /// Returns a slice to the info array.
    pub fn info(&self) -> &[TextInfo] {
        &self.info[..(self.len as usize)]
    }

    /// Returns a mutable slice to the info array.
    pub fn info_mut(&mut self) -> &mut [TextInfo] {
        &mut self.info[..(self.len as usize)]
    }

    /// Returns mutable slices to both the nodes and info arrays.
    pub fn info_and_nodes_mut(&mut self) -> (&mut [TextInfo], &mut [Arc<Node>]) {
        (
            &mut self.info[..(self.len as usize)],
            &mut self.nodes[..(self.len as usize)],
        )
    }

    /// Pushes an item into the end of the array.
    ///
    /// Increases length by one.  Panics if already full.
    pub fn push(&mut self, item: (TextInfo, Arc<Node>)) {
        assert!((self.len as usize) < MAX_LEN);
        self.info[self.len as usize] = item.0;
        mem::forget(mem::replace(&mut self.nodes[self.len as usize], item.1));
        self.len += 1;
    }

    /// Pushes an element onto the end of the array, and then splits it in half,
    /// returning the right half.
    ///
    /// This works even when the array is full.
    pub fn push_split(&mut self, new_child: (TextInfo, Arc<Node>)) -> ChildArray {
        let mut right = ChildArray::new();

        let r_count = (self.len() + 1) / 2;
        let l_count = (self.len() + 1) - r_count;

        for _ in l_count..self.len() {
            right.push(self.remove(l_count));
        }
        right.push(new_child);

        right
    }

    /// Pops an item off the end of the array and returns it.
    ///
    /// Decreases length by one.  Panics if already empty.
    pub fn pop(&mut self) -> (TextInfo, Arc<Node>) {
        assert!(self.len > 0);
        self.len -= 1;
        let item = (self.info[self.len as usize], unsafe {
            ptr::read(&self.nodes[self.len as usize])
        });
        item
    }

    /// Inserts an item into the the array at the given index.
    ///
    /// Increases length by one.  Panics if already full.  Preserves ordering
    /// of the other items.
    pub fn insert(&mut self, idx: usize, item: (TextInfo, Arc<Node>)) {
        assert!(idx <= (self.len as usize));
        assert!((self.len as usize) < MAX_LEN);

        let len = self.len as usize;
        unsafe {
            ptr::copy(
                self.nodes.as_ptr().offset(idx as isize),
                self.nodes.as_mut_ptr().offset((idx + 1) as isize),
                len - idx,
            );
            ptr::copy(
                self.info.as_ptr().offset(idx as isize),
                self.info.as_mut_ptr().offset((idx + 1) as isize),
                len - idx,
            );
        }

        self.info[idx] = item.0;
        mem::forget(mem::replace(&mut self.nodes[idx], item.1));

        self.len += 1;
    }

    /// Inserts an element into a the array, and then splits it in half, returning
    /// the right half.
    ///
    /// This works even when the array is full.
    pub fn insert_split(&mut self, idx: usize, item: (TextInfo, Arc<Node>)) -> ChildArray {
        assert!(self.len() > 0);
        let extra = if idx < self.len() {
            let extra = self.pop();
            self.insert(idx, item);
            extra
        } else {
            item
        };

        self.push_split(extra)
    }

    /// Removes the item at the given index from the the array.
    ///
    /// Decreases length by one.  Preserves ordering of the other items.
    pub fn remove(&mut self, idx: usize) -> (TextInfo, Arc<Node>) {
        assert!(idx < (self.len as usize));

        let item = (self.info[idx], unsafe { ptr::read(&self.nodes[idx]) });

        let len = self.len as usize;
        unsafe {
            ptr::copy(
                self.nodes.as_ptr().offset(idx as isize + 1),
                self.nodes.as_mut_ptr().offset(idx as isize),
                len - idx - 1,
            );
            ptr::copy(
                self.info.as_ptr().offset(idx as isize + 1),
                self.info.as_mut_ptr().offset(idx as isize),
                len - idx - 1,
            );
        }

        self.len -= 1;
        return item;
    }

    /// Gets references to the nth item's node and info.
    pub fn i(&self, n: usize) -> (&TextInfo, &Arc<Node>) {
        assert!(n < self.len as usize);
        (
            &self.info[self.len as usize],
            &self.nodes[self.len as usize],
        )
    }

    /// Gets mut references to the nth item's node and info.
    pub fn i_mut(&mut self, n: usize) -> (&mut TextInfo, &mut Arc<Node>) {
        assert!(n < self.len as usize);
        (
            &mut self.info[self.len as usize],
            &mut self.nodes[self.len as usize],
        )
    }

    /// Creates an iterator over the array's items.
    pub fn iter(&self) -> Zip<slice::Iter<TextInfo>, slice::Iter<Arc<Node>>> {
        Iterator::zip(
            (&self.info[..(self.len as usize)]).iter(),
            (&self.nodes[..(self.len as usize)]).iter(),
        )
    }

    /// Creates an iterator over the array's items.
    pub fn iter_mut(&mut self) -> Zip<slice::IterMut<TextInfo>, slice::IterMut<Arc<Node>>> {
        Iterator::zip(
            (&mut self.info[..(self.len as usize)]).iter_mut(),
            (&mut self.nodes[..(self.len as usize)]).iter_mut(),
        )
    }

    pub fn combined_info(&self) -> TextInfo {
        self.info[..self.len()].iter().fold(
            TextInfo::new(),
            |a, b| a.combine(b),
        )
    }

    pub fn search_combine_info<F: Fn(&TextInfo) -> bool>(&self, pred: F) -> (usize, TextInfo) {
        let mut accum = TextInfo::new();
        for (idx, inf) in self.info[..self.len()].iter().enumerate() {
            if pred(&accum.combine(inf)) {
                return (idx, accum);
            } else {
                accum = accum.combine(inf);
            }
        }
        panic!("Predicate is mal-formed and never evaluated true.")
    }
}

impl fmt::Debug for ChildArray {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("ChildArray")
            .field("nodes", &&self.nodes[0..self.len()])
            .field("info", &&self.info[0..self.len()])
            .field("len", &self.len)
            .finish()
    }
}

impl Drop for ChildArray {
    fn drop(&mut self) {
        for node in &mut self.nodes[..self.len as usize] {
            let mptr: *mut Arc<Node> = node; // Make sure we have the right dereference
            unsafe { ptr::drop_in_place(mptr) };
        }
    }
}

impl Clone for ChildArray {
    fn clone(&self) -> ChildArray {
        let mut clone_array = ChildArray::new();

        // Copy nodes... carefully.
        for (clone_arc, arc) in Iterator::zip(
            clone_array.nodes[..self.len()].iter_mut(),
            self.nodes[..self.len()].iter(),
        )
        {
            mem::forget(mem::replace(clone_arc, arc.clone()));
        }

        // Copy TextInfo
        for (clone_info, info) in
            Iterator::zip(
                clone_array.info[..self.len()].iter_mut(),
                self.info[..self.len()].iter(),
            )
        {
            *clone_info = *info;
        }

        // Set length
        clone_array.len = self.len;

        // Some sanity checks for debug builds
        #[cfg(debug_assertions)]
        {
            for (a, b) in Iterator::zip(clone_array.iter(), self.iter()) {
                assert_eq!(a.0, b.0);
                assert!(Arc::ptr_eq(a.1, b.1));
            }
        }

        clone_array
    }
}
<|endoftext|>


<commit_before>use std::convert::From;

use binding::{class, global};
use types;

use super::traits::RawObject;

pub struct Class {
    value: types::rb_value
}

impl Class {
    // TODO: replace rb_cObject with optional superclass
    pub fn new(name: &str) -> Self {
        Class {
            value: class::define_class(name, global::rb_cObject)
        }
    }

    pub fn define_method(&self,
                         name: &str,
                         callback: extern fn(types::argc, *const types::rb_value, types::rb_value) -> types::rb_value) {
        class::define_method(self.value, name, callback);
    }
}

impl From<types::rb_value> for Class {
    fn from(value: types::rb_value) -> Self {
        Class {
            value: value
        }
    }
}

impl RawObject for Class {
    fn value(&self) -> types::rb_value {
        self.value
    }
}
<commit_msg>Create Class::define_singleton_method()<commit_after>use std::convert::From;

use binding::{class, global};
use types;

use super::traits::RawObject;

pub struct Class {
    value: types::rb_value
}

impl Class {
    // TODO: replace rb_cObject with optional superclass
    pub fn new(name: &str) -> Self {
        Class {
            value: class::define_class(name, global::rb_cObject)
        }
    }

    pub fn define_method(&self,
                         name: &str,
                         callback: extern fn(types::argc, *const types::rb_value, types::rb_value) -> types::rb_value) {
        class::define_method(self.value, name, callback);
    }

    pub fn define_singleton_method(&self,
                         name: &str,
                         callback: extern fn(types::argc, *const types::rb_value, types::rb_value) -> types::rb_value) {
        class::define_singleton_method(self.value, name, callback);
    }
}

impl From<types::rb_value> for Class {
    fn from(value: types::rb_value) -> Self {
        Class {
            value: value
        }
    }
}

impl RawObject for Class {
    fn value(&self) -> types::rb_value {
        self.value
    }
}
<|endoftext|>