<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 https://mozilla.org/MPL/2.0/. */

use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::RTCDataChannelBinding::RTCDataChannelInit;
use crate::dom::bindings::codegen::Bindings::RTCDataChannelBinding::RTCDataChannelMethods;
use crate::dom::bindings::codegen::Bindings::RTCErrorBinding::{RTCErrorDetailType, RTCErrorInit};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::{DOMString, USVString};
use crate::dom::blob::Blob;
use crate::dom::event::{Event, EventBubbles, EventCancelable};
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::messageevent::MessageEvent;
use crate::dom::rtcerror::RTCError;
use crate::dom::rtcerrorevent::RTCErrorEvent;
use crate::task_source::TaskSource;
use dom_struct::dom_struct;
use js::conversions::ToJSValConvertible;
use js::jsapi::JSAutoRealm;
use js::jsval::UndefinedValue;
use js::rust::CustomAutoRooterGuard;
use js::typedarray::{ArrayBuffer, ArrayBufferView};
use servo_media::webrtc::{
    WebRtcController, WebRtcDataChannelBackend, WebRtcDataChannelInit, WebRtcError,
};
use std::sync::mpsc;

#[dom_struct]
pub struct RTCDataChannel {
    eventtarget: EventTarget,
    #[ignore_malloc_size_of = "defined in servo-media"]
    channel: Box<dyn WebRtcDataChannelBackend>,
    label: USVString,
    ordered: bool,
    max_packet_life_time: Option<u16>,
    max_retransmits: Option<u16>,
    protocol: USVString,
    negotiated: bool,
    id: Option<u16>,
}

impl RTCDataChannel {
    #[allow(unrooted_must_root)]
    pub fn new_inherited(
        webrtc_controller: &DomRefCell<Option<WebRtcController>>,
        label: USVString,
        options: &RTCDataChannelInit,
        channel: Option<Box<dyn WebRtcDataChannelBackend>>,
    ) -> RTCDataChannel {
        let webrtc = webrtc_controller.borrow();
        let webrtc = webrtc.as_ref().unwrap();

        let (sender, receiver) = mpsc::channel::<Box<dyn WebRtcDataChannelBackend>>();

        let mut init: WebRtcDataChannelInit = options.into();
        init.label = label.to_string();

        let channel = if channel.is_none() {
            webrtc.create_data_channel(init, sender);
            receiver.recv().unwrap()
        } else {
            channel.unwrap()
        };

        let rtc_data_channel = RTCDataChannel {
            eventtarget: EventTarget::new_inherited(),
            channel,
            label,
            ordered: options.ordered,
            max_packet_life_time: options.maxPacketLifeTime,
            max_retransmits: options.maxRetransmits,
            protocol: options.protocol.clone(),
            negotiated: options.negotiated,
            id: options.id,
        };

        let trusted = Trusted::new(&rtc_data_channel);

        let this = trusted.clone();
        rtc_data_channel.channel.set_on_open(Box::new(move || {
            let this_ = this.clone();
            let global = this.root().global();
            let task_source = global.networking_task_source();
            let _ = task_source.queue(
                task!(on_open: move || {
                    this_.root().on_open();
                }),
                global.upcast(),
            );
        }));

        let this = trusted.clone();
        rtc_data_channel.channel.set_on_close(Box::new(move || {
            let this_ = this.clone();
            let global = this.root().global();
            let task_source = global.networking_task_source();
            let _ = task_source.queue(
                task!(on_close: move || {
                    this_.root().on_close();
                }),
                global.upcast(),
            );
        }));

        let this = trusted.clone();
        rtc_data_channel
            .channel
            .set_on_error(Box::new(move |error| {
                let this_ = this.clone();
                let global = this.root().global();
                let task_source = global.networking_task_source();
                let _ = task_source.queue(
                    task!(on_error: move || {
                        this_.root().on_error(error);
                    }),
                    global.upcast(),
                );
            }));

        let this = trusted.clone();
        rtc_data_channel
            .channel
            .set_on_message(Box::new(move |message| {
                let this_ = this.clone();
                let global = this.root().global();
                let task_source = global.networking_task_source();
                let _ = task_source.queue(
                    task!(on_message: move || {
                        this_.root().on_message(message);
                    }),
                    global.upcast(),
                );
            }));

        rtc_data_channel
    }

    pub fn new(
        global: &GlobalScope,
        webrtc_controller: &DomRefCell<Option<WebRtcController>>,
        label: USVString,
        options: &RTCDataChannelInit,
        channel: Option<Box<dyn WebRtcDataChannelBackend>>,
    ) -> DomRoot<RTCDataChannel> {
        reflect_dom_object(
            Box::new(RTCDataChannel::new_inherited(
                webrtc_controller,
                label,
                options,
                channel,
            )),
            global,
        )
    }

    fn on_open(&self) {
        let event = Event::new(
            &self.global(),
            atom!("open"),
            EventBubbles::DoesNotBubble,
            EventCancelable::NotCancelable,
        );
        event.upcast::<Event>().fire(self.upcast());
    }

    fn on_close(&self) {
        let event = Event::new(
            &self.global(),
            atom!("close"),
            EventBubbles::DoesNotBubble,
            EventCancelable::NotCancelable,
        );
        event.upcast::<Event>().fire(self.upcast());
    }

    fn on_error(&self, error: WebRtcError) {
        let init = RTCErrorInit {
            errorDetail: RTCErrorDetailType::Data_channel_failure,
            httpRequestStatusCode: None,
            receivedAlert: None,
            sctpCauseCode: None,
            sdpLineNumber: None,
            sentAlert: None,
        };
        let message = match error {
            WebRtcError::Backend(message) => DOMString::from(message),
        };
        let error = RTCError::new(&self.global(), &init, message);
        let event = RTCErrorEvent::new(&self.global(), atom!("error"), false, false, &error);
        event.upcast::<Event>().fire(self.upcast());
    }

    #[allow(unsafe_code)]
    fn on_message(&self, text: String) {
        // XXX(ferjm) Support binary messages
        unsafe {
            let global = self.global();
            let cx = global.get_cx();
            let _ac = JSAutoRealm::new(*cx, self.reflector().get_jsobject().get());
            rooted!(in(*cx) let mut message = UndefinedValue());
            text.to_jsval(*cx, message.handle_mut());

            MessageEvent::dispatch_jsval(
                self.upcast(),
                &global,
                message.handle(),
                Some(&global.origin().immutable().ascii_serialization()),
                None,
                vec![],
            );
        }
    }
}

impl RTCDataChannelMethods for RTCDataChannel {
    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onopen
    event_handler!(open, GetOnopen, SetOnopen);
    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onbufferedamountlow
    event_handler!(
        bufferedamountlow,
        GetOnbufferedamountlow,
        SetOnbufferedamountlow
    );
    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onerror
    event_handler!(error, GetOnerror, SetOnerror);
    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onclosing
    event_handler!(closing, GetOnclosing, SetOnclosing);
    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onclose
    event_handler!(close, GetOnclose, SetOnclose);
    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onmessage
    event_handler!(message, GetOnmessage, SetOnmessage);

    // https://www.w3.org/TR/webrtc/#dom-datachannel-label
    fn Label(&self) -> USVString {
        self.label.clone()
    }
    // https://www.w3.org/TR/webrtc/#dom-datachannel-ordered
    fn Ordered(&self) -> bool {
        self.ordered
    }

    // https://www.w3.org/TR/webrtc/#dom-datachannel-maxpacketlifetime
    fn GetMaxPacketLifeTime(&self) -> Option<u16> {
        self.max_packet_life_time
    }

    // https://www.w3.org/TR/webrtc/#dom-datachannel-maxretransmits
    fn GetMaxRetransmits(&self) -> Option<u16> {
        self.max_retransmits
    }

    // https://www.w3.org/TR/webrtc/#dom-datachannel-protocol
    fn Protocol(&self) -> USVString {
        self.protocol.clone()
    }

    // https://www.w3.org/TR/webrtc/#dom-datachannel-negotiated
    fn Negotiated(&self) -> bool {
        self.negotiated
    }

    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-id
    fn GetId(&self) -> Option<u16> {
        self.id
    }

    //    fn ReadyState(&self) -> RTCDataChannelState;
    //    fn BufferedAmount(&self) -> u32;
    //    fn BufferedAmountLowThreshold(&self) -> u32;
    //    fn SetBufferedAmountLowThreshold(&self, value: u32) -> ();

    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-close
    fn Close(&self) -> () {}

    //    fn BinaryType(&self) -> DOMString;
    //    fn SetBinaryType(&self, value: DOMString) -> ();

    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send
    fn Send(&self, data: USVString) -> () {
        if let Err(error) = self.channel.send(&data.0) {
            warn!("Could not send data channel message. Error: {:?}", error);
        }
    }

    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send!overload-1
    fn Send_(&self, data: &Blob) -> () {}

    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send!overload-2
    fn Send__(&self, data: CustomAutoRooterGuard<ArrayBuffer>) -> () {}

    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send!overload-3
    fn Send___(&self, data: CustomAutoRooterGuard<ArrayBufferView>) -> () {}
}

impl From<&RTCDataChannelInit> for WebRtcDataChannelInit {
    fn from(init: &RTCDataChannelInit) -> WebRtcDataChannelInit {
        WebRtcDataChannelInit {
            label: String::new(),
            id: init.id,
            max_packet_life_time: init.maxPacketLifeTime,
            max_retransmits: init.maxRetransmits,
            negotiated: init.negotiated,
            ordered: init.ordered,
            protocol: init.protocol.to_string(),
        }
    }
}
<commit_msg>Fix rooting issues with data channels callbacks<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 https://mozilla.org/MPL/2.0/. */

