<commit_before>use serialize::json::{Json};
use anymap::AnyMap;
use std::os;

use server::{Request, Response};
use errors::{Error, FileError};
use middleware::{Application, HandleResult};
use framework::endpoint::Endpoint;
use framework::media::Media;
use server_backend::status;
use server_backend::mime;
use server_backend::header::{Header, HeaderFormat};
use server_backend::header::common::{ContentType, Location};
use {Extensible};

pub struct Client<'a> {
    pub app: &'a Application,
    pub endpoint: &'a Endpoint,
    pub request: &'a mut Request,
    pub media: &'a Media,
    pub ext: AnyMap,
    pub response: Response
}

pub type ClientResult<'a> = HandleResult<Client<'a>>;

impl<'a> Client<'a> {

    pub fn new(app: &'a Application, endpoint: &'a Endpoint, request: &'a mut Request, media: &'a Media) -> Client<'a> {
        Client {
            app: app,
            endpoint: endpoint,
            request: request,
            media: media,
            ext: AnyMap::new(),
            response: Response::new(status::Ok)
        }
    }

    //
    // Work with status
    //

    pub fn status(&mut self) -> status::StatusCode {
        self.response.status
    }

    pub fn set_status(&mut self, status: status::StatusCode) {
        self.response.status = status;
    }

    pub fn unauthorized(&mut self) {
        self.response.status = status::Unauthorized;
    }

    pub fn forbidden(&mut self) {
        self.response.status = status::Forbidden;
    }

    pub fn not_found(&mut self) {
        self.response.status = status::NotFound;
    }

    pub fn internal_server_error(&mut self) {
        self.response.status = status::InternalServerError;
    }

    pub fn not_implemented(&mut self) {
        self.response.status = status::NotImplemented;
    }

    //

    pub fn set_header<H: Header + HeaderFormat>(&mut self, header: H) {
        self.response.set_header(header);
    }

    pub fn set_json_content_type(&mut self) {
        self.set_header(ContentType(mime::Mime(mime::Application, mime::Json, vec![])));
    }

    pub fn set_content_type(&mut self, mime: mime::Mime) {
        self.set_header(ContentType(mime));
    }

    pub fn error<T: Error>(self, error: T) -> ClientResult<'a> {
        Err(box error as Box<Error>)
    }

    pub fn json(mut self, result: &Json) -> ClientResult<'a> {
        self.set_json_content_type();
        self.response.push_string(result.to_string());

        Ok(self)
    }

    pub fn text(mut self, result: String) -> ClientResult<'a> {
        self.response.push_string(result);

        Ok(self)
    }

    pub fn file(mut self, path: &Path) -> ClientResult<'a> {
       match self.response.push_file(&os::make_absolute(path)) {
            Ok(()) => Ok(self),
            Err(err) => {
                return Err(box FileError(err) as Box<Error>);
            }
        }
    }

    pub fn redirect(mut self, to: &str) -> ClientResult<'a> {
        self.set_status(status::Found);
        self.set_header(Location(to.to_string()));

        Ok(self)
    }

    pub fn permanent_redirect(mut self, to: &str) -> ClientResult<'a> {
        self.set_status(status::MovedPermanently);
        self.set_header(Location(to.to_string()));

        Ok(self)
    }

    pub fn move_response(self) -> Response {
        self.response
    }

    pub fn ext(&self) -> &AnyMap {
        &self.ext
    }

    pub fn ext_mut(&mut self) -> &mut AnyMap {
        &mut self.ext
    }

}

impl<'a> Extensible for Client<'a> {
    fn ext(&self) -> &::anymap::AnyMap { &self.ext }
    fn ext_mut(&mut self) -> &mut ::anymap::AnyMap { &mut self.ext }
}<commit_msg>feat: allow to chain `Client` methods<commit_after>use serialize::json::{Json};
use anymap::AnyMap;
use std::os;

use server::{Request, Response};
use errors::{Error, FileError};
use middleware::{Application, HandleResult};
use framework::endpoint::Endpoint;
use framework::media::Media;
use server_backend::status;
use server_backend::mime;
use server_backend::header::{Header, HeaderFormat};
use server_backend::header::common::{ContentType, Location};
use {Extensible};

pub struct Client<'a> {
    pub app: &'a Application,
    pub endpoint: &'a Endpoint,
    pub request: &'a mut Request,
    pub media: &'a Media,
    pub ext: AnyMap,
    pub response: Response
}

pub type ClientResult<'a> = HandleResult<Client<'a>>;

impl<'a> Client<'a> {

    pub fn new(app: &'a Application, endpoint: &'a Endpoint, request: &'a mut Request, media: &'a Media) -> Client<'a> {
        Client {
            app: app,
            endpoint: endpoint,
            request: request,
            media: media,
            ext: AnyMap::new(),
            response: Response::new(status::Ok)
        }
    }

    //
    // Work with status
    //

    pub fn status(&mut self) -> status::StatusCode {
        self.response.status
    }

    pub fn set_status(&mut self, status: status::StatusCode) -> &mut Client<'a> {
        self.response.status = status;
        self
    }

    pub fn unauthorized(&mut self) -> &mut Client<'a> {
        self.response.status = status::Unauthorized;
        self
    }

    pub fn forbidden(&mut self) -> &mut Client<'a> {
        self.response.status = status::Forbidden;
        self
    }

    pub fn not_found(&mut self) -> &mut Client<'a> {
        self.response.status = status::NotFound;
        self
    }

    pub fn internal_server_error(&mut self) -> &mut Client<'a> {
        self.response.status = status::InternalServerError;
        self
    }

    pub fn not_implemented(&mut self) -> &mut Client<'a> {
        self.response.status = status::NotImplemented;
        self
    }

    //

    pub fn set_header<H: Header + HeaderFormat>(&mut self, header: H) -> &mut Client<'a> {
        self.response.set_header(header);
        self
    }

    pub fn set_json_content_type(&mut self) -> &mut Client<'a> {
        self.set_header(ContentType(mime::Mime(mime::Application, mime::Json, vec![])));
        self
    }

    pub fn set_content_type(&mut self, mime: mime::Mime) -> &mut Client<'a> {
        self.set_header(ContentType(mime));
        self
    }

    pub fn error<T: Error>(self, error: T) -> ClientResult<'a> {
        Err(box error as Box<Error>)
    }

    pub fn json(mut self, result: &Json) -> ClientResult<'a> {
        self.set_json_content_type();
        self.response.push_string(result.to_string());

        Ok(self)
    }

    pub fn text(mut self, result: String) -> ClientResult<'a> {
        self.response.push_string(result);

        Ok(self)
    }

    pub fn file(mut self, path: &Path) -> ClientResult<'a> {
       match self.response.push_file(&os::make_absolute(path)) {
            Ok(()) => Ok(self),
            Err(err) => {
                return Err(box FileError(err) as Box<Error>);
            }
        }
    }

    pub fn redirect(mut self, to: &str) -> ClientResult<'a> {
        self.set_status(status::Found);
        self.set_header(Location(to.to_string()));

        Ok(self)
    }

    pub fn permanent_redirect(mut self, to: &str) -> ClientResult<'a> {
        self.set_status(status::MovedPermanently);
        self.set_header(Location(to.to_string()));

        Ok(self)
    }

    pub fn move_response(self) -> Response {
        self.response
    }

    pub fn ext(&self) -> &AnyMap {
        &self.ext
    }

    pub fn ext_mut(&mut self) -> &mut AnyMap {
        &mut self.ext
    }

}

impl<'a> Extensible for Client<'a> {
    fn ext(&self) -> &::anymap::AnyMap { &self.ext }
    fn ext_mut(&mut self) -> &mut ::anymap::AnyMap { &mut self.ext }
}<|endoftext|>


<commit_before>use uuid::Uuid;
use message::Message;

/// Broadcast represents a single bi-directional communication with two
/// nodes within the cluster. The communication does **not** need to be
/// bi-directional. Responses are completely optional.
///
/// Each broadcast is tagged with a unique ID so that we may track
/// which node has received a given broadcast.
pub struct Broadcast<'a, T> {
    /// A unique id (uuidv4) representing the broadcast. This will allow us to keep
    /// track of it when dealing with many broadcasts and we receive them in
    /// different orders.
    id: Uuid,

    /// Request is an arbitrary type. This allows users
    /// to specify their own custom broadcasts to be sent and received.
    request: T,

    /// Each broadcast may have an **optional** response of a different
    /// type than the request. The closure will be called once we receive
    /// the full response.
    ///
    /// The closure is not guaranteed to be ran on a specific thread.
    response: Option<|response: Box<Message>|: 'a>
}

impl<'a, T> Broadcast<'a, T> {

    pub fn new(message: T) -> Broadcast<'a, T> {
        Broadcast {
            id: Uuid::new_v4(),
            request: message,
            response: None
        }
    }

    /// Add a response to the broadcast, which isn't required. Once
    /// the response has been received, the closure will be called.
    ///
    /// ```rust
    /// Broadcast::new(Message).with_response(|response| {
    ///     // Do something with the response
    /// });
    /// ```
    ///
    /// To allow chaining, we'll return a reference to the broadcast
    /// object.
    pub fn with_response(&mut self, response: |response: Box<Message>|: 'a) {
        self.response = Some(response);
    }
}

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

    #[test]
    fn have_no_response() {
        let broadcast = Broadcast::new(123);
        assert!(broadcast.response.is_none());
    }

    #[test]
    fn add_response() {
        let mut broadcast = Broadcast::new(123);
        broadcast.with_response(|response| {

        });

        assert!(broadcast.response.is_some());
    }
}<commit_msg>Refactored the broadcast api<commit_after>use uuid::Uuid;
use message::Message;

/// Broadcast represents a single bi-directional communication with two
/// nodes within the cluster. The communication does **not** need to be
/// bi-directional. Responses are completely optional.
///
/// Each broadcast is tagged with a unique ID so that we may track
/// which node has received a given broadcast.
pub struct Broadcast<'a, T> {
    /// A unique id (uuidv4) representing the broadcast. This will allow us to keep
    /// track of it when dealing with many broadcasts and we receive them in
    /// different orders.
    id: Uuid,

    /// Request is an arbitrary type. This allows users
    /// to specify their own custom broadcasts to be sent and received.
    request: T,

    /// Each broadcast may have an **optional** response of a different
    /// type than the request. The closure will be called once we receive
    /// the full response.
    ///
    /// The closure is not guaranteed to be ran on a specific thread.
    response: Option<|response: Box<Message>|: 'a>
}

impl<'a, T> Broadcast<'a, T> {

