<commit_before>//! Module for implementing convert's FromTable

use hlua::any::AnyLuaValue;
use hlua::any::AnyLuaValue::*;

use std::cmp::Ordering;

/// Represents types which can be serialized from a Lua table (AnyLuaValue).
///
/// For convenience, this method takes in a `LuaDecoder` (obtained from
/// `LuaDecoder::new(AnyLuaValue)`). See methods on `LuaDecoder`.
pub trait FromTable {
    /// Attempt to parse this value from the decoder.
    fn from_table(decoder: LuaDecoder) -> ConvertResult<Self>
        where Self: Sized;

    fn from_lua_table(table: AnyLuaValue) -> ConvertResult<Self>
        where Self: Sized {
        Self::from_table(LuaDecoder::new(table))
    }
}

/// Errors a converter can run into
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum ConverterError {
    /// The type of value present did not match the one expected
    UnexpectedType(String),
    /// The table index expected did not exist
    MissingTableIndex(String),
    /// The table index present was not valid
    InvalidTableIndex(String)
}

/// Results for conversion operations
pub type ConvertResult<T> = Result<T, ConverterError>;

/// Can decode values with a FromTable
#[derive(Debug, PartialEq, Clone)]
pub struct LuaDecoder {
    val: AnyLuaValue
}

impl LuaDecoder {
    pub fn new(val: AnyLuaValue) -> LuaDecoder {
        LuaDecoder { val: val }
    }

    pub fn get_bool(self) -> ConvertResult<bool> {
        match self.val {
            LuaBoolean(val) => Ok(val),
            _ => Err(ConverterError::UnexpectedType(
                format!("Expected bool, got {:?}", self.val)))
        }
    }

    pub fn get_string(self) -> ConvertResult<String> {
        match self.val {
            LuaString(text) => Ok(text),
            _ => Err(ConverterError::UnexpectedType(
                format!("Expected String, got {:?}", self.val)))
        }
    }

    pub fn get_option<T: FromTable>(self) -> ConvertResult<Option<T>> {
        match self.val {
            LuaNil => Ok(None),
            val => T::from_table(LuaDecoder::new(val)).map(|val| Some(val))
        }
    }

    pub fn read_field<T>(self, name: String) -> ConvertResult<(Self, T)>
        where T: FromTable {
        match self.val {
            LuaArray(mut arr) => {
                let maybe_pos = arr.iter().position(|ref val_pair| {
                    match val_pair.0 {
                        LuaString(ref key) => {
                            *key == name
                        },
                        _ => false
                    }
                });
                if let Some(pos) = maybe_pos {
                    let (_, val) = arr.remove(pos);
                    let val_parser = LuaDecoder::new(val);
                    T::from_table(val_parser).map(|parse|
                                    (LuaDecoder::new(LuaArray(arr)), parse))
                }
                else {
                    Err(ConverterError::MissingTableIndex(name))
                }
            }
            _ => Err(ConverterError::UnexpectedType(
                format!("Expected table, got {:?}", self.val)))
        }
    }

    pub fn get_unordered_array<T>(self) -> ConvertResult<Vec<T>>
    where T: FromTable {
        match self.val {
            LuaArray(mut arr) => {
                let mut turn = Vec::with_capacity(arr.len());
                // Completely ignore the keys, push values of type T
                for (_, val) in arr.into_iter() {
                    turn.push(try!(T::from_lua_table(val)));
                }
                Ok(turn)
            }
            _ => Err(ConverterError::UnexpectedType(
                 format!("Expected table/vec, got {:?}", self.val)))
        }
    }
}

macro_rules! primitive_decode {
    ( $($ptype:ty, $fun:ident;) +) => {
        $(impl LuaDecoder {
            pub fn $fun(self) -> ConvertResult<$ptype> {
                match self.val {
                    AnyLuaValue::LuaNumber(num) => Ok(num as $ptype),
                    _ => Err(ConverterError::UnexpectedType(
                        format!("Expected {}, got {:?}", stringify!($ptype), self.val)))
                }
            }
        }

        impl FromTable for $ptype {
            fn from_table(decoder: LuaDecoder) -> ConvertResult<$ptype> {
                LuaDecoder::$fun(decoder)
            }
        })+
    }
}

primitive_decode! {
    i8,  get_i8;
    i16, get_i16;
    i32, get_i32;

    u8,  get_u8;
    u16, get_u16;
    u32, get_u32;

    f32, get_f32;
    f64, get_f64;
}

impl FromTable for String {
    fn from_table(decoder: LuaDecoder) -> ConvertResult<String> {
        decoder.get_string()
    }
}

impl<T: FromTable> FromTable for Vec<T> {
    fn from_table(decoder: LuaDecoder) -> ConvertResult<Vec<T>> {
        decoder.get_unordered_array()
    }
}
<commit_msg>Implement FromTable for HashMap<commit_after>//! Module for implementing convert's FromTable

use hlua::any::AnyLuaValue;
use hlua::any::AnyLuaValue::*;

use std::hash::Hash;
use std::cmp::Eq;
use std::collections::HashMap;

/// Represents types which can be serialized from a Lua table (AnyLuaValue).
///
/// For convenience, this method takes in a `LuaDecoder` (obtained from
/// `LuaDecoder::new(AnyLuaValue)`). See methods on `LuaDecoder`.
pub trait FromTable {
    /// Attempt to parse this value from the decoder.
    fn from_table(decoder: LuaDecoder) -> ConvertResult<Self>
        where Self: Sized;

    fn from_lua_table(table: AnyLuaValue) -> ConvertResult<Self>
        where Self: Sized {
        Self::from_table(LuaDecoder::new(table))
    }
}

/// Errors a converter can run into
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum ConverterError {
    /// The type of value present did not match the one expected
    UnexpectedType(String),
    /// The table index expected did not exist
    MissingTableIndex(String),
    /// The table index present was not valid
    InvalidTableIndex(String)
}

impl ConverterError {
    pub fn into_message(self) -> String {
        match self {
            ConverterError::UnexpectedType(m) => m,
            ConverterError::MissingTableIndex(m) => m,
            ConverterError::InvalidTableIndex(m) => m
        }
    }
}

/// Results for conversion operations
pub type ConvertResult<T> = Result<T, ConverterError>;

/// Can decode values with a FromTable
#[derive(Debug, PartialEq, Clone)]
pub struct LuaDecoder {
    val: AnyLuaValue
}

impl LuaDecoder {
    pub fn new(val: AnyLuaValue) -> LuaDecoder {
        LuaDecoder { val: val }
    }

    pub fn get_bool(self) -> ConvertResult<bool> {
        match self.val {
            LuaBoolean(val) => Ok(val),
            _ => Err(ConverterError::UnexpectedType(
                format!("Expected bool, got {:?}", self.val)))
        }
    }

    pub fn get_string(self) -> ConvertResult<String> {
        match self.val {
            LuaString(text) => Ok(text),
            _ => Err(ConverterError::UnexpectedType(
                format!("Expected String, got {:?}", self.val)))
        }
    }

    pub fn get_option<T: FromTable>(self) -> ConvertResult<Option<T>> {
        match self.val {
            LuaNil => Ok(None),
            val => T::from_table(LuaDecoder::new(val)).map(|val| Some(val))
        }
    }

    pub fn read_field<T>(self, name: String) -> ConvertResult<(Self, T)>
        where T: FromTable {
        match self.val {
            LuaArray(mut arr) => {
                let maybe_pos = arr.iter().position(|ref val_pair| {
                    match val_pair.0 {
                        LuaString(ref key) => {
                            *key == name
                        },
                        _ => false
                    }
                });
                if let Some(pos) = maybe_pos {
                    let (_, val) = arr.remove(pos);
                    let val_parser = LuaDecoder::new(val);
                    T::from_table(val_parser).map(|parse|
                                    (LuaDecoder::new(LuaArray(arr)), parse))
                }
                else {
                    Err(ConverterError::MissingTableIndex(name))
                }
            }
            _ => Err(ConverterError::UnexpectedType(
                format!("Expected table, got {:?}", self.val)))
        }
    }

    pub fn get_unordered_array<T: FromTable>(self) -> ConvertResult<Vec<T>> {
        match self.val {
            LuaArray(mut arr) => {
                let mut turn = Vec::with_capacity(arr.len());
                // Completely ignore the keys, push values of type T
                for (_, lua_val) in arr.into_iter() {
                    match T::from_lua_table(lua_val) {
                        Ok(val) => turn.push(val),
                        Err(err) => {
                            return Err(ConverterError::InvalidTableIndex(
                                format!("Attempted to parse value in a Vec, \
                                got error: {}", err.into_message())));
                        }
                    }
                }
                return Ok(turn);
            }
            _ => Err(ConverterError::UnexpectedType(
                 format!("Expected table for Vec, got {:?}", self.val)))
        }
    }

    pub fn get_hash_map<K, V>(self) -> ConvertResult<HashMap<K, V>>
        where K: Eq + Hash + FromTable, V: FromTable {
        match self.val {
            LuaArray(arr) => {
                let mut map = HashMap::with_capacity(arr.len());
                for (lua_key, lua_value) in arr.into_iter() {
                    match K::from_lua_table(lua_key) {
                        Ok(key) => match V::from_lua_table(lua_value) {
                            Ok(value) => { map.insert(key, value); },
                            Err(e) =>
                                return Err(ConverterError::InvalidTableIndex(
                                    format!("Attempted to parse value in a Hash\
                                             Map, got error: {}",
                                            e.into_message())))
                        },
                        Err(e) => return Err(ConverterError::InvalidTableIndex(
                        format!("Attempted to parse key in a HashMap, got error\
                                 : {}", e.into_message())))
                    }
                }
                return Ok(map);
            },
            _ => Err(ConverterError::UnexpectedType(
            format!("Expected table for HashMap, got {:?}", self.val)))
        }
    }
}

macro_rules! primitive_decode {
    ( $($ptype:ty, $fun:ident;) +) => {
        $(impl LuaDecoder {
            pub fn $fun(self) -> ConvertResult<$ptype> {
                match self.val {
                    AnyLuaValue::LuaNumber(num) => Ok(num as $ptype),
                    other => Err(ConverterError::UnexpectedType(
                        format!("Expected {}, got {:?}",
                                stringify!($ptype), other)))
                }
            }
        }

        impl FromTable for $ptype {
            fn from_table(decoder: LuaDecoder) -> ConvertResult<$ptype> {
                LuaDecoder::$fun(decoder)
            }
        })+
    }
}

macro_rules! type_fn_decode {
    ( $( $ptype:ty => $fun:ident), + ) => {
        $(impl FromTable for $ptype {
            fn from_table(decoder: LuaDecoder) -> ConvertResult<$ptype> {
                LuaDecoder::$fun(decoder)
            }
        })+
    }
}

primitive_decode! {
    i8,  get_i8;
    i16, get_i16;
    i32, get_i32;

    u8,  get_u8;
    u16, get_u16;
    u32, get_u32;

    f32, get_f32;
    f64, get_f64;
}

type_fn_decode! {
    String => get_string,
    bool => get_bool
}

impl<T: FromTable> FromTable for Vec<T> {
    fn from_table(decoder: LuaDecoder) -> ConvertResult<Vec<T>> {
        decoder.get_unordered_array()
    }
}

impl<T: FromTable> FromTable for Option<T> {
    fn from_table(decoder: LuaDecoder) -> ConvertResult<Option<T>> {
        decoder.get_option()
    }
}