use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::RTCDataChannelBinding::RTCDataChannelInit;
use crate::dom::bindings::codegen::Bindings::RTCDataChannelBinding::RTCDataChannelMethods;
use crate::dom::bindings::codegen::Bindings::RTCErrorBinding::{RTCErrorDetailType, RTCErrorInit};
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::refcounted::Trusted;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::{DOMString, USVString};
use crate::dom::blob::Blob;
use crate::dom::event::{Event, EventBubbles, EventCancelable};
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::messageevent::MessageEvent;
use crate::dom::rtcerror::RTCError;
use crate::dom::rtcerrorevent::RTCErrorEvent;
use crate::task_source::TaskSource;
use dom_struct::dom_struct;
use js::conversions::ToJSValConvertible;
use js::jsapi::JSAutoRealm;
use js::jsval::UndefinedValue;
use js::rust::CustomAutoRooterGuard;
use js::typedarray::{ArrayBuffer, ArrayBufferView};
use servo_media::webrtc::{
    WebRtcController, WebRtcDataChannelBackend, WebRtcDataChannelInit, WebRtcError,
};
use std::sync::mpsc;

#[dom_struct]
pub struct RTCDataChannel {
    eventtarget: EventTarget,
    #[ignore_malloc_size_of = "defined in servo-media"]
    channel: Box<dyn WebRtcDataChannelBackend>,
    label: USVString,
    ordered: bool,
    max_packet_life_time: Option<u16>,
    max_retransmits: Option<u16>,
    protocol: USVString,
    negotiated: bool,
    id: Option<u16>,
}

impl RTCDataChannel {
    pub fn new_inherited(
        webrtc_controller: &DomRefCell<Option<WebRtcController>>,
        label: USVString,
        options: &RTCDataChannelInit,
        channel: Option<Box<dyn WebRtcDataChannelBackend>>,
    ) -> RTCDataChannel {
        let webrtc = webrtc_controller.borrow();
        let webrtc = webrtc.as_ref().unwrap();

        let (sender, receiver) = mpsc::channel::<Box<dyn WebRtcDataChannelBackend>>();

        let mut init: WebRtcDataChannelInit = options.into();
        init.label = label.to_string();

        let channel = if channel.is_none() {
            webrtc.create_data_channel(init, sender);
            receiver.recv().unwrap()
        } else {
            channel.unwrap()
        };

        RTCDataChannel {
            eventtarget: EventTarget::new_inherited(),
            channel,
            label,
            ordered: options.ordered,
            max_packet_life_time: options.maxPacketLifeTime,
            max_retransmits: options.maxRetransmits,
            protocol: options.protocol.clone(),
            negotiated: options.negotiated,
            id: options.id,
        }
    }

    pub fn new(
        global: &GlobalScope,
        webrtc_controller: &DomRefCell<Option<WebRtcController>>,
        label: USVString,
        options: &RTCDataChannelInit,
        channel: Option<Box<dyn WebRtcDataChannelBackend>>,
    ) -> DomRoot<RTCDataChannel> {
        let rtc_data_channel = reflect_dom_object(
            Box::new(RTCDataChannel::new_inherited(
                webrtc_controller,
                label,
                options,
                channel,
            )),
            global,
        );

        let trusted = Trusted::new(&*rtc_data_channel);
        let (task_source, canceller) = global
            .as_window()
            .task_manager()
            .networking_task_source_with_canceller();

        let this = trusted.clone();
        rtc_data_channel.channel.set_on_open(Box::new(move || {
            let this = this.clone();
            let _ = task_source.queue_with_canceller(
                task!(on_open: move || {
                    this.root().on_open();
                }),
                &canceller,
            );
        }));

        let this = trusted.clone();
        let (task_source, canceller) = global
            .as_window()
            .task_manager()
            .networking_task_source_with_canceller();
        rtc_data_channel.channel.set_on_close(Box::new(move || {
            let this = this.clone();
            let _ = task_source.queue_with_canceller(
                task!(on_close: move || {
                    this.root().on_close();
                }),
                &canceller,
            );
        }));

        let this = trusted.clone();
        let (task_source, canceller) = global
            .as_window()
            .task_manager()
            .networking_task_source_with_canceller();
        rtc_data_channel
            .channel
            .set_on_error(Box::new(move |error| {
                let this = this.clone();
                let _ = task_source.queue_with_canceller(
                    task!(on_error: move || {
                        this.root().on_error(error);
                    }),
                    &canceller,
                );
            }));

        let this = trusted.clone();
        let (task_source, canceller) = global
            .as_window()
            .task_manager()
            .networking_task_source_with_canceller();
        rtc_data_channel
            .channel
            .set_on_message(Box::new(move |message| {
                let this = this.clone();
                let _ = task_source.queue_with_canceller(
                    task!(on_message: move || {
                        this.root().on_message(message);
                    }),
                    &canceller,
                );
            }));

        rtc_data_channel
    }

    fn on_open(&self) {
        let event = Event::new(
            &self.global(),
            atom!("open"),
            EventBubbles::DoesNotBubble,
            EventCancelable::NotCancelable,
        );
        event.upcast::<Event>().fire(self.upcast());
    }

    fn on_close(&self) {
        let event = Event::new(
            &self.global(),
            atom!("close"),
            EventBubbles::DoesNotBubble,
            EventCancelable::NotCancelable,
        );
        event.upcast::<Event>().fire(self.upcast());
    }

    fn on_error(&self, error: WebRtcError) {
        let init = RTCErrorInit {
            errorDetail: RTCErrorDetailType::Data_channel_failure,
            httpRequestStatusCode: None,
            receivedAlert: None,
            sctpCauseCode: None,
            sdpLineNumber: None,
            sentAlert: None,
        };
        let message = match error {
            WebRtcError::Backend(message) => DOMString::from(message),
        };
        let error = RTCError::new(&self.global(), &init, message);
        let event = RTCErrorEvent::new(&self.global(), atom!("error"), false, false, &error);
        event.upcast::<Event>().fire(self.upcast());
    }

    #[allow(unsafe_code)]
    fn on_message(&self, text: String) {
        // XXX(ferjm) Support binary messages
        unsafe {
            let global = self.global();
            let cx = global.get_cx();
            let _ac = JSAutoRealm::new(*cx, self.reflector().get_jsobject().get());
            rooted!(in(*cx) let mut message = UndefinedValue());
            text.to_jsval(*cx, message.handle_mut());

            MessageEvent::dispatch_jsval(
                self.upcast(),
                &global,
                message.handle(),
                Some(&global.origin().immutable().ascii_serialization()),
                None,
                vec![],
            );
        }
    }
}

impl RTCDataChannelMethods for RTCDataChannel {
    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onopen
    event_handler!(open, GetOnopen, SetOnopen);
    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onbufferedamountlow
    event_handler!(
        bufferedamountlow,
        GetOnbufferedamountlow,
        SetOnbufferedamountlow
    );
    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onerror
    event_handler!(error, GetOnerror, SetOnerror);
    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onclosing
    event_handler!(closing, GetOnclosing, SetOnclosing);
    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onclose
    event_handler!(close, GetOnclose, SetOnclose);
    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-onmessage
    event_handler!(message, GetOnmessage, SetOnmessage);

    // https://www.w3.org/TR/webrtc/#dom-datachannel-label
    fn Label(&self) -> USVString {
        self.label.clone()
    }
    // https://www.w3.org/TR/webrtc/#dom-datachannel-ordered
    fn Ordered(&self) -> bool {
        self.ordered
    }

    // https://www.w3.org/TR/webrtc/#dom-datachannel-maxpacketlifetime
    fn GetMaxPacketLifeTime(&self) -> Option<u16> {
        self.max_packet_life_time
    }

    // https://www.w3.org/TR/webrtc/#dom-datachannel-maxretransmits
    fn GetMaxRetransmits(&self) -> Option<u16> {
        self.max_retransmits
    }

    // https://www.w3.org/TR/webrtc/#dom-datachannel-protocol
    fn Protocol(&self) -> USVString {
        self.protocol.clone()
    }

    // https://www.w3.org/TR/webrtc/#dom-datachannel-negotiated
    fn Negotiated(&self) -> bool {
        self.negotiated
    }

    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-id
    fn GetId(&self) -> Option<u16> {
        self.id
    }

    //    fn ReadyState(&self) -> RTCDataChannelState;
    //    fn BufferedAmount(&self) -> u32;
    //    fn BufferedAmountLowThreshold(&self) -> u32;
    //    fn SetBufferedAmountLowThreshold(&self, value: u32) -> ();

    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-close
    fn Close(&self) -> () {}

    //    fn BinaryType(&self) -> DOMString;
    //    fn SetBinaryType(&self, value: DOMString) -> ();

    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send
    fn Send(&self, data: USVString) -> () {
        if let Err(error) = self.channel.send(&data.0) {
            warn!("Could not send data channel message. Error: {:?}", error);
        }
    }

    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send!overload-1
    fn Send_(&self, data: &Blob) -> () {}

    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send!overload-2
    fn Send__(&self, data: CustomAutoRooterGuard<ArrayBuffer>) -> () {}

    // https://www.w3.org/TR/webrtc/#dom-rtcdatachannel-send!overload-3
    fn Send___(&self, data: CustomAutoRooterGuard<ArrayBufferView>) -> () {}
}

impl From<&RTCDataChannelInit> for WebRtcDataChannelInit {
    fn from(init: &RTCDataChannelInit) -> WebRtcDataChannelInit {
        WebRtcDataChannelInit {
            label: String::new(),
            id: init.id,
            max_packet_life_time: init.maxPacketLifeTime,
            max_retransmits: init.maxRetransmits,
            negotiated: init.negotiated,
            ordered: init.ordered,
            protocol: init.protocol.to_string(),
        }
    }
}
<|endoftext|>


<commit_before>extern crate std;
use core::prelude::*;
use self::std::io::Error as IoError;
use stack;
use valgrind;