    pub fn new(message: T) -> Broadcast<'a, T> {
        Broadcast {
            id: Uuid::new_v4(),
            request: message,
            response: None
        }
    }

    /// Add a response to the broadcast, which isn't required. Once
    /// the response has been received, the closure will be called.
    ///
    /// ```rust
    /// Broadcast::new(Message).with_response(|response| {
    ///     // Do something with the response
    /// });
    /// ```
    ///
    /// To allow chaining, we'll return a reference to the broadcast
    /// object.
    pub fn with_response(message: T,
                         response: |response: Box<Message>|: 'a) -> Broadcast<'a, T> {
        Broadcast {
            id: Uuid::new_v4(),
            request: message,
            response: Some(response)
        }
    }
}

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

    #[test]
    fn have_no_response() {
        let broadcast = Broadcast::new(123);
        assert!(broadcast.response.is_none());
    }

    #[test]
    fn add_response() {
        let mut broadcast = Broadcast::with_response(123, |response| {

        });

        assert!(broadcast.response.is_some());
    }
}<|endoftext|>


<commit_before>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// 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.

/*!
UART configuration.

This code doesn't support UART1, while it really should (UART1 has more features
than other UARTs in MCU).
*/

use core::intrinsics::abort;

use hal::lpc17xx::peripheral_clock::{PeripheralClock, UART0Clock, UART2Clock, UART3Clock};
use drivers::chario::CharIO;
use hal::uart;

#[path="../../lib/ioreg.rs"] mod ioreg;
#[path="../../lib/wait_for.rs"] mod wait_for;

/// Available UART peripherals.
pub enum UARTPeripheral {
  UART0,
  UART2,
  UART3,
}

/// UART word length.
pub enum WordLen {
  WordLen5bits = 0b00,
  WordLen6bits = 0b01,
  WordLen7bits = 0b10,
  WordLen8bits = 0b11,
}

impl WordLen {
  pub fn from_u8(val: u8) -> WordLen {
    match val {
      5 => WordLen5bits,
      6 => WordLen6bits,
      7 => WordLen7bits,
      8 => WordLen8bits,
      _ => unsafe { abort() },
    }
  }
}

/// Stop bits configuration.
pub enum StopBit {
  StopBit1bit  = 0b0_00,
  StopBit2bits = 0b1_00,
}

impl StopBit {
  pub fn from_u8(val: u8) -> StopBit {
    match val {
      1 => StopBit1bit,
      2 => StopBit2bits,
      _ => unsafe { abort() },
    }
  }
}

enum ParityEnabled {
  PEDisabled = 0b0_0_00,
  PEEnabled  = 0b1_0_00,
}

enum ParitySelect {
  PSOdd    = 0b00_0_0_00,
  PSEven   = 0b01_0_0_00,
  PSForced1 = 0b10_0_0_00,
  PSForced0 = 0b11_0_0_00,
}

#[allow(dead_code)]
enum BreakControl {
  BCDisabled = 0b0_00_0_0_00,
  BCEnabled  = 0b1_00_0_0_00,
}

enum FIFOEnabled {
  FEEnabled  = 0b1,
  FEDisabled = 0b0,
}

enum FIFODmaMode {
  FDEnabled  = 0b1_0_0_0,
  FDDisabled = 0b0_0_0_0,
}

enum FIFOTriggerLevel {
  FT1char   = 0b00_00_0_0_0_0,
  FT4chars  = 0b01_00_0_0_0_0,
  FT8chars  = 0b10_00_0_0_0_0,
  FT14chars = 0b11_00_0_0_0_0,
}

static FIFOResetRx: u8 = 0b1_0;
static FIFOResetTx: u8 = 0b1_0_0;

static LCRModeMask: u8 = 0b1_11_1_1_11;

static LSRTHREmpty: u8 = 0x20;

pub struct UART {
  reg: &'static reg::UART,
  clock: PeripheralClock,
}

impl UARTPeripheral {
  fn reg(self) -> &reg::UART {
    match self {
      UART0 => &reg::UART0,
      UART2 => &reg::UART2,
      UART3 => &reg::UART3,
    }
  }

  fn peripheral_clock(self) -> PeripheralClock {
    match self {
      UART0 => UART0Clock,
      UART2 => UART2Clock,
      UART3 => UART3Clock,
    }
  }
}

impl UART {
  pub fn new(peripheral: UARTPeripheral, baudrate: u32, word_len: u8,
      parity: uart::Parity, stop_bits: u8) -> UART {
    let uart = UART {
      reg: peripheral.reg(),
      clock: peripheral.peripheral_clock(),
    };

    uart.clock.enable();
    uart.set_baud_rate(baudrate);
    uart.set_mode(WordLen::from_u8(word_len), parity,
        StopBit::from_u8(stop_bits));
    uart.set_fifo_enabled(true, true);

    uart
  }

  #[no_split_stack]
  fn uart_clock(&self) -> u32 {
    self.clock.frequency()
  }

  #[no_split_stack]
  fn set_baud_rate(&self, baud_rate: u32) {
    self.reg.set_LCR(0b1000_0000); // enable divisor latch access

    let (dl, div_add_val, mul_val) = self.calculate_divisors(baud_rate);

    self.reg.set_DLM((dl >> 8) & 0xff);
    self.reg.set_DLL(dl & 0xff);
    self.reg.set_FDR(div_add_val | (mul_val << 4));

    self.reg.set_LCR(3);
  }

  #[no_split_stack]
  fn set_mode(&self, word_len: WordLen, parity: uart::Parity, stop_bits: StopBit) {
    let lcr: u8 = (*(self.reg)).LCR() as u8;
    let computed_val: u8 = word_len as u8 | stop_bits as u8 | match parity {
      uart::Disabled => PEDisabled as u8  | PSOdd as u8,
      uart::Odd      => PEEnabled as u8   | PSOdd as u8,
      uart::Even     => PEEnabled as u8   | PSEven as u8,
      uart::Forced1  => PEEnabled as u8   | PSForced1 as u8,
      uart::Forced0  => PEEnabled as u8   | PSForced0 as u8,
    };
    let new_lcr = (lcr & !LCRModeMask) | computed_val;

    (*(self.reg)).set_LCR(new_lcr as u32);
  }

  fn set_fifo_enabled(&self, enabled: bool, reset: bool) {
    let val: u8 = match enabled {
      true => FEEnabled as u8,
      false => FEDisabled as u8
    } | match reset {
      true  => FIFOResetTx & FIFOResetRx,
      false => 0,
    } | FDDisabled as u8 | FT1char as u8;

    (*(self.reg)).set_FCR(val as u32);
  }

  // TODO(farcaller): license note
  // loosely based on serial_api.c
  // Copyright (c) 2006-2013 ARM Limited
  // Licensed under the Apache License, Version 2.0
  fn calculate_divisors(&self, baud_rate: u32) -> (u32, u32, u32) {
    let baudrate: u32 = baud_rate;
    let pclk = self.uart_clock();
    let mut dl: u32 = pclk / (16 * baudrate);

    let mut div_add_val: u32 = 0;
    let mut mul_val: u32 = 1;
    let mut hit = false;
    let mut dlv: u32;
    let mut mv: u32;
    let mut dav: u32;
    if pclk % (16 * baudrate) != 0 {     // Checking for zero remainder
      let mut err_best: u32 = baudrate;
      let mut b: i32;

      mv = 1;
      while mv < 16 && !hit {
        dav = 0;
        while dav < mv {
          if (mv * pclk * 2) & 0x80000000 == 0x80000000 {
            dlv = ((((2 * mv * pclk) / (baudrate * (dav + mv))) / 16) + 1) / 2;
          } else {
            dlv = ((((4 * mv * pclk) / (baudrate * (dav + mv))) / 32) + 1) / 2;
          }

          if dlv == 0 {
            dlv = 1;
          }

          if (dav > 0) && (dlv < 2) {
            dlv = 2;
          }

          b = (((pclk * mv / (dlv * (dav + mv) * 8)) + 1) / 2) as i32;

          b = b - baudrate as i32;
          if b < 0 {
            b = -b;
          }
          if (b as u32) < err_best {
            err_best  = b as u32;

            dl        = dlv;
            mul_val    = mv;
            div_add_val = dav;

            if (b as u32) == baudrate {
              hit = true;
              break;
            }
          }
          dav += 1;
        }
        mv += 1;
      }
    }
    return (dl, div_add_val, mul_val)
  }
}

impl CharIO for UART {
  fn putc(&self, value: char) {
    wait_for!(self.reg.LSR() as u8 & LSRTHREmpty == LSRTHREmpty);
    self.reg.set_THR(value as u32);
  }
}

mod reg {
  use lib::volatile_cell::VolatileCell;

  ioreg!(UART: u32, RBR_THR_DLL, DLM_IER, IIR_FCR, LCR, _pad_0, LSR, _pad_1, SCR, ACR, ICR, FDR, _pad_2, TER)
  reg_r!( UART, u32, RBR,          RBR_THR_DLL)
  reg_w!( UART, u32,      set_THR, RBR_THR_DLL)
  reg_rw!(UART, u32, DLL, set_DLL, RBR_THR_DLL)
  reg_rw!(UART, u32, DLM, set_DLM, DLM_IER)
  reg_rw!(UART, u32, IER, set_IER, DLM_IER)
  reg_r!( UART, u32, IIR,          IIR_FCR)
  reg_w!( UART, u32,      set_FCR, IIR_FCR)
  reg_rw!(UART, u32, LCR, set_LCR, LCR)
  reg_r!( UART, u32, LSR,          LSR)
  reg_rw!(UART, u32, SCR, set_SCR, SCR)
  reg_rw!(UART, u32, ACR, set_ACR, ACR)
  reg_rw!(UART, u32, ICR, set_ICR, ICR)
  reg_rw!(UART, u32, FDR, set_FDR, FDR)
  reg_rw!(UART, u32, TER, set_TER, TER)

  extern {
    #[link_name="iomem_UART0"] pub static UART0: UART;
    #[link_name="iomem_UART2"] pub static UART2: UART;
    #[link_name="iomem_UART3"] pub static UART3: UART;
  }
}
<commit_msg>lpc17xx::uart: Shuffle register constants<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Vladimir "farcaller" Pouzanov <farcaller@gmail.com>
//
// 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.

/*!
UART configuration.

This code doesn't support UART1, while it really should (UART1 has more features
than other UARTs in MCU).
*/

use core::intrinsics::abort;

use hal::lpc17xx::peripheral_clock::{PeripheralClock, UART0Clock, UART2Clock, UART3Clock};
use drivers::chario::CharIO;
use hal::uart;

#[path="../../lib/ioreg.rs"] mod ioreg;
#[path="../../lib/wait_for.rs"] mod wait_for;