impl<K, V> FromTable for HashMap<K, V> where K: Hash + Eq + FromTable, V: FromTable {
    fn from_table(decoder: LuaDecoder) -> ConvertResult<HashMap<K,V>> {
        decoder.get_hash_map()
    }
}
<|endoftext|>


<commit_before><commit_msg>added run function to glulx struct, added missing gestalt opcode creation, and fixed up the panic statements when an instruction or opcode is unimplemented<commit_after><|endoftext|>


<commit_before><commit_msg>og:title is used only if rss entrh title is empty<commit_after><|endoftext|>


<commit_before><commit_msg>First cut at parser using Parsell 0.4.2.<commit_after><|endoftext|>


<commit_before>//! Log all requests in a format similar to Heroku's router, but with additional
//! information that we care about like User-Agent

use super::prelude::*;
use crate::util::request_header;
use conduit::{header, RequestExt, StatusCode};
use std::fmt::{self, Display, Formatter};
use std::time::Instant;

const SLOW_REQUEST_THRESHOLD_MS: u64 = 1000;

#[derive(Default)]
pub(super) struct LogRequests();

struct RequestStart(Instant);
struct OriginalPath(String);

impl Middleware for LogRequests {
    fn before(&self, req: &mut dyn RequestExt) -> BeforeResult {
        req.mut_extensions().insert(RequestStart(Instant::now()));
        let path = OriginalPath(req.path().to_string());
        req.mut_extensions().insert(path);
        Ok(())
    }

    fn after(&self, req: &mut dyn RequestExt, res: AfterResult) -> AfterResult {
        // Unwrap shouldn't panic as no other code has access to the private struct to remove it
        let request_start = req.extensions().find::<RequestStart>().unwrap().0;

        let response_time = request_start.elapsed();
        let response_time =
            response_time.as_secs() * 1000 + u64::from(response_time.subsec_nanos()) / 1_000_000;

        println!(
            "{}",
            RequestLine {
                req,
                res: &res,
                response_time,
            }
        );

        res
    }
}

struct CustomMetadata {
    entries: Vec<(&'static str, String)>,
}

pub fn add_custom_metadata<V: Display>(req: &mut dyn RequestExt, key: &'static str, value: V) {
    if let Some(metadata) = req.mut_extensions().find_mut::<CustomMetadata>() {
        metadata.entries.push((key, value.to_string()));
    } else {
        let mut metadata = CustomMetadata {
            entries: Vec::new(),
        };
        metadata.entries.push((key, value.to_string()));
        req.mut_extensions().insert(metadata);
    }
}

#[cfg(test)]
pub(crate) fn get_log_message(req: &dyn RequestExt, key: &'static str) -> String {
    // Unwrap shouldn't panic as no other code has access to the private struct to remove it
    for (k, v) in &req.extensions().find::<CustomMetadata>().unwrap().entries {
        if key == *k {
            return v.clone();
        }
    }
    panic!("expected log message for {} not found", key);
}

struct RequestLine<'r> {
    req: &'r dyn RequestExt,
    res: &'r AfterResult,
    response_time: u64,
}

impl Display for RequestLine<'_> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        let mut line = LogLine::new(f);

        let (at, status) = match self.res {
            Ok(resp) => ("info", resp.status()),
            Err(_) => ("error", StatusCode::INTERNAL_SERVER_ERROR),
        };

        line.add_field("at", at)?;
        line.add_field("method", self.req.method())?;
        line.add_quoted_field("path", FullPath(self.req))?;
        line.add_field("request_id", request_header(self.req, "x-request-id"))?;
        line.add_quoted_field("fwd", request_header(self.req, "x-real-ip"))?;
        line.add_field("service", TimeMs(self.response_time))?;
        line.add_field("status", status.as_str())?;
        line.add_quoted_field("user_agent", request_header(self.req, header::USER_AGENT))?;

        if let Some(metadata) = self.req.extensions().find::<CustomMetadata>() {
            for (key, value) in &metadata.entries {
                line.add_quoted_field(key, value)?;
            }
        }

        if let Err(err) = self.res {
            line.add_quoted_field("error", err)?;
        }

        if self.response_time > SLOW_REQUEST_THRESHOLD_MS {
            line.add_marker("SLOW REQUEST")?;
        }

        Ok(())
    }
}

struct FullPath<'a>(&'a dyn RequestExt);

impl<'a> Display for FullPath<'a> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        // Unwrap shouldn't panic as no other code has access to the private struct to remove it
        write!(
            f,
            "{}",
            self.0.extensions().find::<OriginalPath>().unwrap().0
        )?;
        if let Some(q_string) = self.0.query_string() {
            write!(f, "?{}", q_string)?;
        }
        Ok(())
    }
}

struct TimeMs(u64);

impl Display for TimeMs {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)?;
        f.write_str("ms")?;
        Ok(())
    }
}

struct LogLine<'f, 'g> {
    f: &'f mut Formatter<'g>,
    first: bool,
}

impl<'f, 'g> LogLine<'f, 'g> {
    fn new(f: &'f mut Formatter<'g>) -> Self {
        Self { f, first: true }
    }

    fn add_field<K: Display, V: Display>(&mut self, key: K, value: V) -> fmt::Result {
        self.start_item()?;

        key.fmt(self.f)?;
        self.f.write_str("=")?;
        value.fmt(self.f)?;

        Ok(())
    }

    fn add_quoted_field<K: Display, V: Display>(&mut self, key: K, value: V) -> fmt::Result {
        self.start_item()?;

        key.fmt(self.f)?;
        self.f.write_str("=\"")?;
        value.fmt(self.f)?;
        self.f.write_str("\"")?;

        Ok(())
    }

    fn add_marker<M: Display>(&mut self, marker: M) -> fmt::Result {
        self.start_item()?;

        marker.fmt(self.f)?;

        Ok(())
    }

    fn start_item(&mut self) -> fmt::Result {
        if !self.first {
            self.f.write_str(" ")?;
        }
        self.first = false;
        Ok(())
    }
}
<commit_msg>middleware/log: Report errors and slow requests to Sentry<commit_after>//! Log all requests in a format similar to Heroku's router, but with additional
//! information that we care about like User-Agent

use super::prelude::*;
use crate::util::request_header;
use conduit::{header, Host, RequestExt, Scheme, StatusCode};
use sentry::protocol::IpAddress;
use sentry::Level;
use std::fmt::{self, Display, Formatter};
use std::net::IpAddr;
use std::time::Instant;

const SLOW_REQUEST_THRESHOLD_MS: u64 = 1000;

#[derive(Default)]
pub(super) struct LogRequests();

struct RequestStart(Instant);
struct OriginalPath(String);

impl Middleware for LogRequests {
    fn before(&self, req: &mut dyn RequestExt) -> BeforeResult {
        req.mut_extensions().insert(RequestStart(Instant::now()));
        let path = OriginalPath(req.path().to_string());
        req.mut_extensions().insert(path);
        Ok(())
    }

    fn after(&self, req: &mut dyn RequestExt, res: AfterResult) -> AfterResult {
        // Unwrap shouldn't panic as no other code has access to the private struct to remove it
        let request_start = req.extensions().find::<RequestStart>().unwrap().0;

        let response_time = request_start.elapsed();
        let response_time =
            response_time.as_secs() * 1000 + u64::from(response_time.subsec_nanos()) / 1_000_000;

        println!(
            "{}",
            RequestLine {
                req,
                res: &res,
                response_time,
            }
        );

        report_to_sentry(req, &res, response_time);

        res
    }
}

struct CustomMetadata {
    entries: Vec<(&'static str, String)>,
}

pub fn add_custom_metadata<V: Display>(req: &mut dyn RequestExt, key: &'static str, value: V) {
    if let Some(metadata) = req.mut_extensions().find_mut::<CustomMetadata>() {
        metadata.entries.push((key, value.to_string()));
    } else {
        let mut metadata = CustomMetadata {
            entries: Vec::new(),
        };
        metadata.entries.push((key, value.to_string()));
        req.mut_extensions().insert(metadata);
    }
}

fn report_to_sentry(req: &dyn RequestExt, res: &AfterResult, response_time: u64) {
    let (message, level) = match res {
        Err(e) => (e.to_string(), Level::Error),
        Ok(_) => {
            if response_time <= SLOW_REQUEST_THRESHOLD_MS {
                return;
            }

            let message = format!("Slow Request: {} {}", req.method(), req.path());
            (message, Level::Info)
        }
    };

    let config = |scope: &mut sentry::Scope| {
        let method = Some(req.method().as_str().to_owned());

        let scheme = match req.scheme() {
            Scheme::Http => "http",
            Scheme::Https => "https",
        };

        let host = match req.host() {
            Host::Name(name) => name.to_owned(),
            Host::Socket(addr) => addr.to_string(),
        };

        let path = &req.extensions().find::<OriginalPath>().unwrap().0;

        let url = format!("{}://{}{}", scheme, host, path).parse().ok();

        {
            let ip_addr = match req.headers().get("x-real-ip") {
                Some(value) => value
                    .to_str()
                    .ok()
                    .and_then(|str| str.parse::<IpAddr>().ok()),
                None => Some(req.remote_addr().ip()),
            };

            let user = sentry::User {
                ip_address: ip_addr.map(IpAddress::Exact),
                ..Default::default()
            };

            scope.set_user(Some(user));
        }

        {
            let headers = req
                .headers()
                .iter()
                .map(|(k, v)| (k.to_string(), v.to_str().unwrap_or_default().to_string()))
                .collect();

            let sentry_req = sentry::protocol::Request {
                method,
                url,
                headers,
                ..Default::default()
            };

            scope.add_event_processor(Box::new(move |mut event| {
                if event.request.is_none() {
                    event.request = Some(sentry_req.clone());
                }
                Some(event)
            }));
        }

        if let Some(request_id) = req
            .headers()
            .get("x-request-id")
            .and_then(|value| value.to_str().ok())
        {
            scope.set_tag("request.id", request_id);
        }

        {
            let status = res
                .as_ref()
                .map(|resp| resp.status())
                .unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);

            scope.set_tag("response.status", status.as_str());
        }

        scope.set_extra("Response time [ms]", response_time.into());

        if let Some(metadata) = req.extensions().find::<CustomMetadata>() {
            for (key, value) in &metadata.entries {
                scope.set_extra(key, value.to_string().into());
            }
        }
    };

    sentry::with_scope(config, || sentry::capture_message(&message, level));
}

#[cfg(test)]
pub(crate) fn get_log_message(req: &dyn RequestExt, key: &'static str) -> String {
    // Unwrap shouldn't panic as no other code has access to the private struct to remove it
    for (k, v) in &req.extensions().find::<CustomMetadata>().unwrap().entries {
        if key == *k {
            return v.clone();
        }
    }
    panic!("expected log message for {} not found", key);
}

struct RequestLine<'r> {
    req: &'r dyn RequestExt,
    res: &'r AfterResult,
    response_time: u64,
}