#[cfg(unix)]
#[path = "os/unix.rs"] mod sys;

#[allow(raw_pointer_derive)]
#[derive(Debug)]
pub struct Stack {
  ptr: *mut u8,
  len: usize,
  valgrind_id: valgrind::stack_id_t
}

pub struct StackSource;

impl stack::StackSource for StackSource {
  type Output = Stack;
  fn get_stack(size: usize) -> Stack {
    Stack::new(size)
  }
}

impl stack::Stack for Stack {
  fn top(&mut self) -> *mut u8 {
    unsafe {
      self.ptr.offset(self.len as isize)
    }
  }

  fn limit(&self) -> *const u8 {
    unsafe {
      self.ptr.offset(sys::page_size() as isize)
    }
  }
}

impl Stack {
  fn new(size: usize) -> Stack {
    let page_size = sys::page_size();

    // round the page size up,
    // using the fact that it is a power of two
    let len = (size + page_size - 1) & !(page_size - 1);

    let stack = unsafe {
      let ptr = match sys::map_stack(size) {
        None => {
          panic!("mmap for stack of size {} failed: {:?}",
                 len, IoError::last_os_error())
        }
        Some(ptr) => ptr
      };

      let valgrind_id =
        valgrind::stack_register(ptr as *const _,
                                 ptr.offset(len as isize) as *const _);

      Stack { ptr: ptr as *mut u8, len: len, valgrind_id: valgrind_id }
    };

    unsafe {
      if !sys::protect_stack(stack.ptr) {
        panic!("mprotect for guard page of stack {:p} failed: {:?}",
               stack.ptr, IoError::last_os_error());
      }
    }

    stack
  }
}

impl Drop for Stack {
  fn drop(&mut self) {
    unsafe {
      valgrind::stack_deregister(self.valgrind_id);
      if !sys::unmap_stack(self.ptr, self.len) {
        panic!("munmap for stack {:p} of size {} failed: {:?}",
               self.ptr, self.len, IoError::last_os_error())
      }
    }
  }
}
<commit_msg>use Display for displaying IoErrors<commit_after>extern crate std;
use core::prelude::*;
use self::std::io::Error as IoError;
use stack;
use valgrind;

#[cfg(unix)]
#[path = "os/unix.rs"] mod sys;

#[allow(raw_pointer_derive)]
#[derive(Debug)]
pub struct Stack {
  ptr: *mut u8,
  len: usize,
  valgrind_id: valgrind::stack_id_t
}

pub struct StackSource;

impl stack::StackSource for StackSource {
  type Output = Stack;
  fn get_stack(size: usize) -> Stack {
    Stack::new(size)
  }
}

impl stack::Stack for Stack {
  fn top(&mut self) -> *mut u8 {
    unsafe {
      self.ptr.offset(self.len as isize)
    }
  }

  fn limit(&self) -> *const u8 {
    unsafe {
      self.ptr.offset(sys::page_size() as isize)
    }
  }
}

impl Stack {
  fn new(size: usize) -> Stack {
    let page_size = sys::page_size();

    // round the page size up,
    // using the fact that it is a power of two
    let len = (size + page_size - 1) & !(page_size - 1);

    let stack = unsafe {
      let ptr = match sys::map_stack(size) {
        None => {
          panic!("mmap for stack of size {} failed: {}",
                 len, IoError::last_os_error())
        }
        Some(ptr) => ptr
      };

      let valgrind_id =
        valgrind::stack_register(ptr as *const _,
                                 ptr.offset(len as isize) as *const _);

      Stack { ptr: ptr as *mut u8, len: len, valgrind_id: valgrind_id }
    };

    unsafe {
      if !sys::protect_stack(stack.ptr) {
        panic!("mprotect for guard page of stack {:p} failed: {}",
               stack.ptr, IoError::last_os_error());
      }
    }

    stack
  }
}

impl Drop for Stack {
  fn drop(&mut self) {
    unsafe {
      valgrind::stack_deregister(self.valgrind_id);
      if !sys::unmap_stack(self.ptr, self.len) {
        panic!("munmap for stack {:p} of size {} failed: {}",
               self.ptr, self.len, IoError::last_os_error())
      }
    }
  }
}
<|endoftext|>


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

// TODO(ia0): Remove when used.
#![allow(dead_code)]

/// Bit-level entropy source based on a byte slice shared reference.
struct Entropy<'a> {
    /// The byte slice shared reference providing the entropy.
    data: &'a [u8],

    /// The bit position in the byte slice of the next entropy bit.
    bit: usize,
}

impl Entropy<'_> {
    /// Creates a bit-level entropy given a byte slice.
    fn new(data: &[u8]) -> Entropy {
        let bit = 0;
        Entropy { data, bit }
    }

    /// Consumes the remaining entropy.
    fn consume_all(&mut self) {
        self.bit = 8 * self.data.len();
    }

    /// Returns whether there is entropy remaining.
    fn is_empty(&self) -> bool {
        assert!(self.bit <= 8 * self.data.len());
        self.bit == 8 * self.data.len()
    }

    /// Reads a bit.
    fn read_bit(&mut self) -> bool {
        if self.is_empty() {
            return false;
        }
        let b = self.bit;
        self.bit += 1;
        self.data[b / 8] & 1 << (b % 8) != 0
    }

    /// Reads a number with a given bit-width.
    ///
    /// # Preconditions
    ///
    /// - The number should fit in the return type: `n <= 8 * size_of::<usize>()`.
    fn read_bits(&mut self, n: usize) -> usize {
        assert!(n <= 8 * std::mem::size_of::<usize>());
        let mut r = 0;
        for i in 0..n {
            r |= (self.read_bit() as usize) << i;
        }
        r
    }

    /// Reads a byte.
    fn read_byte(&mut self) -> u8 {
        self.read_bits(8) as u8
    }

    /// Reads a slice.
    fn read_slice(&mut self, length: usize) -> Vec<u8> {
        let mut result = Vec::with_capacity(length);
        for _ in 0..length {
            result.push(self.read_byte());
        }
        result
    }

    /// Reads a bounded number.
    ///
    /// # Preconditions
    ///
    /// - The bounds should be correctly ordered: `min <= max`.
    /// - The upper-bound should not be too large: `max < usize::max_value()`.
    fn read_range(&mut self, min: usize, max: usize) -> usize {
        assert!(min <= max && max < usize::max_value());
        let count = max - min + 1;
        let delta = self.read_bits(num_bits(count - 1)) % count;
        min + delta
    }
}

/// Returns the number of bits necessary to represent a number.
fn num_bits(x: usize) -> usize {
    8 * std::mem::size_of::<usize>() - x.leading_zeros() as usize
}

#[test]
fn num_bits_ok() {
    assert_eq!(num_bits(0), 0);
    assert_eq!(num_bits(1), 1);
    assert_eq!(num_bits(2), 2);
    assert_eq!(num_bits(3), 2);
    assert_eq!(num_bits(4), 3);
    assert_eq!(num_bits(7), 3);
    assert_eq!(num_bits(8), 4);
    assert_eq!(num_bits(15), 4);
    assert_eq!(num_bits(16), 5);
    assert_eq!(
        num_bits(usize::max_value()),
        8 * std::mem::size_of::<usize>()
    );
}

#[test]
fn read_bit_ok() {
    let mut entropy = Entropy::new(&[0b10110010]);
    assert!(!entropy.read_bit());
    assert!(entropy.read_bit());
    assert!(!entropy.read_bit());
    assert!(!entropy.read_bit());
    assert!(entropy.read_bit());
    assert!(entropy.read_bit());
    assert!(!entropy.read_bit());
    assert!(entropy.read_bit());
}

#[test]
fn read_bits_ok() {
    let mut entropy = Entropy::new(&[0x83, 0x92]);
    assert_eq!(entropy.read_bits(4), 0x3);
    assert_eq!(entropy.read_bits(8), 0x28);
    assert_eq!(entropy.read_bits(2), 0b01);
    assert_eq!(entropy.read_bits(2), 0b10);
}

#[test]
fn read_range_ok() {
    let mut entropy = Entropy::new(&[0b00101011]);
    assert_eq!(entropy.read_range(0, 7), 0b011);
    assert_eq!(entropy.read_range(1, 8), 1 + 0b101);
    assert_eq!(entropy.read_range(4, 6), 4 + 0b00);
    let mut entropy = Entropy::new(&[0b00101011]);
    assert_eq!(entropy.read_range(0, 8), 0b1011 % 9);
    assert_eq!(entropy.read_range(3, 15), 3 + 0b0010);
    let mut entropy = Entropy::new(&[0x12, 0x34, 0x56, 0x78]);
    assert_eq!(entropy.read_range(0, usize::max_value() - 1), 0x78563412);
}
<commit_msg>Update documentation<commit_after>// Copyright 2019-2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// TODO(ia0): Remove when used.
#![allow(dead_code)]

/// Bit-level entropy source based on a byte slice shared reference.
struct Entropy<'a> {
    /// The byte slice shared reference providing the entropy.
    data: &'a [u8],

    /// The bit position in the byte slice of the next entropy bit.
    bit: usize,
}