/// Available UART peripherals.
pub enum UARTPeripheral {
  UART0,
  UART2,
  UART3,
}

/// UART word length.
pub enum WordLen {
  WordLen5bits = 0b00,
  WordLen6bits = 0b01,
  WordLen7bits = 0b10,
  WordLen8bits = 0b11,
}

impl WordLen {
  pub fn from_u8(val: u8) -> WordLen {
    match val {
      5 => WordLen5bits,
      6 => WordLen6bits,
      7 => WordLen7bits,
      8 => WordLen8bits,
      _ => unsafe { abort() },
    }
  }
}

/// Stop bits configuration.
pub enum StopBit {
  StopBit1bit  = 0b0_00,
  StopBit2bits = 0b1_00,
}

impl StopBit {
  pub fn from_u8(val: u8) -> StopBit {
    match val {
      1 => StopBit1bit,
      2 => StopBit2bits,
      _ => unsafe { abort() },
    }
  }
}

enum ParityEnabled {
  PEDisabled = 0b0_0_00,
  PEEnabled  = 0b1_0_00,
}

enum ParitySelect {
  PSOdd    = 0b00_0_0_00,
  PSEven   = 0b01_0_0_00,
  PSForced1 = 0b10_0_0_00,
  PSForced0 = 0b11_0_0_00,
}

#[allow(dead_code)]
enum BreakControl {
  BCDisabled = 0b0_00_0_0_00,
  BCEnabled  = 0b1_00_0_0_00,
}

enum FIFOEnabled {
  FEEnabled  = 0b1,
  FEDisabled = 0b0,
}

enum FIFODmaMode {
  FDEnabled  = 0b1_0_0_0,
  FDDisabled = 0b0_0_0_0,
}

enum FIFOTriggerLevel {
  FT1char   = 0b00_00_0_0_0_0,
  FT4chars  = 0b01_00_0_0_0_0,
  FT8chars  = 0b10_00_0_0_0_0,
  FT14chars = 0b11_00_0_0_0_0,
}

pub struct UART {
  reg: &'static reg::UART,
  clock: PeripheralClock,
}

impl UARTPeripheral {
  fn reg(self) -> &reg::UART {
    match self {
      UART0 => &reg::UART0,
      UART2 => &reg::UART2,
      UART3 => &reg::UART3,
    }
  }

  fn peripheral_clock(self) -> PeripheralClock {
    match self {
      UART0 => UART0Clock,
      UART2 => UART2Clock,
      UART3 => UART3Clock,
    }
  }
}

impl UART {
  pub fn new(peripheral: UARTPeripheral, baudrate: u32, word_len: u8,
      parity: uart::Parity, stop_bits: u8) -> UART {
    let uart = UART {
      reg: peripheral.reg(),
      clock: peripheral.peripheral_clock(),
    };

    uart.clock.enable();
    uart.set_baud_rate(baudrate);
    uart.set_mode(WordLen::from_u8(word_len), parity,
        StopBit::from_u8(stop_bits));
    uart.set_fifo_enabled(true, true);

    uart
  }

  #[no_split_stack]
  fn uart_clock(&self) -> u32 {
    self.clock.frequency()
  }

  #[no_split_stack]
  fn set_baud_rate(&self, baud_rate: u32) {
    self.reg.set_LCR(0b1000_0000); // enable divisor latch access

    let (dl, div_add_val, mul_val) = self.calculate_divisors(baud_rate);

    self.reg.set_DLM((dl >> 8) & 0xff);
    self.reg.set_DLL(dl & 0xff);
    self.reg.set_FDR(div_add_val | (mul_val << 4));

    self.reg.set_LCR(3);
  }

  #[no_split_stack]
  fn set_mode(&self, word_len: WordLen, parity: uart::Parity, stop_bits: StopBit) {
    let lcr: u8 = (*(self.reg)).LCR() as u8;
    let computed_val: u8 = word_len as u8 | stop_bits as u8 | match parity {
      uart::Disabled => PEDisabled as u8  | PSOdd as u8,
      uart::Odd      => PEEnabled as u8   | PSOdd as u8,
      uart::Even     => PEEnabled as u8   | PSEven as u8,
      uart::Forced1  => PEEnabled as u8   | PSForced1 as u8,
      uart::Forced0  => PEEnabled as u8   | PSForced0 as u8,
    };
    let new_lcr = (lcr & !LCRModeMask) | computed_val;

    (*(self.reg)).set_LCR(new_lcr as u32);
  }

  fn set_fifo_enabled(&self, enabled: bool, reset: bool) {
    let val: u8 = match enabled {
      true => FEEnabled as u8,
      false => FEDisabled as u8
    } | match reset {
      true  => FIFOResetTx & FIFOResetRx,
      false => 0,
    } | FDDisabled as u8 | FT1char as u8;

    (*(self.reg)).set_FCR(val as u32);
  }

  // TODO(farcaller): license note
  // loosely based on serial_api.c
  // Copyright (c) 2006-2013 ARM Limited
  // Licensed under the Apache License, Version 2.0
  fn calculate_divisors(&self, baud_rate: u32) -> (u32, u32, u32) {
    let baudrate: u32 = baud_rate;
    let pclk = self.uart_clock();
    let mut dl: u32 = pclk / (16 * baudrate);

    let mut div_add_val: u32 = 0;
    let mut mul_val: u32 = 1;
    let mut hit = false;
    let mut dlv: u32;
    let mut mv: u32;
    let mut dav: u32;
    if pclk % (16 * baudrate) != 0 {     // Checking for zero remainder
      let mut err_best: u32 = baudrate;
      let mut b: i32;

      mv = 1;
      while mv < 16 && !hit {
        dav = 0;
        while dav < mv {
          if (mv * pclk * 2) & 0x80000000 == 0x80000000 {
            dlv = ((((2 * mv * pclk) / (baudrate * (dav + mv))) / 16) + 1) / 2;
          } else {
            dlv = ((((4 * mv * pclk) / (baudrate * (dav + mv))) / 32) + 1) / 2;
          }

          if dlv == 0 {
            dlv = 1;
          }

          if (dav > 0) && (dlv < 2) {
            dlv = 2;
          }

          b = (((pclk * mv / (dlv * (dav + mv) * 8)) + 1) / 2) as i32;

          b = b - baudrate as i32;
          if b < 0 {
            b = -b;
          }
          if (b as u32) < err_best {
            err_best  = b as u32;

            dl        = dlv;
            mul_val    = mv;
            div_add_val = dav;

            if (b as u32) == baudrate {
              hit = true;
              break;
            }
          }
          dav += 1;
        }
        mv += 1;
      }
    }
    return (dl, div_add_val, mul_val)
  }
}

impl CharIO for UART {
  fn putc(&self, value: char) {
    wait_for!(self.reg.LSR() as u8 & LSRTHREmpty == LSRTHREmpty);
    self.reg.set_THR(value as u32);
  }
}

static FIFOResetRx: u8 = 0b1_0;
static FIFOResetTx: u8 = 0b1_0_0;

static LCRModeMask: u8 = 0b1_11_1_1_11;

static LSRTHREmpty: u8 = 0x20;

mod reg {
  use lib::volatile_cell::VolatileCell;

  ioreg!(UART: u32, RBR_THR_DLL, DLM_IER, IIR_FCR, LCR, _pad_0, LSR, _pad_1, SCR, ACR, ICR, FDR, _pad_2, TER)
  reg_r!( UART, u32, RBR,          RBR_THR_DLL)
  reg_w!( UART, u32,      set_THR, RBR_THR_DLL)
  reg_rw!(UART, u32, DLL, set_DLL, RBR_THR_DLL)
  reg_rw!(UART, u32, DLM, set_DLM, DLM_IER)
  reg_rw!(UART, u32, IER, set_IER, DLM_IER)
  reg_r!( UART, u32, IIR,          IIR_FCR)
  reg_w!( UART, u32,      set_FCR, IIR_FCR)
  reg_rw!(UART, u32, LCR, set_LCR, LCR)
  reg_r!( UART, u32, LSR,          LSR)
  reg_rw!(UART, u32, SCR, set_SCR, SCR)
  reg_rw!(UART, u32, ACR, set_ACR, ACR)
  reg_rw!(UART, u32, ICR, set_ICR, ICR)
  reg_rw!(UART, u32, FDR, set_FDR, FDR)
  reg_rw!(UART, u32, TER, set_TER, TER)