impl Display for RequestLine<'_> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        let mut line = LogLine::new(f);

        let (at, status) = match self.res {
            Ok(resp) => ("info", resp.status()),
            Err(_) => ("error", StatusCode::INTERNAL_SERVER_ERROR),
        };

        line.add_field("at", at)?;
        line.add_field("method", self.req.method())?;
        line.add_quoted_field("path", FullPath(self.req))?;
        line.add_field("request_id", request_header(self.req, "x-request-id"))?;
        line.add_quoted_field("fwd", request_header(self.req, "x-real-ip"))?;
        line.add_field("service", TimeMs(self.response_time))?;
        line.add_field("status", status.as_str())?;
        line.add_quoted_field("user_agent", request_header(self.req, header::USER_AGENT))?;

        if let Some(metadata) = self.req.extensions().find::<CustomMetadata>() {
            for (key, value) in &metadata.entries {
                line.add_quoted_field(key, value)?;
            }
        }

        if let Err(err) = self.res {
            line.add_quoted_field("error", err)?;
        }

        if self.response_time > SLOW_REQUEST_THRESHOLD_MS {
            line.add_marker("SLOW REQUEST")?;
        }

        Ok(())
    }
}

struct FullPath<'a>(&'a dyn RequestExt);

impl<'a> Display for FullPath<'a> {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        // Unwrap shouldn't panic as no other code has access to the private struct to remove it
        write!(
            f,
            "{}",
            self.0.extensions().find::<OriginalPath>().unwrap().0
        )?;
        if let Some(q_string) = self.0.query_string() {
            write!(f, "?{}", q_string)?;
        }
        Ok(())
    }
}

struct TimeMs(u64);

impl Display for TimeMs {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        self.0.fmt(f)?;
        f.write_str("ms")?;
        Ok(())
    }
}

struct LogLine<'f, 'g> {
    f: &'f mut Formatter<'g>,
    first: bool,
}

impl<'f, 'g> LogLine<'f, 'g> {
    fn new(f: &'f mut Formatter<'g>) -> Self {
        Self { f, first: true }
    }

    fn add_field<K: Display, V: Display>(&mut self, key: K, value: V) -> fmt::Result {
        self.start_item()?;

        key.fmt(self.f)?;
        self.f.write_str("=")?;
        value.fmt(self.f)?;

        Ok(())
    }

    fn add_quoted_field<K: Display, V: Display>(&mut self, key: K, value: V) -> fmt::Result {
        self.start_item()?;

        key.fmt(self.f)?;
        self.f.write_str("=\"")?;
        value.fmt(self.f)?;
        self.f.write_str("\"")?;

        Ok(())
    }

    fn add_marker<M: Display>(&mut self, marker: M) -> fmt::Result {
        self.start_item()?;

        marker.fmt(self.f)?;

        Ok(())
    }

    fn start_item(&mut self) -> fmt::Result {
        if !self.first {
            self.f.write_str(" ")?;
        }
        self.first = false;
        Ok(())
    }
}
<|endoftext|>


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

use core::cmp::PartialEq;
use core::fmt::Debug;
use core::num::{NumCast, cast};
use core::ops::{Add, Sub, Mul, Div, Rem};
use core::marker::Copy;

#[macro_use]
mod int_macros;

mod i8;
mod i16;
mod i32;
mod i64;
mod int;

#[macro_use]
mod uint_macros;

mod u8;
mod u16;
mod u32;
mod u64;
mod uint;

/// Helper function for testing numeric operations
pub fn test_num<T>(ten: T, two: T) where
    T: PartialEq + NumCast
     + Add<Output=T> + Sub<Output=T>
     + Mul<Output=T> + Div<Output=T>
     + Rem<Output=T> + Debug
     + Copy
{
    assert_eq!(ten.add(two),  cast(12).unwrap());
    assert_eq!(ten.sub(two),  cast(8).unwrap());
    assert_eq!(ten.mul(two),  cast(20).unwrap());
    assert_eq!(ten.div(two),  cast(5).unwrap());
    assert_eq!(ten.rem(two),  cast(0).unwrap());

    assert_eq!(ten.add(two),  ten + two);
    assert_eq!(ten.sub(two),  ten - two);
    assert_eq!(ten.mul(two),  ten * two);
    assert_eq!(ten.div(two),  ten / two);
    assert_eq!(ten.rem(two),  ten % two);
}

#[cfg(test)]
mod test {
    use core::option::Option;
    use core::option::Option::{Some, None};
    use core::num::Float;
    use core::num::from_str_radix;

    #[test]
    fn from_str_issue7588() {
        let u : Option<u8> = from_str_radix("1000", 10).ok();
        assert_eq!(u, None);
        let s : Option<i16> = from_str_radix("80000", 10).ok();
        assert_eq!(s, None);
        let f : Option<f32> = from_str_radix("10000000000000000000000000000000000000000", 10).ok();
        assert_eq!(f, Some(Float::infinity()));
        let fe : Option<f32> = from_str_radix("1e40", 10).ok();
        assert_eq!(fe, Some(Float::infinity()));
    }

    #[test]
    fn test_from_str_radix_float() {
        let x1 : Option<f64> = from_str_radix("-123.456", 10).ok();
        assert_eq!(x1, Some(-123.456));
        let x2 : Option<f32> = from_str_radix("123.456", 10).ok();
        assert_eq!(x2, Some(123.456));
        let x3 : Option<f32> = from_str_radix("-0.0", 10).ok();
        assert_eq!(x3, Some(-0.0));
        let x4 : Option<f32> = from_str_radix("0.0", 10).ok();
        assert_eq!(x4, Some(0.0));
        let x4 : Option<f32> = from_str_radix("1.0", 10).ok();
        assert_eq!(x4, Some(1.0));
        let x5 : Option<f32> = from_str_radix("-1.0", 10).ok();
        assert_eq!(x5, Some(-1.0));
    }

    #[test]
    fn test_int_from_str_overflow() {
        let mut i8_val: i8 = 127_i8;
        assert_eq!("127".parse::<i8>().ok(), Some(i8_val));
        assert_eq!("128".parse::<i8>().ok(), None);

        i8_val += 1 as i8;
        assert_eq!("-128".parse::<i8>().ok(), Some(i8_val));
        assert_eq!("-129".parse::<i8>().ok(), None);

        let mut i16_val: i16 = 32_767_i16;
        assert_eq!("32767".parse::<i16>().ok(), Some(i16_val));
        assert_eq!("32768".parse::<i16>().ok(), None);

        i16_val += 1 as i16;
        assert_eq!("-32768".parse::<i16>().ok(), Some(i16_val));
        assert_eq!("-32769".parse::<i16>().ok(), None);

        let mut i32_val: i32 = 2_147_483_647_i32;
        assert_eq!("2147483647".parse::<i32>().ok(), Some(i32_val));
        assert_eq!("2147483648".parse::<i32>().ok(), None);

        i32_val += 1 as i32;
        assert_eq!("-2147483648".parse::<i32>().ok(), Some(i32_val));
        assert_eq!("-2147483649".parse::<i32>().ok(), None);

        let mut i64_val: i64 = 9_223_372_036_854_775_807_i64;
        assert_eq!("9223372036854775807".parse::<i64>().ok(), Some(i64_val));
        assert_eq!("9223372036854775808".parse::<i64>().ok(), None);

        i64_val += 1 as i64;
        assert_eq!("-9223372036854775808".parse::<i64>().ok(), Some(i64_val));
        assert_eq!("-9223372036854775809".parse::<i64>().ok(), None);
    }

    #[test]
    test_int_from_minus_sign() {
        assert_eq!("-".parse::<i32>().ok(), None);
    }
}
<commit_msg>Add missing `fn`<commit_after>// Copyright 2014 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.

use core::cmp::PartialEq;
use core::fmt::Debug;
use core::num::{NumCast, cast};
use core::ops::{Add, Sub, Mul, Div, Rem};
use core::marker::Copy;

#[macro_use]
mod int_macros;

mod i8;
mod i16;
mod i32;
mod i64;
mod int;

#[macro_use]
mod uint_macros;

mod u8;
mod u16;
mod u32;
mod u64;
mod uint;

/// Helper function for testing numeric operations
pub fn test_num<T>(ten: T, two: T) where
    T: PartialEq + NumCast
     + Add<Output=T> + Sub<Output=T>
     + Mul<Output=T> + Div<Output=T>
     + Rem<Output=T> + Debug
     + Copy
{
    assert_eq!(ten.add(two),  cast(12).unwrap());
    assert_eq!(ten.sub(two),  cast(8).unwrap());
    assert_eq!(ten.mul(two),  cast(20).unwrap());
    assert_eq!(ten.div(two),  cast(5).unwrap());
    assert_eq!(ten.rem(two),  cast(0).unwrap());

    assert_eq!(ten.add(two),  ten + two);
    assert_eq!(ten.sub(two),  ten - two);
    assert_eq!(ten.mul(two),  ten * two);
    assert_eq!(ten.div(two),  ten / two);
    assert_eq!(ten.rem(two),  ten % two);
}

#[cfg(test)]
mod test {
    use core::option::Option;
    use core::option::Option::{Some, None};
    use core::num::Float;
    use core::num::from_str_radix;

    #[test]
    fn from_str_issue7588() {
        let u : Option<u8> = from_str_radix("1000", 10).ok();
        assert_eq!(u, None);
        let s : Option<i16> = from_str_radix("80000", 10).ok();
        assert_eq!(s, None);
        let f : Option<f32> = from_str_radix("10000000000000000000000000000000000000000", 10).ok();
        assert_eq!(f, Some(Float::infinity()));
        let fe : Option<f32> = from_str_radix("1e40", 10).ok();
        assert_eq!(fe, Some(Float::infinity()));
    }

    #[test]
    fn test_from_str_radix_float() {
        let x1 : Option<f64> = from_str_radix("-123.456", 10).ok();
        assert_eq!(x1, Some(-123.456));
        let x2 : Option<f32> = from_str_radix("123.456", 10).ok();
        assert_eq!(x2, Some(123.456));
        let x3 : Option<f32> = from_str_radix("-0.0", 10).ok();
        assert_eq!(x3, Some(-0.0));
        let x4 : Option<f32> = from_str_radix("0.0", 10).ok();
        assert_eq!(x4, Some(0.0));
        let x4 : Option<f32> = from_str_radix("1.0", 10).ok();
        assert_eq!(x4, Some(1.0));
        let x5 : Option<f32> = from_str_radix("-1.0", 10).ok();
        assert_eq!(x5, Some(-1.0));
    }

    #[test]
    fn test_int_from_str_overflow() {
        let mut i8_val: i8 = 127_i8;
        assert_eq!("127".parse::<i8>().ok(), Some(i8_val));
        assert_eq!("128".parse::<i8>().ok(), None);

        i8_val += 1 as i8;
        assert_eq!("-128".parse::<i8>().ok(), Some(i8_val));
        assert_eq!("-129".parse::<i8>().ok(), None);

        let mut i16_val: i16 = 32_767_i16;
        assert_eq!("32767".parse::<i16>().ok(), Some(i16_val));
        assert_eq!("32768".parse::<i16>().ok(), None);

        i16_val += 1 as i16;
        assert_eq!("-32768".parse::<i16>().ok(), Some(i16_val));
        assert_eq!("-32769".parse::<i16>().ok(), None);

        let mut i32_val: i32 = 2_147_483_647_i32;
        assert_eq!("2147483647".parse::<i32>().ok(), Some(i32_val));
        assert_eq!("2147483648".parse::<i32>().ok(), None);

        i32_val += 1 as i32;
        assert_eq!("-2147483648".parse::<i32>().ok(), Some(i32_val));
        assert_eq!("-2147483649".parse::<i32>().ok(), None);

        let mut i64_val: i64 = 9_223_372_036_854_775_807_i64;
        assert_eq!("9223372036854775807".parse::<i64>().ok(), Some(i64_val));
        assert_eq!("9223372036854775808".parse::<i64>().ok(), None);

        i64_val += 1 as i64;
        assert_eq!("-9223372036854775808".parse::<i64>().ok(), Some(i64_val));
        assert_eq!("-9223372036854775809".parse::<i64>().ok(), None);
    }