impl Entropy<'_> {
    /// Creates a bit-level entropy given a byte slice.
    fn new(data: &[u8]) -> Entropy {
        let bit = 0;
        Entropy { data, bit }
    }

    /// Consumes the remaining entropy.
    fn consume_all(&mut self) {
        self.bit = 8 * self.data.len();
    }

    /// Returns whether there is entropy remaining.
    fn is_empty(&self) -> bool {
        assert!(self.bit <= 8 * self.data.len());
        self.bit == 8 * self.data.len()
    }

    /// Reads a bit.
    fn read_bit(&mut self) -> bool {
        if self.is_empty() {
            return false;
        }
        let b = self.bit;
        self.bit += 1;
        self.data[b / 8] & 1 << (b % 8) != 0
    }

    /// Reads a number with a given bit-width.
    ///
    /// # Preconditions
    ///
    /// - The number should fit in the return type: `n <= 8 * size_of::<usize>()`.
    fn read_bits(&mut self, n: usize) -> usize {
        assert!(n <= 8 * std::mem::size_of::<usize>());
        let mut r = 0;
        for i in 0..n {
            r |= (self.read_bit() as usize) << i;
        }
        r
    }

    /// Reads a byte.
    fn read_byte(&mut self) -> u8 {
        self.read_bits(8) as u8
    }

    /// Reads a slice.
    fn read_slice(&mut self, length: usize) -> Vec<u8> {
        let mut result = Vec::with_capacity(length);
        for _ in 0..length {
            result.push(self.read_byte());
        }
        result
    }

    /// Reads a number between `min` and `max` (inclusive bounds).
    ///
    /// The distribution is uniform if the range width is a power of two. Otherwise, the minimum
    /// amount of entropy is used (the next power of two) and the distribution is the closest to
    /// uniform for that entropy.
    ///
    /// # Preconditions
    ///
    /// - The bounds should be correctly ordered: `min <= max`.
    /// - The upper-bound should not be too large: `max < usize::max_value()`.
    fn read_range(&mut self, min: usize, max: usize) -> usize {
        assert!(min <= max && max < usize::max_value());
        let count = max - min + 1;
        let delta = self.read_bits(num_bits(count - 1)) % count;
        min + delta
    }
}

/// Returns the number of bits necessary to represent a number.
fn num_bits(x: usize) -> usize {
    8 * std::mem::size_of::<usize>() - x.leading_zeros() as usize
}

#[test]
fn num_bits_ok() {
    assert_eq!(num_bits(0), 0);
    assert_eq!(num_bits(1), 1);
    assert_eq!(num_bits(2), 2);
    assert_eq!(num_bits(3), 2);
    assert_eq!(num_bits(4), 3);
    assert_eq!(num_bits(7), 3);
    assert_eq!(num_bits(8), 4);
    assert_eq!(num_bits(15), 4);
    assert_eq!(num_bits(16), 5);
    assert_eq!(
        num_bits(usize::max_value()),
        8 * std::mem::size_of::<usize>()
    );
}

#[test]
fn read_bit_ok() {
    let mut entropy = Entropy::new(&[0b10110010]);
    assert!(!entropy.read_bit());
    assert!(entropy.read_bit());
    assert!(!entropy.read_bit());
    assert!(!entropy.read_bit());
    assert!(entropy.read_bit());
    assert!(entropy.read_bit());
    assert!(!entropy.read_bit());
    assert!(entropy.read_bit());
}

#[test]
fn read_bits_ok() {
    let mut entropy = Entropy::new(&[0x83, 0x92]);
    assert_eq!(entropy.read_bits(4), 0x3);
    assert_eq!(entropy.read_bits(8), 0x28);
    assert_eq!(entropy.read_bits(2), 0b01);
    assert_eq!(entropy.read_bits(2), 0b10);
}

#[test]
fn read_range_ok() {
    let mut entropy = Entropy::new(&[0b00101011]);
    assert_eq!(entropy.read_range(0, 7), 0b011);
    assert_eq!(entropy.read_range(1, 8), 1 + 0b101);
    assert_eq!(entropy.read_range(4, 6), 4 + 0b00);
    let mut entropy = Entropy::new(&[0b00101011]);
    assert_eq!(entropy.read_range(0, 8), 0b1011 % 9);
    assert_eq!(entropy.read_range(3, 15), 3 + 0b0010);
    let mut entropy = Entropy::new(&[0x12, 0x34, 0x56, 0x78]);
    assert_eq!(entropy.read_range(0, usize::max_value() - 1), 0x78563412);
}
<|endoftext|>


<commit_before>//! `log` crate adapter for slog-rs
//!
//! This crate provides two way compatibility with Rust standard `log` crate.
//!
//! ### `log` -> `slog`
//!
//! After calling `init()` `slog-stdlog` will take a role of `log` crate
//! back-end, forwarding all the `log` logging to `slog_scope::logger()`.
//! In other words, any `log` crate logging statement will behave like it was `slog`
//! logging statement executed with logger returned by `slog_scope::logger()`.
//!
//! See documentation of `slog-scope` for more information about logging scopes.
//!
//! See [`init` documentation](fn.init.html) for an example.
//!
//! ### `slog` -> `log`
//!
//! `StdLog` is `slog::Drain` that will pass all `Record`s passing through it to
//! `log` crate just like they were crated with `log` crate logging macros in
//! the first place.
//!
//! ## `slog-scope`
//!
//! Since `log` does not have any form of context, and does not support `Logger`
//! `slog-stdlog` relies on "logging scopes" to establish it.
//!
//! You must set up logging context for `log` -> `slog` via `slog_scope::scope`
//! or `slog_scope::set_global_logger`. Setting a global logger upfront via
//! `slog_scope::set_global_logger` is highly recommended.
//!
//! Note: Since `slog-stdlog` v2, unlike previous releases, `slog-stdlog` uses
//! logging scopes provided by `slog-scope` crate instead of it's own.
//!
//! Refer to `slog-scope` crate documentation for more information.
//!
//! ### Warning
//!
//! Be careful when using both methods at the same time, as a loop can be easily
//! created: `log` -> `slog` -> `log` -> ...
//!
//! ## Compile-time log level filtering
//!
//! For filtering `debug!` and other `log` statements at compile-time, configure
//! the features on the `log` crate in your `Cargo.toml`:
//!
//! ```norust
//! log = { version = "*", features = ["max_level_trace", "release_max_level_warn"] }
//! ```
#![warn(missing_docs)]

extern crate log;

#[cfg(feature = "kv_unstable")]
mod kv;

use slog::{b, Level, KV};
use std::{fmt, io};

struct Logger;

fn log_to_slog_level(level: log::Level) -> Level {
    match level {
        log::Level::Trace => Level::Trace,
        log::Level::Debug => Level::Debug,
        log::Level::Info => Level::Info,
        log::Level::Warn => Level::Warning,
        log::Level::Error => Level::Error,
    }
}

fn record_as_location(r: &log::Record) -> slog::RecordLocation {
    let module = r.module_path_static().unwrap_or("<unknown>");
    let file = r.file_static().unwrap_or("<unknown>");
    let line = r.line().unwrap_or_default();

    slog::RecordLocation {
        file,
        line,
        column: 0,
        function: "",
        module,
    }
}

impl log::Log for Logger {
    fn enabled(&self, _: &log::Metadata) -> bool {
        true
    }

    fn log(&self, r: &log::Record) {
        let level = log_to_slog_level(r.metadata().level());

        let args = r.args();
        let target = r.target();
        let location = &record_as_location(r);
        let s = slog::RecordStatic {
            location,
            level,
            tag: target,
        };
        #[cfg(feature = "kv_unstable")]
        {
            let key_values = r.key_values();
            let mut visitor = kv::Visitor::new();
            key_values.visit(&mut visitor).unwrap();
            slog_scope::with_logger(|logger| logger.log(&slog::Record::new(&s, args, b!(visitor))))
        }
        #[cfg(not(feature = "kv_unstable"))]
        slog_scope::with_logger(|logger| logger.log(&slog::Record::new(&s, args, b!())))
    }

    fn flush(&self) {}
}

/// Register `slog-stdlog` as `log` backend.
///
/// This will pass all logging statements crated with `log`
/// crate to current `slog-scope::logger()`.
///
/// ```
/// #[macro_use]
/// extern crate log;
/// #[macro_use(slog_o, slog_kv)]
/// extern crate slog;
/// extern crate slog_stdlog;
/// extern crate slog_scope;
/// extern crate slog_term;
/// extern crate slog_async;
///
/// use slog::Drain;
///
/// fn main() {
///     let decorator = slog_term::TermDecorator::new().build();
///     let drain = slog_term::FullFormat::new(decorator).build().fuse();
///     let drain = slog_async::Async::new(drain).build().fuse();
///     let logger = slog::Logger::root(drain, slog_o!("version" => env!("CARGO_PKG_VERSION")));
///
///     let _scope_guard = slog_scope::set_global_logger(logger);
///     let _log_guard = slog_stdlog::init().unwrap();
///     // Note: this `info!(...)` macro comes from `log` crate
///     info!("standard logging redirected to slog");
/// }
/// ```
pub fn init() -> Result<(), log::SetLoggerError> {
    init_with_level(log::Level::max())
}

/// Register `slog-stdlog` as `log` backend.
/// Pass a log::Level to do the log filter explicitly.
///
/// This will pass all logging statements crated with `log`
/// crate to current `slog-scope::logger()`.
///
/// ```
/// #[macro_use]
/// extern crate log;
/// #[macro_use(slog_o, slog_kv)]
/// extern crate slog;
/// extern crate slog_stdlog;
/// extern crate slog_scope;
/// extern crate slog_term;
/// extern crate slog_async;
///
/// use slog::Drain;
///
/// fn main() {
///     let decorator = slog_term::TermDecorator::new().build();
///     let drain = slog_term::FullFormat::new(decorator).build().fuse();
///     let drain = slog_async::Async::new(drain).build().fuse();
///     let logger = slog::Logger::root(drain, slog_o!("version" => env!("CARGO_PKG_VERSION")));
///
///     let _scope_guard = slog_scope::set_global_logger(logger);
///     let _log_guard = slog_stdlog::init_with_level(log::Level::Error).unwrap();
///     // Note: this `info!(...)` macro comes from `log` crate
///     info!("standard logging redirected to slog");
///     error!("standard logging redirected to slog");
/// }
/// ```
pub fn init_with_level(level: log::Level) -> Result<(), log::SetLoggerError> {
    log::set_boxed_logger(Box::new(Logger))?;
    log::set_max_level(level.to_level_filter());

    Ok(())
}