  extern {
    #[link_name="iomem_UART0"] pub static UART0: UART;
    #[link_name="iomem_UART2"] pub static UART2: UART;
    #[link_name="iomem_UART3"] pub static UART3: UART;
  }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;
extern crate dialoguer;
extern crate duct;
#[macro_use]
extern crate error_chain;
extern crate serde;
extern crate serde_json;
extern crate snapshot;
extern crate walkdir;

use std::ffi::OsStr;
use std::fs::File;
use std::io::BufReader;

use clap::{Arg, SubCommand};
use dialoguer::{Checkboxes, Select};
use duct::cmd;
use snapshot::SnapFileContents;
use walkdir::WalkDir;

error_chain!{
    types {
        Error, ErrorKind, ResultExt, SnapResult;
    }

    foreign_links {
        Io(::std::io::Error);
    }
}

quick_main!(run);

fn run() -> SnapResult<()> {
    let input = app_from_crate!()
        .subcommand(
            SubCommand::with_name("update")
                .about("Update snapshots.")
                .arg(Arg::with_name("all").short("a").long("all").help(
                    "Unconditionally update all snapshots, including unrecorded ones.",
                )),
        )
        .get_matches();

    if let Some(update_matches) = input.subcommand_matches("update") {
        if update_matches.is_present("all") {
            let output = cmd("cargo", &["test"])
                .env("UPDATE_SNAPSHOTS", "1")
                .stdout_capture()
                .stderr_capture()
                .run()
                .chain_err(|| "unable to execute cargo")?;

            if !output.status.success() {
                // TODO(dikaiosune) print what failed
                bail!("unable to update all snapshots!");
            }
        } else {
            interactive_process()?;
        }
        println!("\nAll updates processed!");
    } else {
        panic!("unsupported command");
    }

    Ok(())
}

fn interactive_process() -> SnapResult<()> {
    let test_function_names = find_existing_snapshot_test_names()?;
    let mut failed_tests = Vec::new();

    println!("Checking for out of date snapshot tests...");
    for test_fn in test_function_names {
        let mut test_fn_chunks = test_fn.splitn(2, "::");

        // skip the crate name
        test_fn_chunks
            .next()
            .expect("looks like an empty test function name");

        let real_test_fn = test_fn_chunks
            .next()
            .expect("seemingly malformed test name");

        let first_run = cmd("cargo", &["test", &real_test_fn])
            .stdout_capture()
            .stderr_capture()
            .run()
            .chain_err(|| "unable to execute cargo")?;

        if !first_run.status.success() {
            failed_tests.push(real_test_fn.to_owned());
        }
    }

    if failed_tests.is_empty() {
        println!("\nNo snapshot tests require an update!");
        ::std::process::exit(0);
    } else {
        println!("\nPlease select which snapshot tests should be updated:");
        println!("  <Space> to select, <Enter> to submit\n");

        let mut menu = Checkboxes::new();
        for failed in &failed_tests {
            menu.item(failed);
        }
        let all_to_update = menu.interact().expect("error accepting user selections");

        for fn_idx in all_to_update {
            let fn_to_update = &failed_tests[fn_idx];
            println!("Updating {}...", &fn_to_update);

            let mut run_test = true;
            while run_test {
                let run_output = cmd("cargo", &["test", fn_to_update])
                    .env("UPDATE_SNAPSHOTS", "1")
                    .stdout_capture()
                    .stderr_capture()
                    .run()
                    .chain_err(|| "unable to execute cargo")?;

                if run_output.status.success() {
                    run_test = false;
                } else {
                    println!("\nUpdating {} failed! What would you like to do?",
                             fn_to_update);

                    match capture_failure_selection()? {
                        TestFailureSelection::Retry => continue,
                        TestFailureSelection::Skip => break,
                        TestFailureSelection::Abort => {
                            println!("\nExiting...");
                            ::std::process::exit(1);
                        }
                    }
                }
            }
        }

        Ok(())
    }
}

fn find_existing_snapshot_test_names() -> SnapResult<Vec<String>> {
    let cwd = ::std::env::current_dir()
        .chain_err(|| "unable to read cwd")?;

    // FIXME(adam) don't just throw away errors;
    let existing: Vec<SnapFileContents> = WalkDir::new(cwd)
        .into_iter()
        .map(|r| r.expect("unable to traverse project directory"))
        .filter(|e| e.path().extension() == Some(OsStr::new("snap")))
        .map(|p| BufReader::new(File::open(p.path()).expect("unable to open snapshot file")))
        .map(|r| serde_json::from_reader(r).expect("unable to parse snapshot file"))
        .collect::<Vec<_>>();

    let mut test_function_names = Vec::new();
    for snap_file in existing {
        for fun in snap_file.keys() {
            test_function_names.push(fun.clone());
        }
    }
    Ok(test_function_names)
}

enum TestFailureSelection {
    Retry,
    Skip,
    Abort,
}

fn capture_failure_selection() -> SnapResult<TestFailureSelection> {
    let options = ["Retry", "Skip", "Abort"];

    let selection = Select::new()
        .items(&options)
        .interact()
        .chain_err(|| "unable to retrieve user input")?;

    if options[selection] == "Retry" {
        Ok(TestFailureSelection::Retry)
    } else if options[selection] == "Skip" {
        Ok(TestFailureSelection::Skip)
    } else if options[selection] == "Abort" {
        Ok(TestFailureSelection::Abort)
    } else {
        bail!("invalid menu selection")
    }
}
<commit_msg>Refactor fn name search to preserve error info.<commit_after>#[macro_use]
extern crate clap;
extern crate dialoguer;
extern crate duct;
#[macro_use]
extern crate error_chain;
extern crate serde;
extern crate serde_json;
extern crate snapshot;
extern crate walkdir;

use std::ffi::OsStr;
use std::fs::File;
use std::io::BufReader;

use clap::{Arg, SubCommand};
use dialoguer::{Checkboxes, Select};
use duct::cmd;
use snapshot::SnapFileContents;
use walkdir::WalkDir;

error_chain!{
    types {
        Error, ErrorKind, ResultExt, SnapResult;
    }

    foreign_links {
        Io(::std::io::Error);
    }
}

quick_main!(run);

fn run() -> SnapResult<()> {
    let input = app_from_crate!()
        .subcommand(
            SubCommand::with_name("update")
                .about("Update snapshots.")
                .arg(Arg::with_name("all").short("a").long("all").help(
                    "Unconditionally update all snapshots, including unrecorded ones.",
                )),
        )
        .get_matches();

    if let Some(update_matches) = input.subcommand_matches("update") {
        if update_matches.is_present("all") {
            let output = cmd("cargo", &["test"])
                .env("UPDATE_SNAPSHOTS", "1")
                .stdout_capture()
                .stderr_capture()
                .run()
                .chain_err(|| "unable to execute cargo")?;

            if !output.status.success() {
                // TODO(dikaiosune) print what failed
                bail!("unable to update all snapshots!");
            }
        } else {
            interactive_process()?;
        }
        println!("\nAll updates processed!");
    } else {
        panic!("unsupported command");
    }

    Ok(())
}

fn interactive_process() -> SnapResult<()> {
    let test_function_names = find_existing_snapshot_test_names()?;
    let mut failed_tests = Vec::new();

    println!("Checking for out of date snapshot tests...");
    for test_fn in test_function_names {
        let mut test_fn_chunks = test_fn.0.splitn(2, "::");

        // skip the crate name
        test_fn_chunks
            .next()
            .expect("looks like an empty test function name");

        let real_test_fn = test_fn_chunks
            .next()
            .expect("seemingly malformed test name");

        let first_run = cmd("cargo", &["test", &real_test_fn])
            .stdout_capture()
            .stderr_capture()
            .run()
            .chain_err(|| "unable to execute cargo")?;

        if !first_run.status.success() {
            failed_tests.push(real_test_fn.to_owned());
        }
    }

    if failed_tests.is_empty() {
        println!("\nNo snapshot tests require an update!");
        ::std::process::exit(0);
    } else {
        println!("\nPlease select which snapshot tests should be updated:");
        println!("  <Space> to select, <Enter> to submit\n");

        let mut menu = Checkboxes::new();
        for failed in &failed_tests {
            menu.item(failed);
        }
        let all_to_update = menu.interact().expect("error accepting user selections");

        for fn_idx in all_to_update {
            let fn_to_update = &failed_tests[fn_idx];
            println!("Updating {}...", &fn_to_update);

            let mut run_test = true;
            while run_test {
                let run_output = cmd("cargo", &["test", fn_to_update])
                    .env("UPDATE_SNAPSHOTS", "1")
                    .stdout_capture()
                    .stderr_capture()
                    .run()
                    .chain_err(|| "unable to execute cargo")?;

                if run_output.status.success() {
                    run_test = false;
                } else {
                    println!("\nUpdating {} failed! What would you like to do?",
                             fn_to_update);

                    match capture_failure_selection()? {
                        TestFailureSelection::Retry => continue,
                        TestFailureSelection::Skip => break,
                        TestFailureSelection::Abort => {
                            println!("\nExiting...");
                            ::std::process::exit(1);
                        }
                    }
                }
            }
        }

        Ok(())
    }
}

struct FnName(String);

fn find_existing_snapshot_test_names() -> SnapResult<Vec<FnName>> {
    let cwd = ::std::env::current_dir()
        .chain_err(|| "unable to read cwd")?;

    let mut existing: Vec<SnapFileContents> = Vec::new();

    let snap_extension = OsStr::new("snap");
    for walk_result in WalkDir::new(cwd) {
        let entry = walk_result
            .chain_err(|| "unable to traverse project directory")?;

        if entry.path().extension() == Some(snap_extension) {
            let rdr = BufReader::new(File::open(entry.path())
                                         .chain_err(|| "unable to open snapshot file")?);
            let contents = serde_json::from_reader(rdr)
                .chain_err(|| "unable to parse snapshot file")?;
            existing.push(contents);
        }
    }

    let mut test_function_names = Vec::new();
    for snap_file in existing {
        for fun in snap_file.keys() {
            test_function_names.push(FnName(fun.clone()));
        }
    }
    Ok(test_function_names)
}

enum TestFailureSelection {
    Retry,
    Skip,
    Abort,
}

fn capture_failure_selection() -> SnapResult<TestFailureSelection> {
    let options = ["Retry", "Skip", "Abort"];

    let selection = Select::new()
        .items(&options)
        .interact()
        .chain_err(|| "unable to retrieve user input")?;

    if options[selection] == "Retry" {
        Ok(TestFailureSelection::Retry)
    } else if options[selection] == "Skip" {
        Ok(TestFailureSelection::Skip)
    } else if options[selection] == "Abort" {
        Ok(TestFailureSelection::Abort)
    } else {
        bail!("invalid menu selection")
    }
}
<|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 https://mozilla.org/MPL/2.0/. */

use glutin::os::ContextTraitExt;
use glutin::{ContextBuilder, CreationError, EventsLoop, NotCurrent, PossiblyCurrent, WindowedContext, WindowBuilder};
use servo_media::player::context::GlContext as RawContext;
use std::os::raw;

pub enum GlContext {
    Current(WindowedContext<PossiblyCurrent>),
    NotCurrent(WindowedContext<NotCurrent>),
    // Used a temporary value as we switch from Current to NotCurrent.
    None,
}

impl GlContext {
    pub fn window(&self) -> &glutin::Window {
        match self {
            GlContext::Current(c) => c.window(),
            GlContext::NotCurrent(c) => c.window(),
            GlContext::None => unreachable!(),
        }
    }
    pub fn resize(&mut self, size: glutin::dpi::PhysicalSize) {
        if let GlContext::NotCurrent(_) = self {
            self.make_current();
        }
        match self {
            GlContext::Current(c) => c.resize(size),
            _ => unreachable!(),
        }
    }
    pub fn make_current(&mut self) {
        *self = match std::mem::replace(self, GlContext::None) {
            GlContext::Current(c) => {
                warn!("Making an already current context current");
                GlContext::Current(c)
            },
            GlContext::NotCurrent(c) => {
                let c = unsafe {
                    c.make_current().expect("Couldn't make window current")
                };
                GlContext::Current(c)
            }
            GlContext::None => unreachable!(),
        }
    }
    pub fn make_not_current(&mut self) {
        *self = match std::mem::replace(self, GlContext::None) {
            GlContext::Current(c) => {
                let c = unsafe {
                    c.make_not_current().expect("Couldn't make window not current")
                };
                GlContext::NotCurrent(c)
            },
            GlContext::NotCurrent(c) => {
                warn!("Making an already not current context not current");
                GlContext::NotCurrent(c)
            }
            GlContext::None => unreachable!(),
        }
    }
    pub fn swap_buffers(&self) {
        match self {
            GlContext::Current(c) => {
                if let Err(err) = c.swap_buffers() {
                    warn!("Failed to swap window buffers ({}).", err);
                }
            },
            GlContext::NotCurrent(_) => {
                error!("Context is not current. Forgot to call prepare_for_composite?");
            },
            GlContext::None => unreachable!(),
        };
    }
    #[allow(unreachable_code, unused_variables)]
    pub fn raw_context(&self) -> RawContext {
        match self {
            GlContext::Current(c) => {
                #[cfg(any(
                    target_os = "linux",
                    target_os = "dragonfly",
                    target_os = "freebsd",
                    target_os = "netbsd",
                    target_os = "openbsd",
                ))]
                {
                    use glutin::os::unix::RawHandle;

                    let raw_handle = unsafe { c.raw_handle() };
                    return match raw_handle {
                        RawHandle::Egl(handle) => RawContext::Egl(handle as usize),
                        RawHandle::Glx(handle) => RawContext::Glx(handle as usize),
                    };
                }