    #[test]
    fn test_int_from_minus_sign() {
        assert_eq!("-".parse::<i32>().ok(), None);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

use bincode;
use crossbeam_channel::{self, Receiver, Select, Sender, TryRecvError};
use crate::ipc;
use std::sync::{Arc, Mutex};
use std::collections::hash_map::HashMap;
use std::cell::{RefCell, Ref};
use std::error::Error as StdError;
use std::io;
use std::slice;
use std::fmt::{self, Debug, Formatter};
use std::cmp::{PartialEq};
use std::ops::{Deref, RangeFrom};
use std::usize;
use uuid::Uuid;

#[derive(Clone)]
struct ServerRecord {
    sender: OsIpcSender,
    conn_sender: Sender<bool>,
    conn_receiver: Receiver<bool>,
}

impl ServerRecord {
    fn new(sender: OsIpcSender) -> ServerRecord {
        let (tx, rx) = crossbeam_channel::unbounded::<bool>();
        ServerRecord {
            sender: sender,
            conn_sender: tx,
            conn_receiver: rx,
        }
    }

    fn accept(&self) {
        self.conn_receiver.recv().unwrap();
    }

    fn connect(&self) {
        self.conn_sender.send(true).unwrap();
    }
}

lazy_static! {
    static ref ONE_SHOT_SERVERS: Mutex<HashMap<String,ServerRecord>> = Mutex::new(HashMap::new());
}

struct ChannelMessage(Vec<u8>, Vec<OsIpcChannel>, Vec<OsIpcSharedMemory>);

pub fn channel() -> Result<(OsIpcSender, OsIpcReceiver), ChannelError> {
    let (base_sender, base_receiver) = crossbeam_channel::unbounded::<ChannelMessage>();
    Ok((
        OsIpcSender::new(base_sender),
        OsIpcReceiver::new(base_receiver)
    ))
}

#[derive(Debug)]
pub struct OsIpcReceiver {
    receiver: RefCell<Option<crossbeam_channel::Receiver<ChannelMessage>>>,
}

impl PartialEq for OsIpcReceiver {
    fn eq(&self, other: &OsIpcReceiver) -> bool {
        self.receiver.borrow().as_ref().map(|rx| rx as *const _) ==
            other.receiver.borrow().as_ref().map(|rx| rx as *const _)
    }
}

impl OsIpcReceiver {
    fn new(receiver: Receiver<ChannelMessage>) -> OsIpcReceiver {
        OsIpcReceiver { receiver: RefCell::new(Some(receiver)) }
    }

    pub fn consume(&self) -> OsIpcReceiver {
        OsIpcReceiver { receiver: RefCell::new(self.receiver.borrow_mut().take()) }
    }

    pub fn recv(
        &self
    ) -> Result<(Vec<u8>, Vec<OsOpaqueIpcChannel>, Vec<OsIpcSharedMemory>), ChannelError> {
        let r = self.receiver.borrow();
        let r = r.as_ref().unwrap();
        match r.recv() {
            Ok(ChannelMessage(d, c, s)) => {
                Ok((d, c.into_iter().map(OsOpaqueIpcChannel::new).collect(), s))
            }
            Err(_) => Err(ChannelError::ChannelClosedError),
        }
    }

    pub fn try_recv(
        &self
    ) -> Result<(Vec<u8>, Vec<OsOpaqueIpcChannel>, Vec<OsIpcSharedMemory>), ChannelError> {
        let r = self.receiver.borrow();
        let r = r.as_ref().unwrap();
        match r.try_recv() {
            Ok(ChannelMessage(d, c, s)) => {
                Ok((d, c.into_iter().map(OsOpaqueIpcChannel::new).collect(), s))
            },
            Err(e) => {
                match e {
                    TryRecvError::Empty => Err(ChannelError::ChannelEmpty),
                    TryRecvError::Disconnected => Err(ChannelError::ChannelClosedError),
                }
            }
        }
    }
}

#[derive(Clone, Debug)]
pub struct OsIpcSender {
    sender: RefCell<Sender<ChannelMessage>>,
}

impl PartialEq for OsIpcSender {
    fn eq(&self, other: &OsIpcSender) -> bool {
        &*self.sender.borrow() as *const _ ==
            &*other.sender.borrow() as *const _
    }
}

impl OsIpcSender {
    fn new(sender: Sender<ChannelMessage>) -> OsIpcSender {
        OsIpcSender {
            sender: RefCell::new(sender),
        }
    }

    pub fn connect(name: String) -> Result<OsIpcSender, ChannelError> {
        let record = ONE_SHOT_SERVERS.lock().unwrap().get(&name).unwrap().clone();
        record.connect();
        Ok(record.sender)
    }

    pub fn get_max_fragment_size() -> usize {
        usize::MAX
    }

    pub fn send(
        &self,
        data: &[u8],
        ports: Vec<OsIpcChannel>,
        shared_memory_regions: Vec<OsIpcSharedMemory>,
    ) -> Result<(), ChannelError> {
        Ok(self.sender
            .borrow()
            .send(ChannelMessage(data.to_vec(), ports, shared_memory_regions)).map_err(|_| ChannelError::BrokenPipeError)?)
    }
}

pub struct OsIpcReceiverSet {
    incrementor: RangeFrom<u64>,
    receiver_ids: Vec<u64>,
    receivers: Vec<OsIpcReceiver>,
}

impl OsIpcReceiverSet {
    pub fn new() -> Result<OsIpcReceiverSet, ChannelError> {
        Ok(OsIpcReceiverSet {
            incrementor: 0..,
            receiver_ids: vec![],
            receivers: vec![],
        })
    }

    pub fn add(&mut self, receiver: OsIpcReceiver) -> Result<u64, ChannelError> {
        let last_index = self.incrementor.next().unwrap();
        self.receiver_ids.push(last_index);
        self.receivers.push(receiver.consume());
        Ok(last_index)
    }

    pub fn select(&mut self) -> Result<Vec<OsIpcSelectionResult>, ChannelError> {
        if self.receivers.is_empty() {
            return Err(ChannelError::UnknownError);
        }

        struct Remove(usize, u64);

        // FIXME: Remove early returns and explictly drop `borrows` when lifetimes are non-lexical
        let Remove(r_index, r_id) = {
            let borrows: Vec<_> = self.receivers.iter().map(|r| {
                Ref::map(r.receiver.borrow(), |o| o.as_ref().unwrap())
            }).collect();

            let mut select = Select::new();
            for r in &borrows {
                select.recv(&r);
            }
            let res = select.select();
            let r_index = res.index();
            let r_id = self.receiver_ids[r_index];
            if let Ok(ChannelMessage(data, channels, shmems)) = res.recv(&borrows[r_index as usize]) {
                let channels = channels.into_iter().map(OsOpaqueIpcChannel::new).collect();
                return Ok(vec![OsIpcSelectionResult::DataReceived(r_id, data, channels, shmems)])
            } else {
                Remove(r_index, r_id)
            }
        };
        self.receivers.remove(r_index);
        self.receiver_ids.remove(r_index);
        Ok(vec![OsIpcSelectionResult::ChannelClosed(r_id)])
    }
}

pub enum OsIpcSelectionResult {
    DataReceived(u64, Vec<u8>, Vec<OsOpaqueIpcChannel>, Vec<OsIpcSharedMemory>),
    ChannelClosed(u64),
}

impl OsIpcSelectionResult {
    pub fn unwrap(self) -> (u64, Vec<u8>, Vec<OsOpaqueIpcChannel>, Vec<OsIpcSharedMemory>) {
        match self {
            OsIpcSelectionResult::DataReceived(id, data, channels, shared_memory_regions) => {
                (id, data, channels, shared_memory_regions)
            }
            OsIpcSelectionResult::ChannelClosed(id) => {
                panic!("OsIpcSelectionResult::unwrap(): receiver ID {} was closed!", id)
            }
        }
    }
}

pub struct OsIpcOneShotServer {
    receiver: OsIpcReceiver,
    name: String,
}

impl OsIpcOneShotServer {
    pub fn new() -> Result<(OsIpcOneShotServer, String), ChannelError> {
        let (sender, receiver) = channel()?;

        let name = Uuid::new_v4().to_string();
        let record = ServerRecord::new(sender);
        ONE_SHOT_SERVERS.lock().unwrap().insert(name.clone(), record);
        Ok((OsIpcOneShotServer {
            receiver: receiver,
            name: name.clone(),
        },name.clone()))
    }

    pub fn accept(
        self,
    ) -> Result<
        (
            OsIpcReceiver,
            Vec<u8>,
            Vec<OsOpaqueIpcChannel>,
            Vec<OsIpcSharedMemory>,
        ),
        ChannelError,
    > {
        let record = ONE_SHOT_SERVERS
            .lock()
            .unwrap()
            .get(&self.name)
            .unwrap()
            .clone();
        record.accept();
        ONE_SHOT_SERVERS.lock().unwrap().remove(&self.name).unwrap();
        let (data, channels, shmems) = self.receiver.recv()?;
        Ok((self.receiver, data, channels, shmems))
    }
}

#[derive(PartialEq, Debug)]
pub enum OsIpcChannel {
    Sender(OsIpcSender),
    Receiver(OsIpcReceiver),
}

#[derive(PartialEq, Debug)]
pub struct OsOpaqueIpcChannel {
    channel: RefCell<Option<OsIpcChannel>>,
}

impl OsOpaqueIpcChannel {
    fn new(channel: OsIpcChannel) -> OsOpaqueIpcChannel {
        OsOpaqueIpcChannel {
            channel: RefCell::new(Some(channel))
        }
    }

    pub fn to_receiver(&self) -> OsIpcReceiver {
        match self.channel.borrow_mut().take().unwrap() {
            OsIpcChannel::Sender(_) => panic!("Opaque channel is not a receiver!"),
            OsIpcChannel::Receiver(r) => r
        }
    }

    pub fn to_sender(&mut self) -> OsIpcSender {
        match self.channel.borrow_mut().take().unwrap() {
            OsIpcChannel::Sender(s) => s,
            OsIpcChannel::Receiver(_) => panic!("Opaque channel is not a sender!"),
        }
    }
}

pub struct OsIpcSharedMemory {
    ptr: *mut u8,
    length: usize,
    data: Arc<Vec<u8>>,
}

unsafe impl Send for OsIpcSharedMemory {}
unsafe impl Sync for OsIpcSharedMemory {}

impl Clone for OsIpcSharedMemory {
    fn clone(&self) -> OsIpcSharedMemory {
        OsIpcSharedMemory {
            ptr: self.ptr,
            length: self.length,
            data: self.data.clone(),
        }
    }
}

impl PartialEq for OsIpcSharedMemory {
    fn eq(&self, other: &OsIpcSharedMemory) -> bool {
        **self == **other
    }
}

impl Debug for OsIpcSharedMemory {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> {
        (**self).fmt(formatter)
    }
}

impl Deref for OsIpcSharedMemory {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &[u8] {
        if self.ptr.is_null() {
            panic!("attempted to access a consumed `OsIpcSharedMemory`")
        }
        unsafe {
            slice::from_raw_parts(self.ptr, self.length)
        }
    }
}

impl OsIpcSharedMemory {
    pub fn from_byte(byte: u8, length: usize) -> OsIpcSharedMemory {
        let mut v = Arc::new(vec![byte; length]);
        OsIpcSharedMemory {
            ptr: Arc::get_mut(&mut v).unwrap().as_mut_ptr(),
            length: length,
            data: v
        }
    }

    pub fn from_bytes(bytes: &[u8]) -> OsIpcSharedMemory {
        let mut v = Arc::new(bytes.to_vec());
        OsIpcSharedMemory {
            ptr: Arc::get_mut(&mut v).unwrap().as_mut_ptr(),
            length: v.len(),
            data: v
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum ChannelError {
    ChannelClosedError,
    BrokenPipeError,
    ChannelEmpty,
    UnknownError,
}

impl ChannelError {
    #[allow(dead_code)]
    pub fn channel_is_closed(&self) -> bool {
        *self == ChannelError::ChannelClosedError
    }
}

impl fmt::Display for ChannelError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ChannelError::ChannelClosedError => write!(fmt, "channel closed"),
            ChannelError::BrokenPipeError => write!(fmt, "broken pipe"),
            ChannelError::ChannelEmpty => write!(fmt, "channel empty"),
            ChannelError::UnknownError => write!(fmt, "unknown error"),
        }
    }
}

impl StdError for ChannelError {
}

impl From<ChannelError> for bincode::Error {
    fn from(crossbeam_error: ChannelError) -> Self {
        io::Error::from(crossbeam_error).into()
    }
}

impl From<ChannelError> for ipc::IpcError {
    fn from(error: ChannelError) -> Self {
        match error {
            ChannelError::ChannelClosedError => ipc::IpcError::Disconnected,
            e => ipc::IpcError::Bincode(io::Error::from(e).into()),
        }
    }
}

impl From<ChannelError> for ipc::TryRecvError {
    fn from(error: ChannelError) -> Self {
        match error {
            ChannelError::ChannelClosedError => ipc::TryRecvError::IpcError(ipc::IpcError::Disconnected),
            ChannelError::ChannelEmpty => ipc::TryRecvError::Empty,
            e => ipc::TryRecvError::IpcError(ipc::IpcError::Bincode(io::Error::from(e).into())),
        }
    }
}

impl From<ChannelError> for io::Error {
    fn from(crossbeam_error: ChannelError) -> io::Error {
        match crossbeam_error {
            ChannelError::ChannelClosedError => {
                io::Error::new(io::ErrorKind::ConnectionReset, "crossbeam-channel sender closed")
            }
            ChannelError::ChannelEmpty => {
                io::Error::new(io::ErrorKind::ConnectionReset, "crossbeam-channel receiver has no received messages")
            }
            ChannelError::BrokenPipeError => {
                io::Error::new(io::ErrorKind::BrokenPipe, "crossbeam-channel receiver closed")
            }
            ChannelError::UnknownError => {
                io::Error::new(io::ErrorKind::Other, "Other crossbeam-channel error")
            }
        }
    }
}

<commit_msg>implement try_recv_timeout for inprocess only<commit_after>// Copyright 2015 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// 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.

use bincode;
use crossbeam_channel::{self, Receiver, RecvTimeoutError, Select, Sender, TryRecvError};
use crate::ipc;
use std::sync::{Arc, Mutex};
use std::collections::hash_map::HashMap;
use std::cell::{RefCell, Ref};
use std::error::Error as StdError;
use std::io;
use std::slice;
use std::fmt::{self, Debug, Formatter};
use std::cmp::{PartialEq};
use std::ops::{Deref, RangeFrom};
use std::time::Duration;
use std::usize;
use uuid::Uuid;

#[derive(Clone)]
struct ServerRecord {
    sender: OsIpcSender,
    conn_sender: Sender<bool>,
    conn_receiver: Receiver<bool>,
}

impl ServerRecord {
    fn new(sender: OsIpcSender) -> ServerRecord {
        let (tx, rx) = crossbeam_channel::unbounded::<bool>();
        ServerRecord {
            sender: sender,
            conn_sender: tx,
            conn_receiver: rx,
        }
    }

    fn accept(&self) {
        self.conn_receiver.recv().unwrap();
    }

    fn connect(&self) {
        self.conn_sender.send(true).unwrap();
    }
}

lazy_static! {
    static ref ONE_SHOT_SERVERS: Mutex<HashMap<String,ServerRecord>> = Mutex::new(HashMap::new());
}

struct ChannelMessage(Vec<u8>, Vec<OsIpcChannel>, Vec<OsIpcSharedMemory>);

pub fn channel() -> Result<(OsIpcSender, OsIpcReceiver), ChannelError> {
    let (base_sender, base_receiver) = crossbeam_channel::unbounded::<ChannelMessage>();
    Ok((
        OsIpcSender::new(base_sender),
        OsIpcReceiver::new(base_receiver)
    ))
}

#[derive(Debug)]
pub struct OsIpcReceiver {
    receiver: RefCell<Option<crossbeam_channel::Receiver<ChannelMessage>>>,
}

impl PartialEq for OsIpcReceiver {
    fn eq(&self, other: &OsIpcReceiver) -> bool {
        self.receiver.borrow().as_ref().map(|rx| rx as *const _) ==
            other.receiver.borrow().as_ref().map(|rx| rx as *const _)
    }
}

impl OsIpcReceiver {
    fn new(receiver: Receiver<ChannelMessage>) -> OsIpcReceiver {
        OsIpcReceiver { receiver: RefCell::new(Some(receiver)) }
    }

    pub fn consume(&self) -> OsIpcReceiver {
        OsIpcReceiver { receiver: RefCell::new(self.receiver.borrow_mut().take()) }
    }

    pub fn recv(
        &self
    ) -> Result<(Vec<u8>, Vec<OsOpaqueIpcChannel>, Vec<OsIpcSharedMemory>), ChannelError> {
        let r = self.receiver.borrow();
        let r = r.as_ref().unwrap();
        match r.recv() {
            Ok(ChannelMessage(d, c, s)) => {
                Ok((d, c.into_iter().map(OsOpaqueIpcChannel::new).collect(), s))
            }
            Err(_) => Err(ChannelError::ChannelClosedError),
        }
    }

    pub fn try_recv(
        &self
    ) -> Result<(Vec<u8>, Vec<OsOpaqueIpcChannel>, Vec<OsIpcSharedMemory>), ChannelError> {
        let r = self.receiver.borrow();
        let r = r.as_ref().unwrap();
        match r.try_recv() {
            Ok(ChannelMessage(d, c, s)) => {
                Ok((d, c.into_iter().map(OsOpaqueIpcChannel::new).collect(), s))
            },
            Err(e) => {
                match e {
                    TryRecvError::Empty => Err(ChannelError::ChannelEmpty),
                    TryRecvError::Disconnected => Err(ChannelError::ChannelClosedError),
                }
            }
        }
    }

    pub fn try_recv_timeout(
        &self,
        duration: Duration,
    ) -> Result<(Vec<u8>, Vec<OsOpaqueIpcChannel>, Vec<OsIpcSharedMemory>), ChannelError> {
        let r = self.receiver.borrow();
        let r = r.as_ref().unwrap();
        match r.recv_timeout(duration) {
            Ok(ChannelMessage(d, c, s)) => {
                Ok((d, c.into_iter().map(OsOpaqueIpcChannel::new).collect(), s))
            },
            Err(e) => {
                match e {
                    RecvTimeoutError::Timeout => Err(ChannelError::ChannelEmpty),
                    RecvTimeoutError::Disconnected => Err(ChannelError::ChannelClosedError),
                }
            }
        }
    }
}

#[derive(Clone, Debug)]
pub struct OsIpcSender {
    sender: RefCell<Sender<ChannelMessage>>,
}

impl PartialEq for OsIpcSender {
    fn eq(&self, other: &OsIpcSender) -> bool {
        &*self.sender.borrow() as *const _ ==
            &*other.sender.borrow() as *const _
    }
}

impl OsIpcSender {
    fn new(sender: Sender<ChannelMessage>) -> OsIpcSender {
        OsIpcSender {
            sender: RefCell::new(sender),
        }
    }

    pub fn connect(name: String) -> Result<OsIpcSender, ChannelError> {
        let record = ONE_SHOT_SERVERS.lock().unwrap().get(&name).unwrap().clone();
        record.connect();
        Ok(record.sender)
    }

    pub fn get_max_fragment_size() -> usize {
        usize::MAX
    }

    pub fn send(
        &self,
        data: &[u8],
        ports: Vec<OsIpcChannel>,
        shared_memory_regions: Vec<OsIpcSharedMemory>,
    ) -> Result<(), ChannelError> {
        Ok(self.sender
            .borrow()
            .send(ChannelMessage(data.to_vec(), ports, shared_memory_regions)).map_err(|_| ChannelError::BrokenPipeError)?)
    }
}

pub struct OsIpcReceiverSet {
    incrementor: RangeFrom<u64>,
    receiver_ids: Vec<u64>,
    receivers: Vec<OsIpcReceiver>,
}

impl OsIpcReceiverSet {
    pub fn new() -> Result<OsIpcReceiverSet, ChannelError> {
        Ok(OsIpcReceiverSet {
            incrementor: 0..,
            receiver_ids: vec![],
            receivers: vec![],
        })
    }

    pub fn add(&mut self, receiver: OsIpcReceiver) -> Result<u64, ChannelError> {
        let last_index = self.incrementor.next().unwrap();
        self.receiver_ids.push(last_index);
        self.receivers.push(receiver.consume());
        Ok(last_index)
    }

    pub fn select(&mut self) -> Result<Vec<OsIpcSelectionResult>, ChannelError> {
        if self.receivers.is_empty() {
            return Err(ChannelError::UnknownError);
        }

        struct Remove(usize, u64);

        // FIXME: Remove early returns and explictly drop `borrows` when lifetimes are non-lexical
        let Remove(r_index, r_id) = {
            let borrows: Vec<_> = self.receivers.iter().map(|r| {
                Ref::map(r.receiver.borrow(), |o| o.as_ref().unwrap())
            }).collect();

            let mut select = Select::new();
            for r in &borrows {
                select.recv(&r);
            }
            let res = select.select();
            let r_index = res.index();
            let r_id = self.receiver_ids[r_index];
            if let Ok(ChannelMessage(data, channels, shmems)) = res.recv(&borrows[r_index as usize]) {
                let channels = channels.into_iter().map(OsOpaqueIpcChannel::new).collect();
                return Ok(vec![OsIpcSelectionResult::DataReceived(r_id, data, channels, shmems)])
            } else {
                Remove(r_index, r_id)
            }
        };
        self.receivers.remove(r_index);
        self.receiver_ids.remove(r_index);
        Ok(vec![OsIpcSelectionResult::ChannelClosed(r_id)])
    }
}

pub enum OsIpcSelectionResult {
    DataReceived(u64, Vec<u8>, Vec<OsOpaqueIpcChannel>, Vec<OsIpcSharedMemory>),
    ChannelClosed(u64),
}

impl OsIpcSelectionResult {
    pub fn unwrap(self) -> (u64, Vec<u8>, Vec<OsOpaqueIpcChannel>, Vec<OsIpcSharedMemory>) {
        match self {
            OsIpcSelectionResult::DataReceived(id, data, channels, shared_memory_regions) => {
                (id, data, channels, shared_memory_regions)
            }
            OsIpcSelectionResult::ChannelClosed(id) => {
                panic!("OsIpcSelectionResult::unwrap(): receiver ID {} was closed!", id)
            }
        }
    }
}

pub struct OsIpcOneShotServer {
    receiver: OsIpcReceiver,
    name: String,
}

impl OsIpcOneShotServer {
    pub fn new() -> Result<(OsIpcOneShotServer, String), ChannelError> {
        let (sender, receiver) = channel()?;

        let name = Uuid::new_v4().to_string();
        let record = ServerRecord::new(sender);
        ONE_SHOT_SERVERS.lock().unwrap().insert(name.clone(), record);
        Ok((OsIpcOneShotServer {
            receiver: receiver,
            name: name.clone(),
        },name.clone()))
    }

    pub fn accept(
        self,
    ) -> Result<
        (
            OsIpcReceiver,
            Vec<u8>,
            Vec<OsOpaqueIpcChannel>,
            Vec<OsIpcSharedMemory>,
        ),
        ChannelError,
    > {
        let record = ONE_SHOT_SERVERS
            .lock()
            .unwrap()
            .get(&self.name)
            .unwrap()
            .clone();
        record.accept();
        ONE_SHOT_SERVERS.lock().unwrap().remove(&self.name).unwrap();
        let (data, channels, shmems) = self.receiver.recv()?;
        Ok((self.receiver, data, channels, shmems))
    }
}

#[derive(PartialEq, Debug)]
pub enum OsIpcChannel {
    Sender(OsIpcSender),
    Receiver(OsIpcReceiver),
}

#[derive(PartialEq, Debug)]
pub struct OsOpaqueIpcChannel {
    channel: RefCell<Option<OsIpcChannel>>,
}

impl OsOpaqueIpcChannel {
    fn new(channel: OsIpcChannel) -> OsOpaqueIpcChannel {
        OsOpaqueIpcChannel {
            channel: RefCell::new(Some(channel))
        }
    }

    pub fn to_receiver(&self) -> OsIpcReceiver {
        match self.channel.borrow_mut().take().unwrap() {
            OsIpcChannel::Sender(_) => panic!("Opaque channel is not a receiver!"),
            OsIpcChannel::Receiver(r) => r
        }
    }

    pub fn to_sender(&mut self) -> OsIpcSender {
        match self.channel.borrow_mut().take().unwrap() {
            OsIpcChannel::Sender(s) => s,
            OsIpcChannel::Receiver(_) => panic!("Opaque channel is not a sender!"),
        }
    }
}

pub struct OsIpcSharedMemory {
    ptr: *mut u8,
    length: usize,
    data: Arc<Vec<u8>>,
}

unsafe impl Send for OsIpcSharedMemory {}
unsafe impl Sync for OsIpcSharedMemory {}

impl Clone for OsIpcSharedMemory {
    fn clone(&self) -> OsIpcSharedMemory {
        OsIpcSharedMemory {
            ptr: self.ptr,
            length: self.length,
            data: self.data.clone(),
        }
    }
}

impl PartialEq for OsIpcSharedMemory {
    fn eq(&self, other: &OsIpcSharedMemory) -> bool {
        **self == **other
    }
}

impl Debug for OsIpcSharedMemory {
    fn fmt(&self, formatter: &mut Formatter) -> Result<(), fmt::Error> {
        (**self).fmt(formatter)
    }
}

impl Deref for OsIpcSharedMemory {
    type Target = [u8];

    #[inline]
    fn deref(&self) -> &[u8] {
        if self.ptr.is_null() {
            panic!("attempted to access a consumed `OsIpcSharedMemory`")
        }
        unsafe {
            slice::from_raw_parts(self.ptr, self.length)
        }
    }
}

impl OsIpcSharedMemory {
    pub fn from_byte(byte: u8, length: usize) -> OsIpcSharedMemory {
        let mut v = Arc::new(vec![byte; length]);
        OsIpcSharedMemory {
            ptr: Arc::get_mut(&mut v).unwrap().as_mut_ptr(),
            length: length,
            data: v
        }
    }

    pub fn from_bytes(bytes: &[u8]) -> OsIpcSharedMemory {
        let mut v = Arc::new(bytes.to_vec());
        OsIpcSharedMemory {
            ptr: Arc::get_mut(&mut v).unwrap().as_mut_ptr(),
            length: v.len(),
            data: v
        }
    }
}

#[derive(Debug, PartialEq)]
pub enum ChannelError {
    ChannelClosedError,
    BrokenPipeError,
    ChannelEmpty,
    UnknownError,
}

impl ChannelError {
    #[allow(dead_code)]
    pub fn channel_is_closed(&self) -> bool {
        *self == ChannelError::ChannelClosedError
    }
}

impl fmt::Display for ChannelError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            ChannelError::ChannelClosedError => write!(fmt, "channel closed"),
            ChannelError::BrokenPipeError => write!(fmt, "broken pipe"),
            ChannelError::ChannelEmpty => write!(fmt, "channel empty"),
            ChannelError::UnknownError => write!(fmt, "unknown error"),
        }
    }
}