/// Drain logging `Record`s into `log` crate
///
/// Any `Record` passing through this `Drain` will be forwarded
/// to `log` crate, just like it was created with `log` crate macros
/// in the first place. The message and key-value pairs will be formated
/// to be one string.
///
/// Caution needs to be taken to prevent circular loop where `Logger`
/// installed via `slog-stdlog::set_logger` would log things to a `StdLog`
/// drain, which would again log things to the global `Logger` and so on
/// leading to an infinite recursion.
pub struct StdLog;

struct LazyLogString<'a> {
    info: &'a slog::Record<'a>,
    logger_values: &'a slog::OwnedKVList,
}

impl<'a> LazyLogString<'a> {
    fn new(info: &'a slog::Record, logger_values: &'a slog::OwnedKVList) -> Self {
        LazyLogString {
            info,
            logger_values,
        }
    }
}

impl<'a> fmt::Display for LazyLogString<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.info.msg())?;

        let io = io::Cursor::new(Vec::new());
        let mut ser = KSV::new(io);

        self.logger_values
            .serialize(self.info, &mut ser)
            .map_err(|_| fmt::Error)?;
        self.info
            .kv()
            .serialize(self.info, &mut ser)
            .map_err(|_| fmt::Error)?;

        let values = ser.into_inner().into_inner();

        write!(f, "{}", String::from_utf8_lossy(&values))
    }
}

impl slog::Drain for StdLog {
    type Ok = ();
    type Err = io::Error;

    fn log(&self, info: &slog::Record, logger_values: &slog::OwnedKVList) -> io::Result<()> {
        let level = match info.level() {
            slog::Level::Critical | slog::Level::Error => log::Level::Error,
            slog::Level::Warning => log::Level::Warn,
            slog::Level::Info => log::Level::Info,
            slog::Level::Debug => log::Level::Debug,
            slog::Level::Trace => log::Level::Trace,
        };

        let mut target = info.tag();
        if target.is_empty() {
            target = info.module();
        }

        let lazy = LazyLogString::new(info, logger_values);
        /*
         * TODO: Support `log` crate key_values here.
         *
         * This requires the log/kv_unstable feature here.
         *
         * Not supporting this feature is backwards compatible
         * and it shouldn't break anything (because we've never had),
         * but is undesirable from a feature-completeness point of view.
         *
         * However, this is most likely not as powerful as slog's own
         * notion of key/value pairs, so I would humbly suggest using `slog`
         * directly if this feature is important to you ;)
         *
         * This avoids using the private log::__private_api_log api function,
         * which is just a thin wrapper around a `RecordBuilder`.
         */
        log::logger().log(
            &log::Record::builder()
                .args(format_args!("{}", lazy))
                .level(level)
                .target(target)
                .module_path_static(Some(info.module()))
                .file_static(Some(info.file()))
                .line(Some(info.line()))
                .build(),
        );

        Ok(())
    }
}

/// Key-Separator-Value serializer
struct KSV<W: io::Write> {
    io: W,
}

impl<W: io::Write> KSV<W> {
    fn new(io: W) -> Self {
        KSV { io: io }
    }

    fn into_inner(self) -> W {
        self.io
    }
}

impl<W: io::Write> slog::Serializer for KSV<W> {
    fn emit_arguments(&mut self, key: slog::Key, val: &fmt::Arguments) -> slog::Result {
        write!(self.io, ", {}: {}", key, val)?;
        Ok(())
    }
}
<commit_msg>Fix clippy lints<commit_after>//! `log` crate adapter for slog-rs
//!
//! This crate provides two way compatibility with Rust standard `log` crate.
//!
//! ### `log` -> `slog`
//!
//! After calling `init()` `slog-stdlog` will take a role of `log` crate
//! back-end, forwarding all the `log` logging to `slog_scope::logger()`.
//! In other words, any `log` crate logging statement will behave like it was `slog`
//! logging statement executed with logger returned by `slog_scope::logger()`.
//!
//! See documentation of `slog-scope` for more information about logging scopes.
//!
//! See [`init` documentation](fn.init.html) for an example.
//!
//! ### `slog` -> `log`
//!
//! `StdLog` is `slog::Drain` that will pass all `Record`s passing through it to
//! `log` crate just like they were crated with `log` crate logging macros in
//! the first place.
//!
//! ## `slog-scope`
//!
//! Since `log` does not have any form of context, and does not support `Logger`
//! `slog-stdlog` relies on "logging scopes" to establish it.
//!
//! You must set up logging context for `log` -> `slog` via `slog_scope::scope`
//! or `slog_scope::set_global_logger`. Setting a global logger upfront via
//! `slog_scope::set_global_logger` is highly recommended.
//!
//! Note: Since `slog-stdlog` v2, unlike previous releases, `slog-stdlog` uses
//! logging scopes provided by `slog-scope` crate instead of it's own.
//!
//! Refer to `slog-scope` crate documentation for more information.
//!
//! ### Warning
//!
//! Be careful when using both methods at the same time, as a loop can be easily
//! created: `log` -> `slog` -> `log` -> ...
//!
//! ## Compile-time log level filtering
//!
//! For filtering `debug!` and other `log` statements at compile-time, configure
//! the features on the `log` crate in your `Cargo.toml`:
//!
//! ```norust
//! log = { version = "*", features = ["max_level_trace", "release_max_level_warn"] }
//! ```
#![warn(missing_docs)]

extern crate log;

#[cfg(feature = "kv_unstable")]
mod kv;

use slog::{b, Level, KV};
use std::{fmt, io};

struct Logger;

fn log_to_slog_level(level: log::Level) -> Level {
    match level {
        log::Level::Trace => Level::Trace,
        log::Level::Debug => Level::Debug,
        log::Level::Info => Level::Info,
        log::Level::Warn => Level::Warning,
        log::Level::Error => Level::Error,
    }
}

fn record_as_location(r: &log::Record) -> slog::RecordLocation {
    let module = r.module_path_static().unwrap_or("<unknown>");
    let file = r.file_static().unwrap_or("<unknown>");
    let line = r.line().unwrap_or_default();

    slog::RecordLocation {
        file,
        line,
        column: 0,
        function: "",
        module,
    }
}

impl log::Log for Logger {
    fn enabled(&self, _: &log::Metadata) -> bool {
        true
    }

    fn log(&self, r: &log::Record) {
        let level = log_to_slog_level(r.metadata().level());

        let args = r.args();
        let target = r.target();
        let location = &record_as_location(r);
        let s = slog::RecordStatic {
            location,
            level,
            tag: target,
        };
        #[cfg(feature = "kv_unstable")]
        {
            let key_values = r.key_values();
            let mut visitor = kv::Visitor::new();
            key_values.visit(&mut visitor).unwrap();
            slog_scope::with_logger(|logger| logger.log(&slog::Record::new(&s, args, b!(visitor))))
        }
        #[cfg(not(feature = "kv_unstable"))]
        slog_scope::with_logger(|logger| logger.log(&slog::Record::new(&s, args, b!())))
    }

    fn flush(&self) {}
}

/// Register `slog-stdlog` as `log` backend.
///
/// This will pass all logging statements crated with `log`
/// crate to current `slog-scope::logger()`.
///
/// ```
/// #[macro_use]
/// extern crate log;
/// #[macro_use(slog_o, slog_kv)]
/// extern crate slog;
/// extern crate slog_stdlog;
/// extern crate slog_scope;
/// extern crate slog_term;
/// extern crate slog_async;
///
/// use slog::Drain;
///
/// fn main() {
///     let decorator = slog_term::TermDecorator::new().build();
///     let drain = slog_term::FullFormat::new(decorator).build().fuse();
///     let drain = slog_async::Async::new(drain).build().fuse();
///     let logger = slog::Logger::root(drain, slog_o!("version" => env!("CARGO_PKG_VERSION")));
///
///     let _scope_guard = slog_scope::set_global_logger(logger);
///     let _log_guard = slog_stdlog::init().unwrap();
///     // Note: this `info!(...)` macro comes from `log` crate
///     info!("standard logging redirected to slog");
/// }
/// ```
pub fn init() -> Result<(), log::SetLoggerError> {
    init_with_level(log::Level::max())
}

/// Register `slog-stdlog` as `log` backend.
/// Pass a log::Level to do the log filter explicitly.
///
/// This will pass all logging statements crated with `log`
/// crate to current `slog-scope::logger()`.
///
/// ```
/// #[macro_use]
/// extern crate log;
/// #[macro_use(slog_o, slog_kv)]
/// extern crate slog;
/// extern crate slog_stdlog;
/// extern crate slog_scope;
/// extern crate slog_term;
/// extern crate slog_async;
///
/// use slog::Drain;
///
/// fn main() {
///     let decorator = slog_term::TermDecorator::new().build();
///     let drain = slog_term::FullFormat::new(decorator).build().fuse();
///     let drain = slog_async::Async::new(drain).build().fuse();
///     let logger = slog::Logger::root(drain, slog_o!("version" => env!("CARGO_PKG_VERSION")));
///
///     let _scope_guard = slog_scope::set_global_logger(logger);
///     let _log_guard = slog_stdlog::init_with_level(log::Level::Error).unwrap();
///     // Note: this `info!(...)` macro comes from `log` crate
///     info!("standard logging redirected to slog");
///     error!("standard logging redirected to slog");
/// }
/// ```
pub fn init_with_level(level: log::Level) -> Result<(), log::SetLoggerError> {
    log::set_boxed_logger(Box::new(Logger))?;
    log::set_max_level(level.to_level_filter());

    Ok(())
}