                #[cfg(target_os = "windows")]
                {
                    use glutin::os::windows::RawHandle;

                    let raw_handle = unsafe { c.raw_handle() };
                    return match raw_handle {
                        RawHandle::Egl(handle) => RawContext::Egl(handle as usize),
                        // @TODO(victor): RawContext::Wgl in servo-media
                        RawHandle::Wgl(_) => unimplemented!(),
                    }
                }

                #[cfg(target_os = "android")]
                {
                    let raw_handle = unsafe { c.raw_handle() };
                    return RawContext::Egl(raw_handle as usize);
                }

                #[cfg(target_os = "macos")]
                return unimplemented!(); // @TODO(victor): RawContext::Cocoa in servo-media

                #[cfg(not(any(
                    target_os = "linux",
                    target_os = "dragonfly",
                    target_os = "freebsd",
                    target_os = "netbsd",
                    target_os = "openbsd",
                    target_os = "windows",
                    target_os = "android",
                    target_os = "macos",
                )))]
                unimplemented!()
            }
            GlContext::NotCurrent(_) => {
                error!("Context is not current.");
                RawContext::Unknown
            }
            GlContext::None => unreachable!(),
        }
    }

    pub fn new_window<T>(
        &self,
        cb: ContextBuilder<T>,
        wb: WindowBuilder,
        el: &EventsLoop
    ) -> Result<WindowedContext<NotCurrent>, CreationError>
    where
        T: glutin::ContextCurrentState,
    {
        match self {
            GlContext::Current(ref c) => {
                cb.with_shared_lists(c).build_windowed(wb, el)
            },
            GlContext::NotCurrent(ref c) => {
                cb.with_shared_lists(c).build_windowed(wb, el)
            },
            GlContext::None => {
                cb.build_windowed(wb, el)
            },
        }
    }

    #[allow(dead_code)]
    pub fn egl_display(&self) -> Option<*const raw::c_void> {
        match self {
            GlContext::Current(c) => unsafe { c.get_egl_display() },
            GlContext::NotCurrent(_) => {
                error!("Context is not current.");
                None
            },
            GlContext::None => unreachable!(),
        }
    }

    pub fn get_api(&self) -> glutin::Api {
        match self {
            GlContext::Current(c) => c.get_api(),
            GlContext::NotCurrent(c) => c.get_api(),
            GlContext::None => unreachable!(),
        }
    }
}
<commit_msg>Don't completely trust servo's tracking of the GL context in glutin<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 glutin::os::ContextTraitExt;
use glutin::{ContextBuilder, CreationError, EventsLoop, NotCurrent, PossiblyCurrent, WindowedContext, WindowBuilder};
use servo_media::player::context::GlContext as RawContext;
use std::os::raw;

pub enum GlContext {
    Current(WindowedContext<PossiblyCurrent>),
    NotCurrent(WindowedContext<NotCurrent>),
    // Used a temporary value as we switch from Current to NotCurrent.
    None,
}

impl GlContext {
    pub fn window(&self) -> &glutin::Window {
        match self {
            GlContext::Current(c) => c.window(),
            GlContext::NotCurrent(c) => c.window(),
            GlContext::None => unreachable!(),
        }
    }
    pub fn resize(&mut self, size: glutin::dpi::PhysicalSize) {
        if let GlContext::NotCurrent(_) = self {
            self.make_current();
        }
        match self {
            GlContext::Current(c) => c.resize(size),
            _ => unreachable!(),
        }
    }
    pub fn make_current(&mut self) {
        *self = match std::mem::replace(self, GlContext::None) {
            GlContext::Current(c) => {
                warn!("Making an already current context current");
                // Servo thinks that that this window is current,
                // but it might be wrong, since other code may have
                // changed the current GL context. Just to be on
                // the safe side, we make it current anyway.
                let c = unsafe {
                    c.make_current().expect("Couldn't make window current")
                };
                GlContext::Current(c)
            },
            GlContext::NotCurrent(c) => {
                let c = unsafe {
                    c.make_current().expect("Couldn't make window current")
                };
                GlContext::Current(c)
            }
            GlContext::None => unreachable!(),
        }
    }
    pub fn make_not_current(&mut self) {
        *self = match std::mem::replace(self, GlContext::None) {
            GlContext::Current(c) => {
                let c = unsafe {
                    c.make_not_current().expect("Couldn't make window not current")
                };
                GlContext::NotCurrent(c)
            },
            GlContext::NotCurrent(c) => {
                warn!("Making an already not current context not current");
                GlContext::NotCurrent(c)
            }
            GlContext::None => unreachable!(),
        }
    }
    pub fn swap_buffers(&self) {
        match self {
            GlContext::Current(c) => {
                if let Err(err) = c.swap_buffers() {
                    warn!("Failed to swap window buffers ({}).", err);
                }
            },
            GlContext::NotCurrent(_) => {
                error!("Context is not current. Forgot to call prepare_for_composite?");
            },
            GlContext::None => unreachable!(),
        };
    }
    #[allow(unreachable_code, unused_variables)]
    pub fn raw_context(&self) -> RawContext {
        match self {
            GlContext::Current(c) => {
                #[cfg(any(
                    target_os = "linux",
                    target_os = "dragonfly",
                    target_os = "freebsd",
                    target_os = "netbsd",
                    target_os = "openbsd",
                ))]
                {
                    use glutin::os::unix::RawHandle;

                    let raw_handle = unsafe { c.raw_handle() };
                    return match raw_handle {
                        RawHandle::Egl(handle) => RawContext::Egl(handle as usize),
                        RawHandle::Glx(handle) => RawContext::Glx(handle as usize),
                    };
                }

                #[cfg(target_os = "windows")]
                {
                    use glutin::os::windows::RawHandle;

                    let raw_handle = unsafe { c.raw_handle() };
                    return match raw_handle {
                        RawHandle::Egl(handle) => RawContext::Egl(handle as usize),
                        // @TODO(victor): RawContext::Wgl in servo-media
                        RawHandle::Wgl(_) => unimplemented!(),
                    }
                }

                #[cfg(target_os = "android")]
                {
                    let raw_handle = unsafe { c.raw_handle() };
                    return RawContext::Egl(raw_handle as usize);
                }

                #[cfg(target_os = "macos")]
                return unimplemented!(); // @TODO(victor): RawContext::Cocoa in servo-media

                #[cfg(not(any(
                    target_os = "linux",
                    target_os = "dragonfly",
                    target_os = "freebsd",
                    target_os = "netbsd",
                    target_os = "openbsd",
                    target_os = "windows",
                    target_os = "android",
                    target_os = "macos",
                )))]
                unimplemented!()
            }
            GlContext::NotCurrent(_) => {
                error!("Context is not current.");
                RawContext::Unknown
            }
            GlContext::None => unreachable!(),
        }
    }

    pub fn new_window<T>(
        &self,
        cb: ContextBuilder<T>,
        wb: WindowBuilder,
        el: &EventsLoop
    ) -> Result<WindowedContext<NotCurrent>, CreationError>
    where
        T: glutin::ContextCurrentState,
    {
        match self {
            GlContext::Current(ref c) => {
                cb.with_shared_lists(c).build_windowed(wb, el)
            },
            GlContext::NotCurrent(ref c) => {
                cb.with_shared_lists(c).build_windowed(wb, el)
            },
            GlContext::None => {
                cb.build_windowed(wb, el)
            },
        }
    }

    #[allow(dead_code)]
    pub fn egl_display(&self) -> Option<*const raw::c_void> {
        match self {
            GlContext::Current(c) => unsafe { c.get_egl_display() },
            GlContext::NotCurrent(_) => {
                error!("Context is not current.");
                None
            },
            GlContext::None => unreachable!(),
        }
    }

    pub fn get_api(&self) -> glutin::Api {
        match self {
            GlContext::Current(c) => c.get_api(),
            GlContext::NotCurrent(c) => c.get_api(),
            GlContext::None => unreachable!(),
        }
    }
}
<|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.

/// The `Drop` trait is used to run some code when a value goes out of scope.
/// This is sometimes called a 'destructor'.
///
/// When a value goes out of scope, if it implements this trait, it will have
/// its `drop` method called. Then any fields the value contains will also
/// be dropped recursively.
///
/// Because of the recursive dropping, you do not need to implement this trait
/// unless your type needs its own destructor logic.
///
/// # Examples
///
/// A trivial implementation of `Drop`. The `drop` method is called when `_x`
/// goes out of scope, and therefore `main` prints `Dropping!`.
///
/// ```
/// struct HasDrop;
///
/// impl Drop for HasDrop {
///     fn drop(&mut self) {
///         println!("Dropping!");
///     }
/// }
///
/// fn main() {
///     let _x = HasDrop;
/// }
/// ```
///
/// Showing the recursive nature of `Drop`. When `outer` goes out of scope, the
/// `drop` method will be called first for `Outer`, then for `Inner`. Therefore
/// `main` prints `Dropping Outer!` and then `Dropping Inner!`.
///
/// ```
/// struct Inner;
/// struct Outer(Inner);
///
/// impl Drop for Inner {
///     fn drop(&mut self) {
///         println!("Dropping Inner!");
///     }
/// }
///
/// impl Drop for Outer {
///     fn drop(&mut self) {
///         println!("Dropping Outer!");
///     }
/// }
///
/// fn main() {
///     let _x = Outer(Inner);
/// }
/// ```
///
/// Because variables are dropped in the reverse order they are declared,
/// `main` will print `Declared second!` and then `Declared first!`.
///
/// ```
/// struct PrintOnDrop(&'static str);
///
/// fn main() {
///     let _first = PrintOnDrop("Declared first!");
///     let _second = PrintOnDrop("Declared second!");
/// }
/// ```
#[lang = "drop"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Drop {
    /// A method called when the value goes out of scope.
    ///
    /// When this method has been called, `self` has not yet been deallocated.
    /// If it were, `self` would be a dangling reference.
    ///
    /// After this function is over, the memory of `self` will be deallocated.
    ///
    /// This function cannot be called explicitly. This is compiler error
    /// [E0040]. However, the [`std::mem::drop`] function in the prelude can be
    /// used to call the argument's `Drop` implementation.
    ///
    /// [E0040]: ../../error-index.html#E0040
    /// [`std::mem::drop`]: ../../std/mem/fn.drop.html
    ///
    /// # Panics
    ///
    /// Given that a `panic!` will call `drop()` as it unwinds, any `panic!` in
    /// a `drop()` implementation will likely abort.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn drop(&mut self);
}
<commit_msg>Revise `Drop` docs<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.