impl StdError for ChannelError {
}

impl From<ChannelError> for bincode::Error {
    fn from(crossbeam_error: ChannelError) -> Self {
        io::Error::from(crossbeam_error).into()
    }
}

impl From<ChannelError> for ipc::IpcError {
    fn from(error: ChannelError) -> Self {
        match error {
            ChannelError::ChannelClosedError => ipc::IpcError::Disconnected,
            e => ipc::IpcError::Bincode(io::Error::from(e).into()),
        }
    }
}

impl From<ChannelError> for ipc::TryRecvError {
    fn from(error: ChannelError) -> Self {
        match error {
            ChannelError::ChannelClosedError => ipc::TryRecvError::IpcError(ipc::IpcError::Disconnected),
            ChannelError::ChannelEmpty => ipc::TryRecvError::Empty,
            e => ipc::TryRecvError::IpcError(ipc::IpcError::Bincode(io::Error::from(e).into())),
        }
    }
}

impl From<ChannelError> for io::Error {
    fn from(crossbeam_error: ChannelError) -> io::Error {
        match crossbeam_error {
            ChannelError::ChannelClosedError => {
                io::Error::new(io::ErrorKind::ConnectionReset, "crossbeam-channel sender closed")
            }
            ChannelError::ChannelEmpty => {
                io::Error::new(io::ErrorKind::ConnectionReset, "crossbeam-channel receiver has no received messages")
            }
            ChannelError::BrokenPipeError => {
                io::Error::new(io::ErrorKind::BrokenPipe, "crossbeam-channel receiver closed")
            }
            ChannelError::UnknownError => {
                io::Error::new(io::ErrorKind::Other, "Other crossbeam-channel error")
            }
        }
    }
}