/// Drain logging `Record`s into `log` crate
///
/// Any `Record` passing through this `Drain` will be forwarded
/// to `log` crate, just like it was created with `log` crate macros
/// in the first place. The message and key-value pairs will be formated
/// to be one string.
///
/// Caution needs to be taken to prevent circular loop where `Logger`
/// installed via `slog-stdlog::set_logger` would log things to a `StdLog`
/// drain, which would again log things to the global `Logger` and so on
/// leading to an infinite recursion.
pub struct StdLog;

struct LazyLogString<'a> {
    info: &'a slog::Record<'a>,
    logger_values: &'a slog::OwnedKVList,
}

impl<'a> LazyLogString<'a> {
    fn new(info: &'a slog::Record, logger_values: &'a slog::OwnedKVList) -> Self {
        LazyLogString {
            info,
            logger_values,
        }
    }
}

impl<'a> fmt::Display for LazyLogString<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self.info.msg())?;

        let io = io::Cursor::new(Vec::new());
        let mut ser = Ksv::new(io);

        self.logger_values
            .serialize(self.info, &mut ser)
            .map_err(|_| fmt::Error)?;
        self.info
            .kv()
            .serialize(self.info, &mut ser)
            .map_err(|_| fmt::Error)?;

        let values = ser.into_inner().into_inner();

        write!(f, "{}", String::from_utf8_lossy(&values))
    }
}

impl slog::Drain for StdLog {
    type Ok = ();
    type Err = io::Error;

    fn log(&self, info: &slog::Record, logger_values: &slog::OwnedKVList) -> io::Result<()> {
        let level = match info.level() {
            slog::Level::Critical | slog::Level::Error => log::Level::Error,
            slog::Level::Warning => log::Level::Warn,
            slog::Level::Info => log::Level::Info,
            slog::Level::Debug => log::Level::Debug,
            slog::Level::Trace => log::Level::Trace,
        };

        let mut target = info.tag();
        if target.is_empty() {
            target = info.module();
        }

        let lazy = LazyLogString::new(info, logger_values);
        /*
         * TODO: Support `log` crate key_values here.
         *
         * This requires the log/kv_unstable feature here.
         *
         * Not supporting this feature is backwards compatible
         * and it shouldn't break anything (because we've never had),
         * but is undesirable from a feature-completeness point of view.
         *
         * However, this is most likely not as powerful as slog's own
         * notion of key/value pairs, so I would humbly suggest using `slog`
         * directly if this feature is important to you ;)
         *
         * This avoids using the private log::__private_api_log api function,
         * which is just a thin wrapper around a `RecordBuilder`.
         */
        log::logger().log(
            &log::Record::builder()
                .args(format_args!("{}", lazy))
                .level(level)
                .target(target)
                .module_path_static(Some(info.module()))
                .file_static(Some(info.file()))
                .line(Some(info.line()))
                .build(),
        );

        Ok(())
    }
}

/// Key-Separator-Value serializer
struct Ksv<W: io::Write> {
    io: W,
}

impl<W: io::Write> Ksv<W> {
    fn new(io: W) -> Self {
        Ksv { io }
    }

    fn into_inner(self) -> W {
        self.io
    }
}

impl<W: io::Write> slog::Serializer for Ksv<W> {
    fn emit_arguments(&mut self, key: slog::Key, val: &fmt::Arguments) -> slog::Result {
        write!(self.io, ", {}: {}", key, val)?;
        Ok(())
    }
}
<|endoftext|>


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

// compile-flags: -Z borrowck=compare

use std::cell::Cell;
use std::mem::swap;

// Just a grab bag of stuff that you wouldn't want to actually write.

fn strange() -> bool { let _x: bool = return true; }

fn funny() {
    fn f(_x: ()) { }
    f(return);
}

fn what() {
    fn the(x: &Cell<bool>) {
        return while !x.get() { x.set(true); };
    }
    let i = &Cell::new(false);
    let dont = {||the(i)};
    dont();
    assert!((i.get()));
}

fn zombiejesus() {
    loop {
        while (return) {
            if (return) {
                match (return) {
                    1 => {
                        if (return) {
                            return
                        } else {
                            return
                        }
                    }
                    _ => { return }
                };
            } else if (return) {
                return;
            }
        }
        if (return) { break; }
    }
}

fn notsure() {
    let mut _x: isize;
    let mut _y = (_x = 0) == (_x = 0);
    let mut _z = (_x = 0) < (_x = 0);
    let _a = (_x += 0) == (_x = 0);
    let _b = swap(&mut _y, &mut _z) == swap(&mut _y, &mut _z);
}

fn canttouchthis() -> usize {
    fn p() -> bool { true }
    let _a = (assert!((true)) == (assert!(p())));
    let _c = (assert!((p())) == ());
    let _b: bool = (println!("{}", 0) == (return 0));
}

fn angrydome() {
    loop { if break { } }
    let mut i = 0;
    loop { i += 1; if i == 1 { match (continue) { 1 => { }, _ => panic!("wat") } }
      break; }
}

fn evil_lincoln() { let _evil = println!("lincoln"); }

fn dots() {
    assert_eq!(String::from(".................................................."),
               format!("{:?}", .. .. .. .. .. .. .. .. .. .. .. .. ..
                               .. .. .. .. .. .. .. .. .. .. .. ..));
}

fn you_eight() {
    assert_eq!(8, {
        macro_rules! u8 {
            (u8) => {
                mod u8 {
                    pub fn u8<'u8>(u8: &'u8 u8) -> &'u8 u8 {
                        "u8";
                        u8
                    }
                }
            };
        }

        u8!(u8);
        let &u8: &u8 = u8::u8(&8u8);
        u8
    });
}

fn fishy() {
    assert_eq!(String::from("><>"),
               String::<>::from::<>("><>").chars::<>().rev::<>().collect::<String>());
}

fn union() {
    union union<'union> { union: &'union union<'union>, }
}

fn special_characters() {
    let val = !((|(..):(_,_),__@_|__)((&*"\\",'🤔')/**/,{})=={&[..=..][..];})//
    ;
    assert!(!val);
}

pub fn main() {
    strange();
    funny();
    what();
    zombiejesus();
    notsure();
    canttouchthis();
    angrydome();
    evil_lincoln();
    dots();
    you_eight();
    fishy();
    union();
    special_characters();
}
<commit_msg>Increase number of usages of `u8` in weird expressions u8 test<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// compile-flags: -Z borrowck=compare

use std::cell::Cell;
use std::mem::swap;

// Just a grab bag of stuff that you wouldn't want to actually write.

fn strange() -> bool { let _x: bool = return true; }

fn funny() {
    fn f(_x: ()) { }
    f(return);
}

fn what() {
    fn the(x: &Cell<bool>) {
        return while !x.get() { x.set(true); };
    }
    let i = &Cell::new(false);
    let dont = {||the(i)};
    dont();
    assert!((i.get()));
}

fn zombiejesus() {
    loop {
        while (return) {
            if (return) {
                match (return) {
                    1 => {
                        if (return) {
                            return
                        } else {
                            return
                        }
                    }
                    _ => { return }
                };
            } else if (return) {
                return;
            }
        }
        if (return) { break; }
    }
}

fn notsure() {
    let mut _x: isize;
    let mut _y = (_x = 0) == (_x = 0);
    let mut _z = (_x = 0) < (_x = 0);
    let _a = (_x += 0) == (_x = 0);
    let _b = swap(&mut _y, &mut _z) == swap(&mut _y, &mut _z);
}

fn canttouchthis() -> usize {
    fn p() -> bool { true }
    let _a = (assert!((true)) == (assert!(p())));
    let _c = (assert!((p())) == ());
    let _b: bool = (println!("{}", 0) == (return 0));
}

fn angrydome() {
    loop { if break { } }
    let mut i = 0;
    loop { i += 1; if i == 1 { match (continue) { 1 => { }, _ => panic!("wat") } }
      break; }
}

fn evil_lincoln() { let _evil = println!("lincoln"); }

fn dots() {
    assert_eq!(String::from(".................................................."),
               format!("{:?}", .. .. .. .. .. .. .. .. .. .. .. .. ..
                               .. .. .. .. .. .. .. .. .. .. .. ..));
}

fn u8(u8: u8) {
    if u8 != 0u8 {
        assert_eq!(8u8, {
            macro_rules! u8 {
                (u8) => {
                    mod u8 {
                        pub fn u8<'u8: 'u8 + 'u8>(u8: &'u8 u8) -> &'u8 u8 {
                            "u8";
                            u8
                        }
                    }
                };
            }

            u8!(u8);
            let &u8: &u8 = u8::u8(&8u8);
            ::u8(0u8);
            u8
        });
    }
}

fn fishy() {
    assert_eq!(String::from("><>"),
               String::<>::from::<>("><>").chars::<>().rev::<>().collect::<String>());
}

fn union() {
    union union<'union> { union: &'union union<'union>, }
}

fn special_characters() {
    let val = !((|(..):(_,_),__@_|__)((&*"\\",'🤔')/**/,{})=={&[..=..][..];})//
    ;
    assert!(!val);
}

pub fn main() {
    strange();
    funny();
    what();
    zombiejesus();
    notsure();
    canttouchthis();
    angrydome();
    evil_lincoln();
    dots();
    u8(8u8);
    fishy();
    union();
    special_characters();
}
<|endoftext|>


<commit_before>// Copyright 2014 The rust-pcre authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(unused_must_use)]
#![feature(phase)]

#[phase(plugin, link)] extern crate log;
extern crate rustc;

use rustc::driver::driver::host_triple;
use std::from_str::{from_str};
use std::io;
use std::io::{Command, FilePermission};
use std::io::fs::{mkdir, File};
use std::option::{Option};
use std::os;
use std::str;

#[deriving(Eq, PartialEq)]
struct Version {
    major: uint,
    minor: uint
}