/// Used to run some code when a value goes out of scope.
/// This is sometimes called a 'destructor'.
///
/// When a value goes out of scope, it will have its `drop` method called if
/// its type implements `Drop`. Then, any fields the value contains will also
/// be dropped recursively.
///
/// Because of this recursive dropping, you do not need to implement this trait
/// unless your type needs its own destructor logic.
///
/// Refer to [the chapter on `Drop` in *The Rust Programming Language*][book]
/// for some more elaboration.
///
/// [book]: ../../book/second-edition/ch15-03-drop.html
///
/// # Examples
///
/// ## Implementing `Drop`
///
/// The `drop` method is called when `_x` goes out of scope, and therefore
/// `main` prints `Dropping!`.
///
/// ```
/// struct HasDrop;
///
/// impl Drop for HasDrop {
///     fn drop(&mut self) {
///         println!("Dropping!");
///     }
/// }
///
/// fn main() {
///     let _x = HasDrop;
/// }
/// ```
///
/// ## Dropping is done recursively
///
/// When `outer` goes out of scope, the `drop` method will be called first for
/// `Outer`, then for `Inner`. Therefore, `main` prints `Dropping Outer!` and
/// then `Dropping Inner!`.
///
/// ```
/// struct Inner;
/// struct Outer(Inner);
///
/// impl Drop for Inner {
///     fn drop(&mut self) {
///         println!("Dropping Inner!");
///     }
/// }
///
/// impl Drop for Outer {
///     fn drop(&mut self) {
///         println!("Dropping Outer!");
///     }
/// }
///
/// fn main() {
///     let _x = Outer(Inner);
/// }
/// ```
///
/// ## Variables are dropped in reverse order of declaration
///
/// `_first` is declared first and `_second` is declared second, so `main` will
/// print `Declared second!` and then `Declared first!`.
///
/// ```
/// struct PrintOnDrop(&'static str);
///
/// impl Drop for PrintOnDrop {
///     fn drop(&mut self) {
///         println!("{}", self.0);
///     }
/// }
///
/// fn main() {
///     let _first = PrintOnDrop("Declared first!");
///     let _second = PrintOnDrop("Declared second!");
/// }
/// ```
#[lang = "drop"]
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Drop {
    /// Executes the destructor for this type.
    ///
    /// This method is called implilcitly when the value goes out of scope,
    /// and cannot be called explicitly (this is compiler error [E0040]).
    /// However, the [`std::mem::drop`] function in the prelude can be
    /// used to call the argument's `Drop` implementation.
    ///
    /// When this method has been called, `self` has not yet been deallocated.
    /// That only happens after the method is over.
    /// If this wasn't the case, `self` would be a dangling reference.
    ///
    /// # Panics
    ///
    /// Given that a [`panic!`] will call `drop` as it unwinds, any [`panic!`]
    /// in a `drop` implementation will likely abort.
    ///
    /// [E0040]: ../../error-index.html#E0040
    /// [`panic!`]: ../macro.panic.html
    /// [`std::mem::drop`]: ../../std/mem/fn.drop.html
    #[stable(feature = "rust1", since = "1.0.0")]
    fn drop(&mut self);
}
<|endoftext|>


<commit_before>//! Support for capturing a stack backtrace of an OS thread
//!
//! This module contains the support necessary to capture a stack backtrace of a
//! running OS thread from the OS thread itself. The `Backtrace` type supports
//! capturing a stack trace via the `Backtrace::capture` and
//! `Backtrace::force_capture` functions.
//!
//! A backtrace is typically quite handy to attach to errors (e.g. types
//! implementing `std::error::Error`) to get a causal chain of where an error
//! was generated.
//!
//! > **Note**: this module is unstable and is designed in [RFC 2504], and you
//! > can learn more about its status in the [tracking issue].
//!
//! [RFC 2504]: https://github.com/rust-lang/rfcs/blob/master/text/2504-fix-error.md
//! [tracking issue]: https://github.com/rust-lang/rust/issues/53487
//!
//! ## Accuracy
//!
//! Backtraces are attempted to be as accurate as possible, but no guarantees
//! are provided about the exact accuracy of a backtrace. Instruction pointers,
//! symbol names, filenames, line numbers, etc, may all be incorrect when
//! reported. Accuracy is attempted on a best-effort basis, however, and bugs
//! are always welcome to indicate areas of improvement!
//!
//! For most platforms a backtrace with a filename/line number requires that
//! programs be compiled with debug information. Without debug information
//! filenames/line numbers will not be reported.
//!
//! ## Platform support
//!
//! Not all platforms that libstd compiles for support capturing backtraces.
//! Some platforms simply do nothing when capturing a backtrace. To check
//! whether the platform supports capturing backtraces you can consult the
//! `BacktraceStatus` enum as a result of `Backtrace::status`.
//!
//! Like above with accuracy platform support is done on a best effort basis.
//! Sometimes libraries may not be available at runtime or something may go
//! wrong which would cause a backtrace to not be captured. Please feel free to
//! report issues with platforms where a backtrace cannot be captured though!
//!
//! ## Environment Variables
//!
//! The `Backtrace::capture` function may not actually capture a backtrace by
//! default. Its behavior is governed by two environment variables:
//!
//! * `RUST_LIB_BACKTRACE` - if this is set to `0` then `Backtrace::capture`
//!   will never capture a backtrace. Any other value this is set to will enable
//!   `Backtrace::capture`.
//!
//! * `RUST_BACKTRACE` - if `RUST_LIB_BACKTRACE` is not set, then this variable
//!   is consulted with the same rules of `RUST_LIB_BACKTRACE`.
//!
//! * If neither of the above env vars are set, then `Backtrace::capture` will
//!   be disabled.
//!
//! Capturing a backtrace can be a quite expensive runtime operation, so the
//! environment variables allow either forcibly disabling this runtime
//! performance hit or allow selectively enabling it in some programs.
//!
//! Note that the `Backtrace::force_capture` function can be used to ignore
//! these environment variables. Also note that the state of environment
//! variables is cached once the first backtrace is created, so altering
//! `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` at runtime may not actually change
//! how backtraces are captured.

#![unstable(feature = "backtrace", issue = "53487")]

// NB: A note on resolution of a backtrace:
//
// Backtraces primarily happen in two steps, one is where we actually capture
// the stack backtrace, giving us a list of instruction pointers corresponding
// to stack frames. Next we take these instruction pointers and, one-by-one,
// turn them into a human readable name (like `main`).
//
// The first phase can be somewhat expensive (walking the stack), especially
// on MSVC where debug information is consulted to return inline frames each as
// their own frame. The second phase, however, is almost always extremely
// expensive (on the order of milliseconds sometimes) when it's consulting debug
// information.
//
// We attempt to amortize this cost as much as possible by delaying resolution
// of an address to a human readable name for as long as possible. When
// `Backtrace::create` is called to capture a backtrace it doesn't actually
// perform any symbol resolution, but rather we lazily resolve symbols only just
// before they're needed for printing. This way we can make capturing a
// backtrace and throwing it away much cheaper, but actually printing a
// backtrace is still basically the same cost.
//
// This strategy comes at the cost of some synchronization required inside of a
// `Backtrace`, but that's a relatively small price to pay relative to capturing
// a backtrace or actually symbolizing it.

use crate::env;
use crate::fmt;
use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
use crate::sync::Mutex;
use crate::sys_common::backtrace::{lock, output_filename};
use crate::vec::Vec;
use backtrace::BytesOrWideString;
use backtrace_rs as backtrace;

/// A captured OS thread stack backtrace.
///
/// This type represents a stack backtrace for an OS thread captured at a
/// previous point in time. In some instances the `Backtrace` type may
/// internally be empty due to configuration. For more information see
/// `Backtrace::capture`.
pub struct Backtrace {
    inner: Inner,
}

/// The current status of a backtrace, indicating whether it was captured or
/// whether it is empty for some other reason.
#[non_exhaustive]
#[derive(Debug, PartialEq, Eq)]
pub enum BacktraceStatus {
    /// Capturing a backtrace is not supported, likely because it's not
    /// implemented for the current platform.
    Unsupported,
    /// Capturing a backtrace has been disabled through either the
    /// `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` environment variables.
    Disabled,
    /// A backtrace has been captured and the `Backtrace` should print
    /// reasonable information when rendered.
    Captured,
}

enum Inner {
    Unsupported,
    Disabled,
    Captured(Mutex<Capture>),
}

struct Capture {
    actual_start: usize,
    resolved: bool,
    frames: Vec<BacktraceFrame>,
}

fn _assert_send_sync() {
    fn _assert<T: Send + Sync>() {}
    _assert::<Backtrace>();
}

struct BacktraceFrame {
    frame: backtrace::Frame,
    symbols: Vec<BacktraceSymbol>,
}

struct BacktraceSymbol {
    name: Option<Vec<u8>>,
    filename: Option<BytesOrWide>,
    lineno: Option<u32>,
}

enum BytesOrWide {
    Bytes(Vec<u8>),
    Wide(Vec<u16>),
}

impl fmt::Debug for Backtrace {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut capture = match &self.inner {
            Inner::Unsupported => return fmt.write_str("<unsupported>"),
            Inner::Disabled => return fmt.write_str("<disabled>"),
            Inner::Captured(c) => c.lock().unwrap(),
        };
        capture.resolve();

        let frames = &capture.frames[capture.actual_start..];

        write!(fmt, "Backtrace ")?;

        let mut dbg = fmt.debug_list();

        for frame in frames {
            if frame.frame.ip().is_null() {
                continue;
            }

            dbg.entries(&frame.symbols);
        }

        dbg.finish()
    }
}

impl fmt::Debug for BacktraceSymbol {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(fmt, "{{ ")?;

        if let Some(fn_name) = self.name.as_ref().map(|b| backtrace::SymbolName::new(b)) {
            write!(fmt, "fn: \"{:#}\"", fn_name)?;
        } else {
            write!(fmt, "fn: <unknown>")?;
        }

        if let Some(fname) = self.filename.as_ref() {
            write!(fmt, ", file: \"{:?}\"", fname)?;
        }