<|endoftext|>


<commit_before>use crate::memop;
use crate::syscalls;
use core::ptr;

// _start and rust_start are the first two procedures executed when a Tock
// application starts. _start is invoked directly by the Tock kernel; it
// performs stack setup then calls rust_start. rust_start performs data
// relocation and sets up the heap before calling the rustc-generated main.
// rust_start and _start are tightly coupled.
//
// The memory layout is controlled by the linker script.
//
// When the kernel gives control to us, we get r0-r3 values that is as follows.
//
//     +--------------+ <- (r2) mem.len()
//     | Grant        |
//     +--------------+
//     | Unused       |
//  S  +--------------+ <- (r3) app_heap_break
//  R  | Heap         |         (hardcoded to mem_start + 3072 in
//  A  +--------------|          Processs::create which could be lesser than
//  M  | .bss         |          mem_start + stack + .data + .bss)
//     +--------------|
//     | .data        |
//     +--------------+
//     | Stack        |
//     +--------------+ <- (r1) mem_start
//
//     +--------------+
//     | .text        |
//  F  +--------------+
//  L  | .crt0_header |
//  A  +--------------+ <- (r0) app_start
//  S  | Protected    |
//  H  | Region       |
//     +--------------+
//
// We want to organize the memory as follows.
//
//     +--------------+ <- app_heap_break
//     | Heap         |
//     +--------------| <- heap_start
//     | .bss         |
//     +--------------|
//     | .data        |
//     +--------------+ <- stack_start (stacktop)
//     | Stack        |
//     | (grows down) |
//     +--------------+ <- mem_start
//
// app_heap_break and mem_start are given to us by the kernel. The stack size is
// determined using pointer app_start, and is used with mem_start to compute
// stack_start (stacktop). The placement of .data and .bss are given to us by
// the linker script; the heap is located between the end of .bss and
// app_heap_break. This requires that .bss is the last (highest-address) section
// placed by the linker script.

#[cfg_attr(target_arch = "riscv32", path = "start_item_riscv32.rs")]
#[cfg_attr(target_arch = "arm", path = "start_item_arm.rs")]
mod start_item;

/// The header encoded at the beginning of .text by the linker script. It is
/// accessed by rust_start() using its app_start parameter.
#[repr(C)]
struct LayoutHeader {
    got_sym_start: usize,
    got_start: usize,
    got_size: usize,
    data_sym_start: usize,
    data_start: usize,
    data_size: usize,
    bss_start: usize,
    bss_size: usize,
    reldata_start: usize,
    stack_size: usize,
}

//Procedural macro to generate a function to read APP_HEAP_SIZE
libtock_codegen::make_read_env_var!("APP_HEAP_SIZE");

/// Rust setup, called by _start. Uses the extern "C" calling convention so that
/// the assembly in _start knows how to call it (the Rust ABI is not defined).
/// Sets up the data segment (including relocations) and the heap, then calls
/// into the rustc-generated main(). This cannot use mutable global variables or
/// global references to globals until it is done setting up the data segment.
#[no_mangle]
unsafe extern "C" fn rust_start(app_start: usize, stacktop: usize, _app_heap_break: usize) -> ! {
    extern "C" {
        // This function is created internally by `rustc`. See
        // `src/lang_items.rs` for more details.
        fn main(argc: isize, argv: *const *const u8) -> isize;
    }

    // Copy .data into its final location in RAM (determined by the linker
    // script -- should be immediately above the stack).
    let layout_header: &LayoutHeader = core::mem::transmute(app_start);

    let data_flash_start_addr = app_start + layout_header.data_sym_start;

    ptr::copy_nonoverlapping(
        data_flash_start_addr as *const u8,
        stacktop as *mut u8,
        layout_header.data_size,
    );

    // Zero .bss (specified by the linker script).
    let bss_end = layout_header.bss_start + layout_header.bss_size; // 1 past the end of .bss
    for i in layout_header.bss_start..bss_end {
        core::ptr::write(i as *mut u8, 0);
    }

    // TODO: Wait for rustc to have working ROPI-RWPI relocation support, then
    // implement dynamic relocations here. At the moment, rustc does not have
    // working ROPI-RWPI support, and it is not clear what that support would
    // look like at the LLVM level. Once we know what the relocation strategy
    // looks like we can write the dynamic linker.

    // Initialize the heap. Unlike libtock-c's newlib allocator, which can use
    // `sbrk` system call to dynamically request heap memory from the kernel, we
    // need to tell `linked_list_allocator` where the heap starts and ends.
    //
    // We get this from the environment to make it easy to set per compile.
    let app_heap_size: usize = read_APP_HEAP_SIZE();

    // Make the heap start exactly at bss_end. The suggested _app_heap_break
    // is almost always going to be too big and leads to us wasting memory.
    let app_heap_start = bss_end;
    let app_heap_end = app_heap_start + app_heap_size;

    // Tell the kernel the new app heap break.
    memop::set_brk(app_heap_end as *const u8);

    #[cfg(feature = "alloc")]
    crate::alloc::HEAP.init(app_heap_start, app_heap_size);

    main(0, ptr::null());

    loop {
        syscalls::raw::yieldk();
    }
}
<commit_msg>core/entry_point: Start the heap at app_heap_break<commit_after>use crate::memop;
use crate::syscalls;
use core::ptr;