impl Version {
    pub fn parse(version_str: &str) -> Option<Version> {
        let mut it = version_str.split('.');
        match (it.next().and_then(from_str::<uint>), it.next().and_then(from_str::<uint>)) {
            (Some(major), Some(minor)) => Some(Version { major: major, minor: minor }),
            _                          => None
        }
    }
}

impl std::fmt::Show for Version {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{:u}.{:u}", self.major, self.minor)
    }
}

impl PartialOrd for Version {
    fn partial_cmp(&self, other: &Version) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Version {
    fn cmp(&self, other: &Version) -> Ordering {
        (self.major, self.minor).cmp(&(other.major, other.minor))
    }
}

fn cd(path: &Path) {
    if !os::change_dir(path) {
        fail!("Package script error: Failed to `cd` into `{}`", path.display());
    }
}

fn main() {
    let pcre_libdir = match os::getenv("PCRE_LIBDIR") {
        None            => {
            let pcre_config_output = match Command::new("pcre-config").arg("--prefix").output() {
                Err(e) => {
                    match e.kind {
                        io::FileNotFound => fail!("Package script error: Could not run `pcre-config` because no such executable is in the executable search PATH. Make sure that you have installed a dev package for libpcre and/or make sure that libpcre's bindir is added to your PATH (currently \"{}\").", os::getenv("PATH").unwrap_or(String::from_str(""))),
                        _ => fail!("Package script error: Could not run `pcre-config`: {}", e)
                    }
                },
                Ok(pcre_config_output) => pcre_config_output
            };
            if !pcre_config_output.status.success() {
                fail!("Package script error: `pcre-config --prefix` failed");
            }
            let output_ptr = pcre_config_output.output.as_ptr();
            let output_len = pcre_config_output.output.len();
            let prefix_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };
            // `pcre-config` adds a newline to the end, which we need to trim away.
            String::from_str(prefix_str.as_slice().trim()).append("/lib")
        },
        Some(pcre_libdir) => pcre_libdir
    };
    let pcre_lib_path = Path::new(pcre_libdir);

    let workspace_path = os::getcwd();

    // Check the version
    let target_build_path = workspace_path.join("build").join(host_triple());
    if !target_build_path.exists() {
        if mkdir(&target_build_path, FilePermission::from_bits_truncate(0x1FF)).is_err() {
            fail!("Package script error: Failed to create target build directory `{}`", target_build_path.display());
        }
    }
    let out_path = target_build_path.join("pcre");
    if !out_path.exists() {
        if mkdir(&out_path, FilePermission::from_bits_truncate(0x1FF)).is_err() {
            fail!("Package script error: Failed to create output directory `{}`", out_path.display());
        }
    }