        if let Some(line) = self.lineno.as_ref() {
            write!(fmt, ", line: {:?}", line)?;
        }

        write!(fmt, " }}")
    }
}

impl fmt::Debug for BytesOrWide {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        output_filename(
            fmt,
            match self {
                BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
                BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
            },
            backtrace::PrintFmt::Short,
            crate::env::current_dir().as_ref().ok(),
        )
    }
}

impl Backtrace {
    /// Returns whether backtrace captures are enabled through environment
    /// variables.
    fn enabled() -> bool {
        // Cache the result of reading the environment variables to make
        // backtrace captures speedy, because otherwise reading environment
        // variables every time can be somewhat slow.
        static ENABLED: AtomicUsize = AtomicUsize::new(0);
        match ENABLED.load(SeqCst) {
            0 => {}
            1 => return false,
            _ => return true,
        }
        let enabled = match env::var("RUST_LIB_BACKTRACE") {
            Ok(s) => s != "0",
            Err(_) => match env::var("RUST_BACKTRACE") {
                Ok(s) => s != "0",
                Err(_) => false,
            },
        };
        ENABLED.store(enabled as usize + 1, SeqCst);
        return enabled;
    }

    /// Capture a stack backtrace of the current thread.
    ///
    /// This function will capture a stack backtrace of the current OS thread of
    /// execution, returning a `Backtrace` type which can be later used to print
    /// the entire stack trace or render it to a string.
    ///
    /// This function will be a noop if the `RUST_BACKTRACE` or
    /// `RUST_LIB_BACKTRACE` backtrace variables are both not set. If either
    /// environment variable is set and enabled then this function will actually
    /// capture a backtrace. Capturing a backtrace can be both memory intensive
    /// and slow, so these environment variables allow liberally using
    /// `Backtrace::capture` and only incurring a slowdown when the environment
    /// variables are set.
    ///
    /// To forcibly capture a backtrace regardless of environment variables, use
    /// the `Backtrace::force_capture` function.
    #[inline(never)] // want to make sure there's a frame here to remove
    pub fn capture() -> Backtrace {
        if !Backtrace::enabled() {
            return Backtrace { inner: Inner::Disabled };
        }
        Backtrace::create(Backtrace::capture as usize)
    }

    /// Forcibly captures a full backtrace, regardless of environment variable
    /// configuration.
    ///
    /// This function behaves the same as `capture` except that it ignores the
    /// values of the `RUST_BACKTRACE` and `RUST_LIB_BACKTRACE` environment
    /// variables, always capturing a backtrace.
    ///
    /// Note that capturing a backtrace can be an expensive operation on some
    /// platforms, so this should be used with caution in performance-sensitive
    /// parts of code.
    #[inline(never)] // want to make sure there's a frame here to remove
    pub fn force_capture() -> Backtrace {
        Backtrace::create(Backtrace::force_capture as usize)
    }

    // Capture a backtrace which start just before the function addressed by
    // `ip`
    fn create(ip: usize) -> Backtrace {
        let _lock = lock();
        let mut frames = Vec::new();
        let mut actual_start = None;
        unsafe {
            backtrace::trace_unsynchronized(|frame| {
                frames.push(BacktraceFrame { frame: frame.clone(), symbols: Vec::new() });
                if frame.symbol_address() as usize == ip && actual_start.is_none() {
                    actual_start = Some(frames.len());
                }
                true
            });
        }

        // If no frames came out assume that this is an unsupported platform
        // since `backtrace` doesn't provide a way of learning this right now,
        // and this should be a good enough approximation.
        let inner = if frames.is_empty() {
            Inner::Unsupported
        } else {
            Inner::Captured(Mutex::new(Capture {
                actual_start: actual_start.unwrap_or(0),
                frames,
                resolved: false,
            }))
        };

        Backtrace { inner }
    }

    /// Returns the status of this backtrace, indicating whether this backtrace
    /// request was unsupported, disabled, or a stack trace was actually
    /// captured.
    pub fn status(&self) -> BacktraceStatus {
        match self.inner {
            Inner::Unsupported => BacktraceStatus::Unsupported,
            Inner::Disabled => BacktraceStatus::Disabled,
            Inner::Captured(_) => BacktraceStatus::Captured,
        }
    }
}

impl fmt::Display for Backtrace {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut capture = match &self.inner {
            Inner::Unsupported => return fmt.write_str("unsupported backtrace"),
            Inner::Disabled => return fmt.write_str("disabled backtrace"),
            Inner::Captured(c) => c.lock().unwrap(),
        };
        capture.resolve();

        let full = fmt.alternate();
        let (frames, style) = if full {
            (&capture.frames[..], backtrace::PrintFmt::Full)
        } else {
            (&capture.frames[capture.actual_start..], backtrace::PrintFmt::Short)
        };

        // When printing paths we try to strip the cwd if it exists, otherwise
        // we just print the path as-is. Note that we also only do this for the
        // short format, because if it's full we presumably want to print
        // everything.
        let cwd = crate::env::current_dir();
        let mut print_path = move |fmt: &mut fmt::Formatter<'_>, path: BytesOrWideString<'_>| {
            output_filename(fmt, path, style, cwd.as_ref().ok())
        };

        let mut f = backtrace::BacktraceFmt::new(fmt, style, &mut print_path);
        f.add_context()?;
        for frame in frames {
            let mut f = f.frame();
            if frame.symbols.is_empty() {
                f.print_raw(frame.frame.ip(), None, None, None)?;
            } else {
                for symbol in frame.symbols.iter() {
                    f.print_raw(
                        frame.frame.ip(),
                        symbol.name.as_ref().map(|b| backtrace::SymbolName::new(b)),
                        symbol.filename.as_ref().map(|b| match b {
                            BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
                            BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
                        }),
                        symbol.lineno,
                    )?;
                }
            }
        }
        f.finish()?;
        Ok(())
    }
}

impl Capture {
    fn resolve(&mut self) {
        // If we're already resolved, nothing to do!
        if self.resolved {
            return;
        }
        self.resolved = true;

        // Use the global backtrace lock to synchronize this as it's a
        // requirement of the `backtrace` crate, and then actually resolve
        // everything.
        let _lock = lock();
        for frame in self.frames.iter_mut() {
            let symbols = &mut frame.symbols;
            unsafe {
                backtrace::resolve_frame_unsynchronized(&frame.frame, |symbol| {
                    symbols.push(BacktraceSymbol {
                        name: symbol.name().map(|m| m.as_bytes().to_vec()),
                        filename: symbol.filename_raw().map(|b| match b {
                            BytesOrWideString::Bytes(b) => BytesOrWide::Bytes(b.to_owned()),
                            BytesOrWideString::Wide(b) => BytesOrWide::Wide(b.to_owned()),
                        }),
                        lineno: symbol.lineno(),
                    });
                });
            }
        }
    }
}
<commit_msg>Make it possible to instantiate hardcoded Backtrace from test<commit_after>//! Support for capturing a stack backtrace of an OS thread
//!
//! This module contains the support necessary to capture a stack backtrace of a
//! running OS thread from the OS thread itself. The `Backtrace` type supports
//! capturing a stack trace via the `Backtrace::capture` and
//! `Backtrace::force_capture` functions.
//!
//! A backtrace is typically quite handy to attach to errors (e.g. types
//! implementing `std::error::Error`) to get a causal chain of where an error
//! was generated.
//!
//! > **Note**: this module is unstable and is designed in [RFC 2504], and you
//! > can learn more about its status in the [tracking issue].
//!
//! [RFC 2504]: https://github.com/rust-lang/rfcs/blob/master/text/2504-fix-error.md
//! [tracking issue]: https://github.com/rust-lang/rust/issues/53487
//!
//! ## Accuracy
//!
//! Backtraces are attempted to be as accurate as possible, but no guarantees
//! are provided about the exact accuracy of a backtrace. Instruction pointers,
//! symbol names, filenames, line numbers, etc, may all be incorrect when
//! reported. Accuracy is attempted on a best-effort basis, however, and bugs
//! are always welcome to indicate areas of improvement!
//!
//! For most platforms a backtrace with a filename/line number requires that
//! programs be compiled with debug information. Without debug information
//! filenames/line numbers will not be reported.
//!
//! ## Platform support
//!
//! Not all platforms that libstd compiles for support capturing backtraces.
//! Some platforms simply do nothing when capturing a backtrace. To check
//! whether the platform supports capturing backtraces you can consult the
//! `BacktraceStatus` enum as a result of `Backtrace::status`.
//!
//! Like above with accuracy platform support is done on a best effort basis.
//! Sometimes libraries may not be available at runtime or something may go
//! wrong which would cause a backtrace to not be captured. Please feel free to
//! report issues with platforms where a backtrace cannot be captured though!
//!
//! ## Environment Variables
//!
//! The `Backtrace::capture` function may not actually capture a backtrace by
//! default. Its behavior is governed by two environment variables:
//!
//! * `RUST_LIB_BACKTRACE` - if this is set to `0` then `Backtrace::capture`
//!   will never capture a backtrace. Any other value this is set to will enable
//!   `Backtrace::capture`.
//!
//! * `RUST_BACKTRACE` - if `RUST_LIB_BACKTRACE` is not set, then this variable
//!   is consulted with the same rules of `RUST_LIB_BACKTRACE`.
//!
//! * If neither of the above env vars are set, then `Backtrace::capture` will
//!   be disabled.
//!
//! Capturing a backtrace can be a quite expensive runtime operation, so the
//! environment variables allow either forcibly disabling this runtime
//! performance hit or allow selectively enabling it in some programs.
//!
//! Note that the `Backtrace::force_capture` function can be used to ignore
//! these environment variables. Also note that the state of environment
//! variables is cached once the first backtrace is created, so altering
//! `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` at runtime may not actually change
//! how backtraces are captured.

#![unstable(feature = "backtrace", issue = "53487")]

// NB: A note on resolution of a backtrace:
//
// Backtraces primarily happen in two steps, one is where we actually capture
// the stack backtrace, giving us a list of instruction pointers corresponding
// to stack frames. Next we take these instruction pointers and, one-by-one,
// turn them into a human readable name (like `main`).
//
// The first phase can be somewhat expensive (walking the stack), especially
// on MSVC where debug information is consulted to return inline frames each as
// their own frame. The second phase, however, is almost always extremely
// expensive (on the order of milliseconds sometimes) when it's consulting debug
// information.
//
// We attempt to amortize this cost as much as possible by delaying resolution
// of an address to a human readable name for as long as possible. When
// `Backtrace::create` is called to capture a backtrace it doesn't actually
// perform any symbol resolution, but rather we lazily resolve symbols only just
// before they're needed for printing. This way we can make capturing a
// backtrace and throwing it away much cheaper, but actually printing a
// backtrace is still basically the same cost.
//
// This strategy comes at the cost of some synchronization required inside of a
// `Backtrace`, but that's a relatively small price to pay relative to capturing
// a backtrace or actually symbolizing it.