// _start and rust_start are the first two procedures executed when a Tock
// application starts. _start is invoked directly by the Tock kernel; it
// performs stack setup then calls rust_start. rust_start performs data
// relocation and sets up the heap before calling the rustc-generated main.
// rust_start and _start are tightly coupled.
//
// The memory layout is controlled by the linker script.
//
// When the kernel gives control to us, we get r0-r3 values that is as follows.
//
//     +--------------+ <- (r2) mem.len()
//     | Grant        |
//     +--------------+
//     | Unused       |
//  S  +--------------+ <- (r3) app_heap_break
//  R  | Heap         |         (hardcoded to mem_start + 3072 in
//  A  +--------------|          Processs::create which could be lesser than
//  M  | .bss         |          mem_start + stack + .data + .bss)
//     +--------------|
//     | .data        |
//     +--------------+
//     | Stack        |
//     +--------------+ <- (r1) mem_start
//
//     +--------------+
//     | .text        |
//  F  +--------------+
//  L  | .crt0_header |
//  A  +--------------+ <- (r0) app_start
//  S  | Protected    |
//  H  | Region       |
//     +--------------+
//
// We want to organize the memory as follows.
//
//     +--------------+ <- app_heap_break
//     | Heap         |
//     +--------------| <- heap_start
//     | .bss         |
//     +--------------|
//     | .data        |
//     +--------------+ <- stack_start (stacktop)
//     | Stack        |
//     | (grows down) |
//     +--------------+ <- mem_start
//
// app_heap_break and mem_start are given to us by the kernel. The stack size is
// determined using pointer app_start, and is used with mem_start to compute
// stack_start (stacktop). The placement of .data and .bss are given to us by
// the linker script; the heap is located between the end of .bss and
// app_heap_break. This requires that .bss is the last (highest-address) section
// placed by the linker script.

#[cfg_attr(target_arch = "riscv32", path = "start_item_riscv32.rs")]
#[cfg_attr(target_arch = "arm", path = "start_item_arm.rs")]
mod start_item;

/// The header encoded at the beginning of .text by the linker script. It is
/// accessed by rust_start() using its app_start parameter.
#[repr(C)]
struct LayoutHeader {
    got_sym_start: usize,
    got_start: usize,
    got_size: usize,
    data_sym_start: usize,
    data_start: usize,
    data_size: usize,
    bss_start: usize,
    bss_size: usize,
    reldata_start: usize,
    stack_size: usize,
}

//Procedural macro to generate a function to read APP_HEAP_SIZE
libtock_codegen::make_read_env_var!("APP_HEAP_SIZE");

/// Rust setup, called by _start. Uses the extern "C" calling convention so that
/// the assembly in _start knows how to call it (the Rust ABI is not defined).
/// Sets up the data segment (including relocations) and the heap, then calls
/// into the rustc-generated main(). This cannot use mutable global variables or
/// global references to globals until it is done setting up the data segment.
#[no_mangle]
unsafe extern "C" fn rust_start(app_start: usize, stacktop: usize, app_heap_start: usize) -> ! {
    extern "C" {
        // This function is created internally by `rustc`. See
        // `src/lang_items.rs` for more details.
        fn main(argc: isize, argv: *const *const u8) -> isize;
    }

    // Copy .data into its final location in RAM (determined by the linker
    // script -- should be immediately above the stack).
    let layout_header: &LayoutHeader = core::mem::transmute(app_start);

    let data_flash_start_addr = app_start + layout_header.data_sym_start;

    ptr::copy_nonoverlapping(
        data_flash_start_addr as *const u8,
        stacktop as *mut u8,
        layout_header.data_size,
    );

    // Zero .bss (specified by the linker script).
    let bss_end = layout_header.bss_start + layout_header.bss_size; // 1 past the end of .bss
    for i in layout_header.bss_start..bss_end {
        core::ptr::write(i as *mut u8, 0);
    }

    // TODO: Wait for rustc to have working ROPI-RWPI relocation support, then
    // implement dynamic relocations here. At the moment, rustc does not have
    // working ROPI-RWPI support, and it is not clear what that support would
    // look like at the LLVM level. Once we know what the relocation strategy
    // looks like we can write the dynamic linker.

    // Initialize the heap. Unlike libtock-c's newlib allocator, which can use
    // `sbrk` system call to dynamically request heap memory from the kernel, we
    // need to tell `linked_list_allocator` where the heap starts and ends.
    //
    // We get this from the environment to make it easy to set per compile.
    let app_heap_size: usize = read_APP_HEAP_SIZE();

    let app_heap_end = app_heap_start + app_heap_size;

    // Tell the kernel the new app heap break.
    memop::set_brk(app_heap_end as *const u8);

    #[cfg(feature = "alloc")]
    crate::alloc::HEAP.init(app_heap_start, app_heap_size);

    main(0, ptr::null());

    loop {
        syscalls::raw::yieldk();
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use super::match_::MATCH_CONSTANTS;
use crate::util::get_fragment_filename;
use common::{NamedItem, WithLocation};
use fnv::FnvHashMap;
use graphql_ir::{
    Argument, ConstantValue, Directive, FragmentDefinition, OperationDefinition, Program,
    Selection, Transformed, Transformer, Value,
};
use interner::{Intern, StringKey};
use lazy_static::lazy_static;
use schema::{Schema, TypeReference};

lazy_static! {
    pub static ref DATA_DRIVEN_DEPENDENCY_METADATA_KEY: StringKey =
        "__dataDrivenDependencyMetadata".intern();
}

pub fn generate_data_driven_dependency_metadata(program: &Program) -> Program {
    let mut transformer = GenerateDataDrivenDependencyMetadata::new(program);
    transformer
        .transform_program(program)
        .replace_or_else(|| program.clone())
}

struct GenerateDataDrivenDependencyMetadata<'s> {
    pub program: &'s Program,
}

impl<'s> GenerateDataDrivenDependencyMetadata<'s> {
    fn new(program: &'s Program) -> Self {
        GenerateDataDrivenDependencyMetadata { program }
    }

    fn generate_data_driven_dependency_for_selections(
        &mut self,
        type_: TypeReference,
        selections: &[Selection],
    ) -> Option<Directive> {
        let mut processing_queue: Vec<ProcessingItem<'_>> = vec![ProcessingItem {
            plural: false,
            parent_type: type_,
            selections,
        }];

        let mut module_entries: ModuleEntries = Default::default();

        while !processing_queue.is_empty() {
            if let Some(processing_item) = processing_queue.pop() {
                for selection in processing_item.selections {
                    match selection {
                        Selection::ScalarField(_) | Selection::FragmentSpread(_) => {}
                        Selection::LinkedField(linked_filed) => {
                            let field_type = &self
                                .program
                                .schema
                                .field(linked_filed.definition.item)
                                .type_;
                            processing_queue.push(ProcessingItem {
                                plural: processing_item.plural || field_type.is_list(),
                                parent_type: field_type.clone(),
                                selections: &linked_filed.selections,
                            });
                        }
                        Selection::InlineFragment(inline_fragment) => {
                            let parent_type = match inline_fragment.type_condition {
                                Some(type_) => TypeReference::Named(type_),
                                None => processing_item.parent_type.clone(),
                            };
                            let module_directive = inline_fragment
                                .directives
                                .named(MATCH_CONSTANTS.custom_module_directive_name);
                            if let Some(module_directive) = module_directive {
                                let id = get_string_literal_argument_value(
                                    &module_directive,
                                    MATCH_CONSTANTS.js_field_id_arg,
                                )
                                .expect("Expected id argument to exist on __module directive");
                                let component = get_string_literal_argument_value(
                                    &module_directive,
                                    MATCH_CONSTANTS.js_field_module_arg,
                                )
                                .expect("Expected module argument to exist on __module directive");

                                let fragment_spread = inline_fragment
                                    .selections
                                    .iter()
                                    .find(|item| matches!(item, Selection::FragmentSpread(_)));
                                // This is expected to be a fragment spread
                                let fragment_name = match fragment_spread {
                                    Some(Selection::FragmentSpread(spread)) => spread.fragment.item,
                                    _ => panic!("Expected to have a fragment spread"),
                                };

                                let type_name = self
                                    .program
                                    .schema
                                    .get_type_string(&processing_item.parent_type);
                                module_entries
                                    .entry(id)
                                    .and_modify(|module_entry| {
                                        module_entry.branches.insert(
                                            type_name.clone(),
                                            Branch {
                                                component,
                                                fragment: get_fragment_filename(fragment_name),
                                            },
                                        );
                                    })
                                    .or_insert(ModuleEntry {
                                        id,
                                        branches: {
                                            let mut map: FnvHashMap<String, Branch> =
                                                Default::default();
                                            map.insert(
                                                type_name.clone(),
                                                Branch {
                                                    component,
                                                    fragment: get_fragment_filename(fragment_name),
                                                },
                                            );
                                            map
                                        },
                                        plural: processing_item.plural,
                                    });
                            }
                            processing_queue.push(ProcessingItem {
                                plural: processing_item.plural,
                                parent_type,
                                selections: &inline_fragment.selections,
                            });
                        }
                        Selection::Condition(condition) => {
                            processing_queue.push(ProcessingItem {
                                plural: processing_item.plural,
                                parent_type: processing_item.parent_type.clone(),
                                selections: &condition.selections,
                            });
                        }
                    }
                }
            }
        }

        if !module_entries.is_empty() {
            Some(create_metadata_directive(module_entries))
        } else {
            None
        }
    }
}

#[derive(Debug, Copy, Clone)]
struct Branch {
    component: StringKey,
    fragment: StringKey,
}

type ModuleEntries = FnvHashMap<StringKey, ModuleEntry>;

#[derive(Debug)]
struct ModuleEntry {
    id: StringKey,
    branches: FnvHashMap<String, Branch>,
    plural: bool,
}

#[derive(Debug)]
struct ProcessingItem<'a> {
    plural: bool,
    parent_type: TypeReference,
    selections: &'a [Selection],
}

impl<'s> Transformer for GenerateDataDrivenDependencyMetadata<'s> {
    const NAME: &'static str = "GenerateDataDrivenDependencyMetadata";
    const VISIT_ARGUMENTS: bool = false;
    const VISIT_DIRECTIVES: bool = false;

    fn transform_operation(
        &mut self,
        operation: &OperationDefinition,
    ) -> Transformed<OperationDefinition> {
        if let Some(query_type) = self.program.schema.query_type() {
            let generated_directive = self.generate_data_driven_dependency_for_selections(
                TypeReference::Named(query_type),
                &operation.selections,
            );
            if let Some(generated_directive) = generated_directive {
                let mut next_directives: Vec<Directive> =
                    Vec::with_capacity(operation.directives.len() + 1);
                for directive in operation.directives.iter() {
                    next_directives.push(directive.clone());
                }

                next_directives.push(generated_directive);

                Transformed::Replace(OperationDefinition {
                    directives: next_directives,
                    ..operation.clone()
                })
            } else {
                Transformed::Keep
            }
        } else {
            Transformed::Keep
        }
    }