    let versioncheck_rs_path = out_path.join("versioncheck.rs");
    {
        let mut f = match File::create(&versioncheck_rs_path) {
            Err(e) => fail!("Package script error: Failed to open `{}` for writing: {}", versioncheck_rs_path.display(), e),
            Ok(f) => f
        };
        let contents = format!("\
extern crate libc;

use std::c_str::{{CString}};
use libc::{{c_char, c_int, c_uchar, c_void}};
use std::ptr;
use std::ptr::{{RawPtr}};
use std::slice;

type options = c_int;
struct pcre;
struct pcre_extra;

#[link(name = \"pcre\")]
extern {{
    static pcre_free: extern \"C\" fn(ptr: *const c_void);

    fn pcre_compile(pattern: *const c_char, options: options, errptr: *mut *const c_char, erroffset: *mut c_int, tableptr: *const c_uchar) -> *const pcre;
    fn pcre_exec(code: *const pcre, extra: *const pcre_extra, subject: *const c_char, length: c_int, startoffset: c_int, options: options, ovector: *mut c_int, ovecsize: c_int) -> c_int;
    fn pcre_version() -> *const c_char;
}}

fn main () {{
    unsafe {{
        let version_cstring = CString::new(pcre_version(), false);
        let version_str = version_cstring.as_str().unwrap().to_string();

        let pattern = \"^\\\\d+\\\\.\\\\d+\";
        pattern.with_c_str(|pattern_c_str| {{
            let mut err: *const c_char = ptr::null();
            let mut erroffset: c_int = 0;
            let code = pcre_compile(pattern_c_str, 0, &mut err, &mut erroffset, ptr::null());
            if code.is_null() {{
                if code.is_null() {{
                    let err_cstring = CString::new(err, false);
                    match err_cstring.as_str() {{
                        None          => fail!(\"pcre_compile() failed at offset {{}}\", erroffset as uint),
                        Some(err_str) => fail!(\"pcre_compile() failed at offset {{}}: {{}}\", erroffset as uint, err_str)
                    }}
                }}
            }}
            assert!(code.is_not_null());

            let ovecsize = 1 * 3;
            let mut ovector = Vec::from_elem(ovecsize, 0 as c_int);
            version_str.with_c_str_unchecked(|version_c_str| {{
                let rc = pcre_exec(code, ptr::null(), version_c_str, version_str.len() as c_int, 0, 0, ovector.as_mut_ptr(), ovecsize as c_int);
                if rc < 0 {{
                    fail!(\"pcre_exec() failed\");
                }}

                print!(\"{{}}\", version_str.as_slice().slice_to(*ovector.get(1) as uint));
            }});

            pcre_free(code as *const c_void);
        }});
    }}
}}
");
        f.write_str(contents.as_slice()).map_err(|e| -> () {
            fail!("Package script error: Failed to write to `{}`: {}", versioncheck_rs_path.display(), e);
        });
    }

    // Compile and run `versioncheck.rs`
    cd(&out_path);
    let rustc_output = match Command::new("rustc").arg("versioncheck.rs").arg("-L").arg(pcre_lib_path.clone()).output() {
        Err(e) => fail!("Package script error: Failed to run `rustc`: {}", e),
        Ok(rustc_output) => rustc_output
    };
    if !rustc_output.status.success() {
        println!("{}", str::from_utf8(rustc_output.output.as_slice()));
        println!("{}", str::from_utf8(rustc_output.error.as_slice()));
        fail!("Package script error: `rustc versioncheck.rs` failed: {}", rustc_output.status);
    }
    let versioncheck_output = match Command::new("./versioncheck").output() {
        Err(e) => fail!("Package script error: Failed to run `./versioncheck`: {}", e),
        Ok(versioncheck_output) => versioncheck_output
    };
    if !versioncheck_output.status.success() {
        println!("{}", str::from_utf8(versioncheck_output.output.as_slice()));
        println!("{}", str::from_utf8(versioncheck_output.error.as_slice()));
        fail!("versioncheck error: {}", versioncheck_output.status);
    }
    cd(&workspace_path);

    let output_ptr = versioncheck_output.output.as_ptr();
    let output_len = versioncheck_output.output.len();
    let output_str = unsafe { str::raw::from_buf_len(output_ptr, output_len) };
    debug!("output_str = `{}`", output_str);

    // The "no debug symbols in executable" warning may be present in the output.
    // https://github.com/mozilla/rust/issues/3495
    let mut output_rsplit_iter = output_str.as_slice().split('\n').rev();
    let version_str: String = match output_rsplit_iter.next() {
        None              => output_str.clone(),
        Some(version_str) => version_str.to_string()
    };

    debug!("libpcre version {:s}", version_str.as_slice());

    let min_required_version = Version::parse("8.20").unwrap();
    let pcre_version = match Version::parse(version_str.as_slice()) {
        None               => fail!("Package script error: Failed to parse version string '{}'", version_str.as_slice()),
        Some(pcre_version) => pcre_version
    };

    if pcre_version < min_required_version {
        fail!("Package script error: Found libpcre version {}, but at least version {} is required", version_str.as_slice(), min_required_version);
    }

    // Create directories `bin` and `lib`
    let bin_path = workspace_path.join("bin");
    if !bin_path.exists() {
        if mkdir(&bin_path, FilePermission::from_bits_truncate(0x1FF)).is_err() {
            fail!("Package script error: Failed to create the `bin` directory");
        }
    }
    let lib_path = workspace_path.join("lib");
    if !lib_path.exists() {
        if mkdir(&lib_path, FilePermission::from_bits_truncate(0x1FF)).is_err() {
            fail!("Package script error: Failed to create the `lib` directory");
        }
    }

    // Compile libpcre-*.rlib
    match Command::new("rustc").arg("--out-dir").arg(lib_path).arg("src/pcre/mod.rs").arg("-L").arg(pcre_lib_path.clone()).output() {
        Err(e) => fail!("Package script error: Failed to run `rustc`: {}", e),
        Ok(rustc_output) => {
            if !rustc_output.status.success() {
                println!("{}", str::from_utf8(rustc_output.output.as_slice()));
                println!("{}", str::from_utf8(rustc_output.error.as_slice()));
                fail!("Package script error: `rustc src/pcre/mod.rs` failed: {}", rustc_output.status);
            }
        }
    }

    match Command::new("rustc").arg("-o").arg(bin_path.join("pcredemo")).arg("src/pcredemo/main.rs").arg("-L").arg("lib").arg("-L").arg(pcre_lib_path.clone()).output() {
        Err(e) => fail!("Package script error: Failed to run `rustc`: {}", e),
        Ok(rustc_output) => {
            if !rustc_output.status.success() {
                println!("{}", str::from_utf8(rustc_output.output.as_slice()));
                println!("{}", str::from_utf8(rustc_output.error.as_slice()));
                fail!("Package script error: `rustc src/pcredemo/main.rs` failed: {}", rustc_output.status);
            }
        }
    }
}
<commit_msg>Switch to string::raw::from_buf_len()<commit_after>// Copyright 2014 The rust-pcre authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![allow(unused_must_use)]
#![feature(phase)]

#[phase(plugin, link)] extern crate log;
extern crate rustc;

use rustc::driver::driver::host_triple;
use std::from_str::{from_str};
use std::io;
use std::io::{Command, FilePermission};
use std::io::fs::{mkdir, File};
use std::option::{Option};
use std::os;
use std::str;
use std::string;

#[deriving(Eq, PartialEq)]
struct Version {
    major: uint,
    minor: uint
}

impl Version {
    pub fn parse(version_str: &str) -> Option<Version> {
        let mut it = version_str.split('.');
        match (it.next().and_then(from_str::<uint>), it.next().and_then(from_str::<uint>)) {
            (Some(major), Some(minor)) => Some(Version { major: major, minor: minor }),
            _                          => None
        }
    }
}

impl std::fmt::Show for Version {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{:u}.{:u}", self.major, self.minor)
    }
}

impl PartialOrd for Version {
    fn partial_cmp(&self, other: &Version) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Version {
    fn cmp(&self, other: &Version) -> Ordering {
        (self.major, self.minor).cmp(&(other.major, other.minor))
    }
}

fn cd(path: &Path) {
    if !os::change_dir(path) {
        fail!("Package script error: Failed to `cd` into `{}`", path.display());
    }
}

fn main() {
    let pcre_libdir = match os::getenv("PCRE_LIBDIR") {
        None            => {
            let pcre_config_output = match Command::new("pcre-config").arg("--prefix").output() {
                Err(e) => {
                    match e.kind {
                        io::FileNotFound => fail!("Package script error: Could not run `pcre-config` because no such executable is in the executable search PATH. Make sure that you have installed a dev package for libpcre and/or make sure that libpcre's bindir is added to your PATH (currently \"{}\").", os::getenv("PATH").unwrap_or(String::from_str(""))),
                        _ => fail!("Package script error: Could not run `pcre-config`: {}", e)
                    }
                },
                Ok(pcre_config_output) => pcre_config_output
            };
            if !pcre_config_output.status.success() {
                fail!("Package script error: `pcre-config --prefix` failed");
            }
            let output_ptr = pcre_config_output.output.as_ptr();
            let output_len = pcre_config_output.output.len();
            let prefix_str = unsafe { string::raw::from_buf_len(output_ptr, output_len) };
            // `pcre-config` adds a newline to the end, which we need to trim away.
            String::from_str(prefix_str.as_slice().trim()).append("/lib")
        },
        Some(pcre_libdir) => pcre_libdir
    };
    let pcre_lib_path = Path::new(pcre_libdir);

    let workspace_path = os::getcwd();

    // Check the version
    let target_build_path = workspace_path.join("build").join(host_triple());
    if !target_build_path.exists() {
        if mkdir(&target_build_path, FilePermission::from_bits_truncate(0x1FF)).is_err() {
            fail!("Package script error: Failed to create target build directory `{}`", target_build_path.display());
        }
    }
    let out_path = target_build_path.join("pcre");
    if !out_path.exists() {
        if mkdir(&out_path, FilePermission::from_bits_truncate(0x1FF)).is_err() {
            fail!("Package script error: Failed to create output directory `{}`", out_path.display());
        }
    }

    let versioncheck_rs_path = out_path.join("versioncheck.rs");
    {
        let mut f = match File::create(&versioncheck_rs_path) {
            Err(e) => fail!("Package script error: Failed to open `{}` for writing: {}", versioncheck_rs_path.display(), e),
            Ok(f) => f
        };
        let contents = format!("\
extern crate libc;

use std::c_str::{{CString}};
use libc::{{c_char, c_int, c_uchar, c_void}};
use std::ptr;
use std::ptr::{{RawPtr}};
use std::slice;

type options = c_int;
struct pcre;
struct pcre_extra;

#[link(name = \"pcre\")]
extern {{
    static pcre_free: extern \"C\" fn(ptr: *const c_void);

    fn pcre_compile(pattern: *const c_char, options: options, errptr: *mut *const c_char, erroffset: *mut c_int, tableptr: *const c_uchar) -> *const pcre;
    fn pcre_exec(code: *const pcre, extra: *const pcre_extra, subject: *const c_char, length: c_int, startoffset: c_int, options: options, ovector: *mut c_int, ovecsize: c_int) -> c_int;
    fn pcre_version() -> *const c_char;
}}

fn main () {{
    unsafe {{
        let version_cstring = CString::new(pcre_version(), false);
        let version_str = version_cstring.as_str().unwrap().to_string();

        let pattern = \"^\\\\d+\\\\.\\\\d+\";
        pattern.with_c_str(|pattern_c_str| {{
            let mut err: *const c_char = ptr::null();
            let mut erroffset: c_int = 0;
            let code = pcre_compile(pattern_c_str, 0, &mut err, &mut erroffset, ptr::null());
            if code.is_null() {{
                if code.is_null() {{
                    let err_cstring = CString::new(err, false);
                    match err_cstring.as_str() {{
                        None          => fail!(\"pcre_compile() failed at offset {{}}\", erroffset as uint),
                        Some(err_str) => fail!(\"pcre_compile() failed at offset {{}}: {{}}\", erroffset as uint, err_str)
                    }}
                }}
            }}
            assert!(code.is_not_null());

            let ovecsize = 1 * 3;
            let mut ovector = Vec::from_elem(ovecsize, 0 as c_int);
            version_str.with_c_str_unchecked(|version_c_str| {{
                let rc = pcre_exec(code, ptr::null(), version_c_str, version_str.len() as c_int, 0, 0, ovector.as_mut_ptr(), ovecsize as c_int);
                if rc < 0 {{
                    fail!(\"pcre_exec() failed\");
                }}

                print!(\"{{}}\", version_str.as_slice().slice_to(*ovector.get(1) as uint));
            }});

            pcre_free(code as *const c_void);
        }});
    }}
}}
");
        f.write_str(contents.as_slice()).map_err(|e| -> () {
            fail!("Package script error: Failed to write to `{}`: {}", versioncheck_rs_path.display(), e);
        });
    }

    // Compile and run `versioncheck.rs`
    cd(&out_path);
    let rustc_output = match Command::new("rustc").arg("versioncheck.rs").arg("-L").arg(pcre_lib_path.clone()).output() {
        Err(e) => fail!("Package script error: Failed to run `rustc`: {}", e),
        Ok(rustc_output) => rustc_output
    };
    if !rustc_output.status.success() {
        println!("{}", str::from_utf8(rustc_output.output.as_slice()));
        println!("{}", str::from_utf8(rustc_output.error.as_slice()));
        fail!("Package script error: `rustc versioncheck.rs` failed: {}", rustc_output.status);
    }
    let versioncheck_output = match Command::new("./versioncheck").output() {
        Err(e) => fail!("Package script error: Failed to run `./versioncheck`: {}", e),
        Ok(versioncheck_output) => versioncheck_output
    };
    if !versioncheck_output.status.success() {
        println!("{}", str::from_utf8(versioncheck_output.output.as_slice()));
        println!("{}", str::from_utf8(versioncheck_output.error.as_slice()));
        fail!("versioncheck error: {}", versioncheck_output.status);
    }
    cd(&workspace_path);

    let output_ptr = versioncheck_output.output.as_ptr();
    let output_len = versioncheck_output.output.len();
    let output_str = unsafe { string::raw::from_buf_len(output_ptr, output_len) };
    debug!("output_str = `{}`", output_str);

    // The "no debug symbols in executable" warning may be present in the output.
    // https://github.com/mozilla/rust/issues/3495
    let mut output_rsplit_iter = output_str.as_slice().split('\n').rev();
    let version_str: String = match output_rsplit_iter.next() {
        None              => output_str.clone(),
        Some(version_str) => version_str.to_string()
    };

    debug!("libpcre version {:s}", version_str.as_slice());

    let min_required_version = Version::parse("8.20").unwrap();
    let pcre_version = match Version::parse(version_str.as_slice()) {
        None               => fail!("Package script error: Failed to parse version string '{}'", version_str.as_slice()),
        Some(pcre_version) => pcre_version
    };

    if pcre_version < min_required_version {
        fail!("Package script error: Found libpcre version {}, but at least version {} is required", version_str.as_slice(), min_required_version);
    }

    // Create directories `bin` and `lib`
    let bin_path = workspace_path.join("bin");
    if !bin_path.exists() {
        if mkdir(&bin_path, FilePermission::from_bits_truncate(0x1FF)).is_err() {
            fail!("Package script error: Failed to create the `bin` directory");
        }
    }
    let lib_path = workspace_path.join("lib");
    if !lib_path.exists() {
        if mkdir(&lib_path, FilePermission::from_bits_truncate(0x1FF)).is_err() {
            fail!("Package script error: Failed to create the `lib` directory");
        }
    }

    // Compile libpcre-*.rlib
    match Command::new("rustc").arg("--out-dir").arg(lib_path).arg("src/pcre/mod.rs").arg("-L").arg(pcre_lib_path.clone()).output() {
        Err(e) => fail!("Package script error: Failed to run `rustc`: {}", e),
        Ok(rustc_output) => {
            if !rustc_output.status.success() {
                println!("{}", str::from_utf8(rustc_output.output.as_slice()));
                println!("{}", str::from_utf8(rustc_output.error.as_slice()));
                fail!("Package script error: `rustc src/pcre/mod.rs` failed: {}", rustc_output.status);
            }
        }
    }

    match Command::new("rustc").arg("-o").arg(bin_path.join("pcredemo")).arg("src/pcredemo/main.rs").arg("-L").arg("lib").arg("-L").arg(pcre_lib_path.clone()).output() {
        Err(e) => fail!("Package script error: Failed to run `rustc`: {}", e),
        Ok(rustc_output) => {
            if !rustc_output.status.success() {
                println!("{}", str::from_utf8(rustc_output.output.as_slice()));
                println!("{}", str::from_utf8(rustc_output.error.as_slice()));
                fail!("Package script error: `rustc src/pcredemo/main.rs` failed: {}", rustc_output.status);
            }
        }
    }
}
<|endoftext|>