use crate::env;
use crate::ffi::c_void;
use crate::fmt;
use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
use crate::sync::Mutex;
use crate::sys_common::backtrace::{lock, output_filename};
use crate::vec::Vec;
use backtrace::BytesOrWideString;
use backtrace_rs as backtrace;

/// A captured OS thread stack backtrace.
///
/// This type represents a stack backtrace for an OS thread captured at a
/// previous point in time. In some instances the `Backtrace` type may
/// internally be empty due to configuration. For more information see
/// `Backtrace::capture`.
pub struct Backtrace {
    inner: Inner,
}

/// The current status of a backtrace, indicating whether it was captured or
/// whether it is empty for some other reason.
#[non_exhaustive]
#[derive(Debug, PartialEq, Eq)]
pub enum BacktraceStatus {
    /// Capturing a backtrace is not supported, likely because it's not
    /// implemented for the current platform.
    Unsupported,
    /// Capturing a backtrace has been disabled through either the
    /// `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` environment variables.
    Disabled,
    /// A backtrace has been captured and the `Backtrace` should print
    /// reasonable information when rendered.
    Captured,
}

enum Inner {
    Unsupported,
    Disabled,
    Captured(Mutex<Capture>),
}

struct Capture {
    actual_start: usize,
    resolved: bool,
    frames: Vec<BacktraceFrame>,
}

fn _assert_send_sync() {
    fn _assert<T: Send + Sync>() {}
    _assert::<Backtrace>();
}

struct BacktraceFrame {
    frame: RawFrame,
    symbols: Vec<BacktraceSymbol>,
}

enum RawFrame {
    Actual(backtrace::Frame),
    #[cfg(test)]
    Fake,
}

struct BacktraceSymbol {
    name: Option<Vec<u8>>,
    filename: Option<BytesOrWide>,
    lineno: Option<u32>,
}

enum BytesOrWide {
    Bytes(Vec<u8>),
    Wide(Vec<u16>),
}

impl fmt::Debug for Backtrace {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut capture = match &self.inner {
            Inner::Unsupported => return fmt.write_str("<unsupported>"),
            Inner::Disabled => return fmt.write_str("<disabled>"),
            Inner::Captured(c) => c.lock().unwrap(),
        };
        capture.resolve();

        let frames = &capture.frames[capture.actual_start..];

        write!(fmt, "Backtrace ")?;

        let mut dbg = fmt.debug_list();

        for frame in frames {
            if frame.frame.ip().is_null() {
                continue;
            }

            dbg.entries(&frame.symbols);
        }

        dbg.finish()
    }
}

impl fmt::Debug for BacktraceSymbol {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(fmt, "{{ ")?;

        if let Some(fn_name) = self.name.as_ref().map(|b| backtrace::SymbolName::new(b)) {
            write!(fmt, "fn: \"{:#}\"", fn_name)?;
        } else {
            write!(fmt, "fn: <unknown>")?;
        }

        if let Some(fname) = self.filename.as_ref() {
            write!(fmt, ", file: \"{:?}\"", fname)?;
        }

        if let Some(line) = self.lineno.as_ref() {
            write!(fmt, ", line: {:?}", line)?;
        }

        write!(fmt, " }}")
    }
}

impl fmt::Debug for BytesOrWide {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        output_filename(
            fmt,
            match self {
                BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
                BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
            },
            backtrace::PrintFmt::Short,
            crate::env::current_dir().as_ref().ok(),
        )
    }
}

impl Backtrace {
    /// Returns whether backtrace captures are enabled through environment
    /// variables.
    fn enabled() -> bool {
        // Cache the result of reading the environment variables to make
        // backtrace captures speedy, because otherwise reading environment
        // variables every time can be somewhat slow.
        static ENABLED: AtomicUsize = AtomicUsize::new(0);
        match ENABLED.load(SeqCst) {
            0 => {}
            1 => return false,
            _ => return true,
        }
        let enabled = match env::var("RUST_LIB_BACKTRACE") {
            Ok(s) => s != "0",
            Err(_) => match env::var("RUST_BACKTRACE") {
                Ok(s) => s != "0",
                Err(_) => false,
            },
        };
        ENABLED.store(enabled as usize + 1, SeqCst);
        return enabled;
    }

    /// Capture a stack backtrace of the current thread.
    ///
    /// This function will capture a stack backtrace of the current OS thread of
    /// execution, returning a `Backtrace` type which can be later used to print
    /// the entire stack trace or render it to a string.
    ///
    /// This function will be a noop if the `RUST_BACKTRACE` or
    /// `RUST_LIB_BACKTRACE` backtrace variables are both not set. If either
    /// environment variable is set and enabled then this function will actually
    /// capture a backtrace. Capturing a backtrace can be both memory intensive
    /// and slow, so these environment variables allow liberally using
    /// `Backtrace::capture` and only incurring a slowdown when the environment
    /// variables are set.
    ///
    /// To forcibly capture a backtrace regardless of environment variables, use
    /// the `Backtrace::force_capture` function.
    #[inline(never)] // want to make sure there's a frame here to remove
    pub fn capture() -> Backtrace {
        if !Backtrace::enabled() {
            return Backtrace { inner: Inner::Disabled };
        }
        Backtrace::create(Backtrace::capture as usize)
    }

    /// Forcibly captures a full backtrace, regardless of environment variable
    /// configuration.
    ///
    /// This function behaves the same as `capture` except that it ignores the
    /// values of the `RUST_BACKTRACE` and `RUST_LIB_BACKTRACE` environment
    /// variables, always capturing a backtrace.
    ///
    /// Note that capturing a backtrace can be an expensive operation on some
    /// platforms, so this should be used with caution in performance-sensitive
    /// parts of code.
    #[inline(never)] // want to make sure there's a frame here to remove
    pub fn force_capture() -> Backtrace {
        Backtrace::create(Backtrace::force_capture as usize)
    }

    // Capture a backtrace which start just before the function addressed by
    // `ip`
    fn create(ip: usize) -> Backtrace {
        let _lock = lock();
        let mut frames = Vec::new();
        let mut actual_start = None;
        unsafe {
            backtrace::trace_unsynchronized(|frame| {
                frames.push(BacktraceFrame {
                    frame: RawFrame::Actual(frame.clone()),
                    symbols: Vec::new(),
                });
                if frame.symbol_address() as usize == ip && actual_start.is_none() {
                    actual_start = Some(frames.len());
                }
                true
            });
        }

        // If no frames came out assume that this is an unsupported platform
        // since `backtrace` doesn't provide a way of learning this right now,
        // and this should be a good enough approximation.
        let inner = if frames.is_empty() {
            Inner::Unsupported
        } else {
            Inner::Captured(Mutex::new(Capture {
                actual_start: actual_start.unwrap_or(0),
                frames,
                resolved: false,
            }))
        };

        Backtrace { inner }
    }

    /// Returns the status of this backtrace, indicating whether this backtrace
    /// request was unsupported, disabled, or a stack trace was actually
    /// captured.
    pub fn status(&self) -> BacktraceStatus {
        match self.inner {
            Inner::Unsupported => BacktraceStatus::Unsupported,
            Inner::Disabled => BacktraceStatus::Disabled,
            Inner::Captured(_) => BacktraceStatus::Captured,
        }
    }
}

impl fmt::Display for Backtrace {
    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut capture = match &self.inner {
            Inner::Unsupported => return fmt.write_str("unsupported backtrace"),
            Inner::Disabled => return fmt.write_str("disabled backtrace"),
            Inner::Captured(c) => c.lock().unwrap(),
        };
        capture.resolve();

        let full = fmt.alternate();
        let (frames, style) = if full {
            (&capture.frames[..], backtrace::PrintFmt::Full)
        } else {
            (&capture.frames[capture.actual_start..], backtrace::PrintFmt::Short)
        };

        // When printing paths we try to strip the cwd if it exists, otherwise
        // we just print the path as-is. Note that we also only do this for the
        // short format, because if it's full we presumably want to print
        // everything.
        let cwd = crate::env::current_dir();
        let mut print_path = move |fmt: &mut fmt::Formatter<'_>, path: BytesOrWideString<'_>| {
            output_filename(fmt, path, style, cwd.as_ref().ok())
        };

        let mut f = backtrace::BacktraceFmt::new(fmt, style, &mut print_path);
        f.add_context()?;
        for frame in frames {
            let mut f = f.frame();
            if frame.symbols.is_empty() {
                f.print_raw(frame.frame.ip(), None, None, None)?;
            } else {
                for symbol in frame.symbols.iter() {
                    f.print_raw(
                        frame.frame.ip(),
                        symbol.name.as_ref().map(|b| backtrace::SymbolName::new(b)),
                        symbol.filename.as_ref().map(|b| match b {
                            BytesOrWide::Bytes(w) => BytesOrWideString::Bytes(w),
                            BytesOrWide::Wide(w) => BytesOrWideString::Wide(w),
                        }),
                        symbol.lineno,
                    )?;
                }
            }
        }
        f.finish()?;
        Ok(())
    }
}

impl Capture {
    fn resolve(&mut self) {
        // If we're already resolved, nothing to do!
        if self.resolved {
            return;
        }
        self.resolved = true;

        // Use the global backtrace lock to synchronize this as it's a
        // requirement of the `backtrace` crate, and then actually resolve
        // everything.
        let _lock = lock();
        for frame in self.frames.iter_mut() {
            let symbols = &mut frame.symbols;
            let frame = match &frame.frame {
                RawFrame::Actual(frame) => frame,
                #[cfg(test)]
                RawFrame::Fake => unimplemented!(),
            };
            unsafe {
                backtrace::resolve_frame_unsynchronized(frame, |symbol| {
                    symbols.push(BacktraceSymbol {
                        name: symbol.name().map(|m| m.as_bytes().to_vec()),
                        filename: symbol.filename_raw().map(|b| match b {
                            BytesOrWideString::Bytes(b) => BytesOrWide::Bytes(b.to_owned()),
                            BytesOrWideString::Wide(b) => BytesOrWide::Wide(b.to_owned()),
                        }),
                        lineno: symbol.lineno(),
                    });
                });
            }
        }
    }
}

impl RawFrame {
    fn ip(&self) -> *mut c_void {
        match self {
            RawFrame::Actual(frame) => frame.ip(),
            #[cfg(test)]
            RawFrame::Fake => 1 as *mut c_void,
        }
    }
}
<|endoftext|>