    fn transform_fragment(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> Transformed<FragmentDefinition> {
        let generated_directive = self.generate_data_driven_dependency_for_selections(
            TypeReference::Named(fragment.type_condition),
            &fragment.selections,
        );
        if let Some(generated_directive) = generated_directive {
            let mut next_directives: Vec<Directive> =
                Vec::with_capacity(fragment.directives.len() + 1);
            for directive in fragment.directives.iter() {
                next_directives.push(directive.clone());
            }
            next_directives.push(generated_directive);

            Transformed::Replace(FragmentDefinition {
                directives: next_directives,
                ..fragment.clone()
            })
        } else {
            Transformed::Keep
        }
    }
}

fn create_metadata_directive(module_entries: FnvHashMap<StringKey, ModuleEntry>) -> Directive {
    let mut arguments: Vec<Argument> = Vec::with_capacity(module_entries.len());
    for (key, module_entry) in module_entries {
        arguments.push(Argument {
            name: WithLocation::generated(key),
            value: WithLocation::generated(Value::Constant(ConstantValue::String(From::from(
                module_entry,
            )))),
        })
    }
    arguments.sort_unstable_by(|a, b| a.name.item.cmp(&b.name.item));

    Directive {
        name: WithLocation::generated(*DATA_DRIVEN_DEPENDENCY_METADATA_KEY),
        arguments,
    }
}

impl From<ModuleEntry> for StringKey {
    fn from(module_entry: ModuleEntry) -> Self {
        let mut serialized_branches: Vec<(String, String)> =
            Vec::with_capacity(module_entry.branches.len());
        for (id, branch) in module_entry.branches.iter() {
            serialized_branches.push((
                id.clone(),
                format!(
                    "\"{}\":{{\"component\":\"{}\",\"fragment\":\"{}\"}}",
                    id, branch.component, branch.fragment
                ),
            ));
        }

        serialized_branches.sort_unstable_by(|a, b| a.0.cmp(&b.0));

        format!(
            "{{\"branches\":{{{}}},\"plural\":{}}}",
            serialized_branches
                .into_iter()
                .map(|(_, value)| value)
                .collect::<Vec<String>>()
                .join(","),
            module_entry.plural
        )
        .intern()
    }
}

fn get_string_literal_argument_value(
    directive: &Directive,
    argument_name: StringKey,
) -> Option<StringKey> {
    directive
        .arguments
        .named(argument_name)
        .map(|arg| arg.value.item.expect_string_literal())
}
<commit_msg>Use while let instead of while and if let<commit_after>/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

use super::match_::MATCH_CONSTANTS;
use crate::util::get_fragment_filename;
use common::{NamedItem, WithLocation};
use fnv::FnvHashMap;
use graphql_ir::{
    Argument, ConstantValue, Directive, FragmentDefinition, OperationDefinition, Program,
    Selection, Transformed, Transformer, Value,
};
use interner::{Intern, StringKey};
use lazy_static::lazy_static;
use schema::{Schema, TypeReference};

lazy_static! {
    pub static ref DATA_DRIVEN_DEPENDENCY_METADATA_KEY: StringKey =
        "__dataDrivenDependencyMetadata".intern();
}

pub fn generate_data_driven_dependency_metadata(program: &Program) -> Program {
    let mut transformer = GenerateDataDrivenDependencyMetadata::new(program);
    transformer
        .transform_program(program)
        .replace_or_else(|| program.clone())
}

struct GenerateDataDrivenDependencyMetadata<'s> {
    pub program: &'s Program,
}

impl<'s> GenerateDataDrivenDependencyMetadata<'s> {
    fn new(program: &'s Program) -> Self {
        GenerateDataDrivenDependencyMetadata { program }
    }

    fn generate_data_driven_dependency_for_selections(
        &mut self,
        type_: TypeReference,
        selections: &[Selection],
    ) -> Option<Directive> {
        let mut processing_queue: Vec<ProcessingItem<'_>> = vec![ProcessingItem {
            plural: false,
            parent_type: type_,
            selections,
        }];

        let mut module_entries: ModuleEntries = Default::default();

        while let Some(processing_item) = processing_queue.pop() {
            for selection in processing_item.selections {
                match selection {
                    Selection::ScalarField(_) | Selection::FragmentSpread(_) => {}
                    Selection::LinkedField(linked_filed) => {
                        let field_type = &self
                            .program
                            .schema
                            .field(linked_filed.definition.item)
                            .type_;
                        processing_queue.push(ProcessingItem {
                            plural: processing_item.plural || field_type.is_list(),
                            parent_type: field_type.clone(),
                            selections: &linked_filed.selections,
                        });
                    }
                    Selection::InlineFragment(inline_fragment) => {
                        let parent_type = match inline_fragment.type_condition {
                            Some(type_) => TypeReference::Named(type_),
                            None => processing_item.parent_type.clone(),
                        };
                        let module_directive = inline_fragment
                            .directives
                            .named(MATCH_CONSTANTS.custom_module_directive_name);
                        if let Some(module_directive) = module_directive {
                            let id = get_string_literal_argument_value(
                                &module_directive,
                                MATCH_CONSTANTS.js_field_id_arg,
                            )
                            .expect("Expected id argument to exist on __module directive");
                            let component = get_string_literal_argument_value(
                                &module_directive,
                                MATCH_CONSTANTS.js_field_module_arg,
                            )
                            .expect("Expected module argument to exist on __module directive");

                            let fragment_spread = inline_fragment
                                .selections
                                .iter()
                                .find(|item| matches!(item, Selection::FragmentSpread(_)));
                            // This is expected to be a fragment spread
                            let fragment_name = match fragment_spread {
                                Some(Selection::FragmentSpread(spread)) => spread.fragment.item,
                                _ => panic!("Expected to have a fragment spread"),
                            };

                            let type_name = self
                                .program
                                .schema
                                .get_type_string(&processing_item.parent_type);
                            module_entries
                                .entry(id)
                                .and_modify(|module_entry| {
                                    module_entry.branches.insert(
                                        type_name.clone(),
                                        Branch {
                                            component,
                                            fragment: get_fragment_filename(fragment_name),
                                        },
                                    );
                                })
                                .or_insert(ModuleEntry {
                                    id,
                                    branches: {
                                        let mut map: FnvHashMap<String, Branch> =
                                            Default::default();
                                        map.insert(
                                            type_name.clone(),
                                            Branch {
                                                component,
                                                fragment: get_fragment_filename(fragment_name),
                                            },
                                        );
                                        map
                                    },
                                    plural: processing_item.plural,
                                });
                        }
                        processing_queue.push(ProcessingItem {
                            plural: processing_item.plural,
                            parent_type,
                            selections: &inline_fragment.selections,
                        });
                    }
                    Selection::Condition(condition) => {
                        processing_queue.push(ProcessingItem {
                            plural: processing_item.plural,
                            parent_type: processing_item.parent_type.clone(),
                            selections: &condition.selections,
                        });
                    }
                }
            }
        }

        if !module_entries.is_empty() {
            Some(create_metadata_directive(module_entries))
        } else {
            None
        }
    }
}

#[derive(Debug, Copy, Clone)]
struct Branch {
    component: StringKey,
    fragment: StringKey,
}

type ModuleEntries = FnvHashMap<StringKey, ModuleEntry>;

#[derive(Debug)]
struct ModuleEntry {
    id: StringKey,
    branches: FnvHashMap<String, Branch>,
    plural: bool,
}

#[derive(Debug)]
struct ProcessingItem<'a> {
    plural: bool,
    parent_type: TypeReference,
    selections: &'a [Selection],
}

impl<'s> Transformer for GenerateDataDrivenDependencyMetadata<'s> {
    const NAME: &'static str = "GenerateDataDrivenDependencyMetadata";
    const VISIT_ARGUMENTS: bool = false;
    const VISIT_DIRECTIVES: bool = false;

    fn transform_operation(
        &mut self,
        operation: &OperationDefinition,
    ) -> Transformed<OperationDefinition> {
        if let Some(query_type) = self.program.schema.query_type() {
            let generated_directive = self.generate_data_driven_dependency_for_selections(
                TypeReference::Named(query_type),
                &operation.selections,
            );
            if let Some(generated_directive) = generated_directive {
                let mut next_directives: Vec<Directive> =
                    Vec::with_capacity(operation.directives.len() + 1);
                for directive in operation.directives.iter() {
                    next_directives.push(directive.clone());
                }

                next_directives.push(generated_directive);

                Transformed::Replace(OperationDefinition {
                    directives: next_directives,
                    ..operation.clone()
                })
            } else {
                Transformed::Keep
            }
        } else {
            Transformed::Keep
        }
    }

    fn transform_fragment(
        &mut self,
        fragment: &FragmentDefinition,
    ) -> Transformed<FragmentDefinition> {
        let generated_directive = self.generate_data_driven_dependency_for_selections(
            TypeReference::Named(fragment.type_condition),
            &fragment.selections,
        );
        if let Some(generated_directive) = generated_directive {
            let mut next_directives: Vec<Directive> =
                Vec::with_capacity(fragment.directives.len() + 1);
            for directive in fragment.directives.iter() {
                next_directives.push(directive.clone());
            }
            next_directives.push(generated_directive);

            Transformed::Replace(FragmentDefinition {
                directives: next_directives,
                ..fragment.clone()
            })
        } else {
            Transformed::Keep
        }
    }
}

fn create_metadata_directive(module_entries: FnvHashMap<StringKey, ModuleEntry>) -> Directive {
    let mut arguments: Vec<Argument> = Vec::with_capacity(module_entries.len());
    for (key, module_entry) in module_entries {
        arguments.push(Argument {
            name: WithLocation::generated(key),
            value: WithLocation::generated(Value::Constant(ConstantValue::String(From::from(
                module_entry,
            )))),
        })
    }
    arguments.sort_unstable_by(|a, b| a.name.item.cmp(&b.name.item));

    Directive {
        name: WithLocation::generated(*DATA_DRIVEN_DEPENDENCY_METADATA_KEY),
        arguments,
    }
}

impl From<ModuleEntry> for StringKey {
    fn from(module_entry: ModuleEntry) -> Self {
        let mut serialized_branches: Vec<(String, String)> =
            Vec::with_capacity(module_entry.branches.len());
        for (id, branch) in module_entry.branches.iter() {
            serialized_branches.push((
                id.clone(),
                format!(
                    "\"{}\":{{\"component\":\"{}\",\"fragment\":\"{}\"}}",
                    id, branch.component, branch.fragment
                ),
            ));
        }

        serialized_branches.sort_unstable_by(|a, b| a.0.cmp(&b.0));

        format!(
            "{{\"branches\":{{{}}},\"plural\":{}}}",
            serialized_branches
                .into_iter()
                .map(|(_, value)| value)
                .collect::<Vec<String>>()
                .join(","),
            module_entry.plural
        )
        .intern()
    }
}

fn get_string_literal_argument_value(
    directive: &Directive,
    argument_name: StringKey,
) -> Option<StringKey> {
    directive
        .arguments
        .named(argument_name)
        .map(|arg| arg.value.item.expect_string_literal())
}
<|endoftext|>