<commit_before>use std::ffi::OsStr;
use std::fs;
use std::path;

use cobalt_config::DateTime;
use failure::ResultExt;
use liquid;
use serde_json;
use serde_yaml;
use toml;

use crate::error::*;

use super::files;

#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields, default)]
pub struct Site {
    pub title: Option<kstring::KString>,
    pub description: Option<kstring::KString>,
    pub base_url: Option<kstring::KString>,
    pub sitemap: Option<cobalt_config::RelPath>,
    pub data: Option<liquid::Object>,
    pub data_dir: &'static str,
    /// The time at which the `cobalt` binary built the site
    pub time: DateTime,
}

impl Site {
    pub fn from_config(config: cobalt_config::Site) -> Self {
        let cobalt_config::Site {
            title,
            description,
            base_url,
            sitemap,
            data,
            data_dir,
        } = config;

        let base_url = base_url.map(|mut l| {
            if l.ends_with('/') {
                let mut other = String::from(l.as_str());
                other.pop();
                l = kstring::KString::from_string(other);
            }
            l
        });

        Self {
            title,
            description,
            base_url,
            sitemap,
            data,
            data_dir,
            time: DateTime::now()
        }
    }

    pub fn load(&self, source: &std::path::Path) -> Result<liquid::Object> {
        let mut attributes = liquid::Object::new();
        if let Some(title) = self.title.as_ref() {
            attributes.insert(
                "title".into(),
                liquid::model::Value::scalar(kstring::KString::from_ref(title)),
            );
        }
        if let Some(description) = self.description.as_ref() {
            attributes.insert(
                "description".into(),
                liquid::model::Value::scalar(kstring::KString::from_ref(description)),
            );
        }
        if let Some(base_url) = self.base_url.as_ref() {
            attributes.insert(
                "base_url".into(),
                liquid::model::Value::scalar(kstring::KString::from_ref(base_url)),
            );
        }
        attributes.insert(
            "time".into(),
            liquid::model::Value::scalar(self.time),
        );

        let mut data = self.data.clone().unwrap_or_default();
        let data_path = source.join(&self.data_dir);
        insert_data_dir(&mut data, &data_path)?;
        if !data.is_empty() {
            attributes.insert("data".into(), liquid::model::Value::Object(data));
        }

        Ok(attributes)
    }
}

fn deep_insert(
    data_map: &mut liquid::Object,
    file_path: &path::Path,
    target_key: String,
    data: liquid::model::Value,
) -> Result<()> {
    // now find the nested map it is supposed to be in
    let target_map = if let Some(path) = file_path.parent() {
        let mut map = data_map;
        for part in path.iter() {
            let key = part.to_str().ok_or_else(|| {
                failure::format_err!(
                    "The data from {:?} can't be loaded as it contains non utf-8 characters",
                    path
                )
            })?;
            let cur_map = map;
            let key = kstring::KString::from_ref(key);
            map = cur_map
                .entry(key)
                .or_insert_with(|| liquid::model::Value::Object(liquid::Object::new()))
                .as_object_mut()
                .ok_or_else(|| {
                    failure::format_err!(
                        "Aborting: Duplicate in data tree. Would overwrite {:?} ",
                        path
                    )
                })?;
        }
        map
    } else {
        data_map
    };

    match target_map.insert(target_key.into(), data) {
        None => Ok(()),
        _ => Err(failure::format_err!(
            "The data from {:?} can't be loaded: the key already exists",
            file_path
        )),
    }
}

fn load_data(data_path: &path::Path) -> Result<liquid::model::Value> {
    let ext = data_path.extension().unwrap_or_else(|| OsStr::new(""));

    let data: liquid::model::Value;

    if ext == OsStr::new("yml") || ext == OsStr::new("yaml") {
        let reader = fs::File::open(data_path)?;
        data = serde_yaml::from_reader(reader)?;
    } else if ext == OsStr::new("json") {
        let reader = fs::File::open(data_path)?;
        data = serde_json::from_reader(reader)?;
    } else if ext == OsStr::new("toml") {
        let text = files::read_file(data_path)?;
        data = toml::from_str(&text)?;
    } else {
        failure::bail!(
            "Failed to load of data {:?}: unknown file type '{:?}'.\n\
             Supported data files extensions are: yml, yaml, json and toml.",
            data_path,
            ext
        );
    }

    Ok(data)
}

fn insert_data_dir(data: &mut liquid::Object, data_root: &path::Path) -> Result<()> {
    debug!("Loading data from {:?}", data_root);

    let data_files_builder = files::FilesBuilder::new(data_root)?;
    let data_files = data_files_builder.build()?;
    for full_path in data_files.files() {
        let rel_path = full_path
            .strip_prefix(data_root)
            .expect("file was found under the root");

        let file_stem = full_path
            .file_stem()
            .expect("Files will always return with a stem");
        let file_stem = String::from(file_stem.to_str().unwrap());
        let data_fragment = load_data(&full_path)
            .with_context(|_| format!("Loading data from {:?} failed", full_path))?;

        deep_insert(data, rel_path, file_stem, data_fragment)
            .with_context(|_| format!("Merging data into {:?} failed", rel_path))?;
    }

    Ok(())
}
<commit_msg>rustfmt<commit_after>use std::ffi::OsStr;
use std::fs;
use std::path;

use cobalt_config::DateTime;
use failure::ResultExt;
use liquid;
use serde_json;
use serde_yaml;
use toml;

use crate::error::*;

use super::files;

#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
#[serde(deny_unknown_fields, default)]
pub struct Site {
    pub title: Option<kstring::KString>,
    pub description: Option<kstring::KString>,
    pub base_url: Option<kstring::KString>,
    pub sitemap: Option<cobalt_config::RelPath>,
    pub data: Option<liquid::Object>,
    pub data_dir: &'static str,
    /// The time at which the `cobalt` binary built the site
    pub time: DateTime,
}

impl Site {
    pub fn from_config(config: cobalt_config::Site) -> Self {
        let cobalt_config::Site {
            title,
            description,
            base_url,
            sitemap,
            data,
            data_dir,
        } = config;

        let base_url = base_url.map(|mut l| {
            if l.ends_with('/') {
                let mut other = String::from(l.as_str());
                other.pop();
                l = kstring::KString::from_string(other);
            }
            l
        });

        Self {
            title,
            description,
            base_url,
            sitemap,
            data,
            data_dir,
            time: DateTime::now(),
        }
    }

    pub fn load(&self, source: &std::path::Path) -> Result<liquid::Object> {
        let mut attributes = liquid::Object::new();
        if let Some(title) = self.title.as_ref() {
            attributes.insert(
                "title".into(),
                liquid::model::Value::scalar(kstring::KString::from_ref(title)),
            );
        }
        if let Some(description) = self.description.as_ref() {
            attributes.insert(
                "description".into(),
                liquid::model::Value::scalar(kstring::KString::from_ref(description)),
            );
        }
        if let Some(base_url) = self.base_url.as_ref() {
            attributes.insert(
                "base_url".into(),
                liquid::model::Value::scalar(kstring::KString::from_ref(base_url)),
            );
        }
        attributes.insert("time".into(), liquid::model::Value::scalar(self.time));

        let mut data = self.data.clone().unwrap_or_default();
        let data_path = source.join(&self.data_dir);
        insert_data_dir(&mut data, &data_path)?;
        if !data.is_empty() {
            attributes.insert("data".into(), liquid::model::Value::Object(data));
        }

        Ok(attributes)
    }
}

fn deep_insert(
    data_map: &mut liquid::Object,
    file_path: &path::Path,
    target_key: String,
    data: liquid::model::Value,
) -> Result<()> {
    // now find the nested map it is supposed to be in
    let target_map = if let Some(path) = file_path.parent() {
        let mut map = data_map;
        for part in path.iter() {
            let key = part.to_str().ok_or_else(|| {
                failure::format_err!(
                    "The data from {:?} can't be loaded as it contains non utf-8 characters",
                    path
                )
            })?;
            let cur_map = map;
            let key = kstring::KString::from_ref(key);
            map = cur_map
                .entry(key)
                .or_insert_with(|| liquid::model::Value::Object(liquid::Object::new()))
                .as_object_mut()
                .ok_or_else(|| {
                    failure::format_err!(
                        "Aborting: Duplicate in data tree. Would overwrite {:?} ",
                        path
                    )
                })?;
        }
        map
    } else {
        data_map
    };

    match target_map.insert(target_key.into(), data) {
        None => Ok(()),
        _ => Err(failure::format_err!(
            "The data from {:?} can't be loaded: the key already exists",
            file_path
        )),
    }
}

fn load_data(data_path: &path::Path) -> Result<liquid::model::Value> {
    let ext = data_path.extension().unwrap_or_else(|| OsStr::new(""));

    let data: liquid::model::Value;

    if ext == OsStr::new("yml") || ext == OsStr::new("yaml") {
        let reader = fs::File::open(data_path)?;
        data = serde_yaml::from_reader(reader)?;
    } else if ext == OsStr::new("json") {
        let reader = fs::File::open(data_path)?;
        data = serde_json::from_reader(reader)?;
    } else if ext == OsStr::new("toml") {
        let text = files::read_file(data_path)?;
        data = toml::from_str(&text)?;
    } else {
        failure::bail!(
            "Failed to load of data {:?}: unknown file type '{:?}'.\n\
             Supported data files extensions are: yml, yaml, json and toml.",
            data_path,
            ext
        );
    }

    Ok(data)
}

fn insert_data_dir(data: &mut liquid::Object, data_root: &path::Path) -> Result<()> {
    debug!("Loading data from {:?}", data_root);

    let data_files_builder = files::FilesBuilder::new(data_root)?;
    let data_files = data_files_builder.build()?;
    for full_path in data_files.files() {
        let rel_path = full_path
            .strip_prefix(data_root)
            .expect("file was found under the root");

        let file_stem = full_path
            .file_stem()
            .expect("Files will always return with a stem");
        let file_stem = String::from(file_stem.to_str().unwrap());
        let data_fragment = load_data(&full_path)
            .with_context(|_| format!("Loading data from {:?} failed", full_path))?;

        deep_insert(data, rel_path, file_stem, data_fragment)
            .with_context(|_| format!("Merging data into {:?} failed", rel_path))?;
    }

    Ok(())
}
<|endoftext|>


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

use serde_json::Value;

use std::net::SocketAddr;

use router::Router;
use iron::prelude::*;

use params::{Params, Value as ParamsValue};
use node::{NodeChannel, ApiSender};
use node::state::TxPool;
use blockchain::{Service, Blockchain, SharedNodeState};
use crypto::{Hash, HexValue};
use explorer::{TxInfo, BlockchainExplorer};
use api::{Api, ApiError};
use messages::{TEST_NETWORK_ID, PROTOCOL_MAJOR_VERSION};

#[derive(Serialize, Clone, Debug)]
struct ServiceInfo {
    name: String,
    id: u16,
}

/// `DTO` is used to transfer information about node.
#[derive(Serialize, Clone, Debug)]
pub struct NodeInfo {
    network_id: u8,
    protocol_version: u8,
    services: Vec<ServiceInfo>,
}

impl NodeInfo {
    /// Creates new `NodeInfo`, from services list.
    pub fn new<'a, I>(services: I) -> NodeInfo
    where
        I: IntoIterator<Item = &'a Box<Service>>,
    {
        NodeInfo {
            network_id: TEST_NETWORK_ID,
            protocol_version: PROTOCOL_MAJOR_VERSION,
            services: services
                .into_iter()
                .map(|s| {
                    ServiceInfo {
                        name: s.service_name().to_owned(),
                        id: s.service_id(),
                    }
                })
                .collect(),
        }
    }
}

#[derive(Serialize, Debug)]
struct PeerInfo {
    addr: SocketAddr,
    delay: u64,
}

#[derive(Serialize)]
struct PeersInfo {
    incoming_connections: Vec<SocketAddr>,
    outgoing_connections: Vec<SocketAddr>,
    reconnects: Vec<PeerInfo>,
}

#[derive(Serialize)]
struct MemPoolTxInfo {
    content: Value,
}

#[derive(Serialize)]
#[serde(tag = "type")]
enum MemPoolResult {
    Unknown,
    MemPool(MemPoolTxInfo),
    Commited(TxInfo),
}

#[derive(Serialize)]
struct MemPoolInfo {
    size: usize,
}

#[derive(Clone, Debug)]
pub struct SystemApi {
    blockchain: Blockchain,
    pool: TxPool,
    info: NodeInfo,
    shared_api_state: SharedNodeState,
    node_channel: ApiSender<NodeChannel>,
}

impl SystemApi {
    /// Creates new `SystemApi`, from `ApiContext`
    pub fn new(
        info: NodeInfo,
        blockchain: Blockchain,
        pool: TxPool,
        shared_api_state: SharedNodeState,
        node_channel: ApiSender<NodeChannel>,
    ) -> SystemApi {
        SystemApi {
            info,
            blockchain,
            node_channel,
            pool,
            shared_api_state,
        }
    }

    fn get_mempool_info(&self) -> MemPoolInfo {
        MemPoolInfo { size: self.pool.read().expect("Expected read lock").len() }
    }

    fn get_peers_info(&self) -> PeersInfo {
        PeersInfo {
            incoming_connections: self.shared_api_state.incoming_connections(),
            outgoing_connections: self.shared_api_state.outgoing_connections(),
            reconnects: self.shared_api_state
                .reconnects_timeout()
                .into_iter()
                .map(|(s, d)| PeerInfo { addr: s, delay: d })
                .collect(),
        }
    }

    fn get_network_info(&self) -> NodeInfo {
        self.info.clone()
    }

    fn get_mempool_tx(&self, hash_str: &str) -> Result<MemPoolResult, ApiError> {
        let hash = Hash::from_hex(hash_str)?;
        self.pool
            .read()
            .expect("Expected read lock")
            .get(&hash)
            .map_or_else(
                || {
                    let explorer = BlockchainExplorer::new(&self.blockchain);
                    Ok(explorer.tx_info(&hash)?.map_or(
                        MemPoolResult::Unknown,
                        MemPoolResult::Commited,
                    ))
                },
                |o| Ok(MemPoolResult::MemPool(MemPoolTxInfo { content: o.info() })),
            )

    }

    fn peer_add(&self, ip_str: &str) -> Result<(), ApiError> {
        let addr: SocketAddr = ip_str.parse()?;
        self.node_channel.peer_add(addr)?;
        Ok(())
    }
}

impl Api for SystemApi {
    fn wire(&self, router: &mut Router) {
        let _self = self.clone();
        let mempool = move |req: &mut Request| -> IronResult<Response> {
            let params = req.extensions.get::<Router>().unwrap();
            match params.find("hash") {
                Some(hash_str) => {
                    let info = _self.get_mempool_tx(hash_str)?;
                    _self.ok_response(&::serde_json::to_value(info).unwrap())
                }
                None => {
                    Err(ApiError::IncorrectRequest(
                        "Required parameter of transaction 'hash' is missing".into(),
                    ))?
                }
            }
        };

        let _self = self.clone();
        let mempool_info = move |_: &mut Request| -> IronResult<Response> {
            let info = _self.get_mempool_info();
            _self.ok_response(&::serde_json::to_value(info).unwrap())
        };

        let _self = self.clone();
        let peer_add = move |req: &mut Request| -> IronResult<Response> {
            let map = req.get_ref::<Params>().unwrap();
            match map.find(&["ip"]) {
                Some(&ParamsValue::String(ref ip_str)) => {
                    _self.peer_add(ip_str)?;
                    _self.ok_response(&::serde_json::to_value("Ok").unwrap())
                }
                _ => {
                    Err(ApiError::IncorrectRequest(
                        "Required parameter of peer 'ip' is missing".into(),
                    ))?
                }
            }
        };

        let _self = self.clone();
        let peers_info = move |_: &mut Request| -> IronResult<Response> {
            let info = _self.get_peers_info();
            _self.ok_response(&::serde_json::to_value(info).unwrap())
        };

        let _self = self.clone();
        let network = move |_: &mut Request| -> IronResult<Response> {
            let info = _self.get_network_info();
            _self.ok_response(&::serde_json::to_value(info).unwrap())
        };

        router.get("/v1/mempool", mempool_info, "mempool");
        router.get("/v1/mempool/:hash", mempool, "mempool_tx");
        router.get("/v1/peers", peers_info, "peers_info");
        router.post("/v1/peeradd", peer_add, "peer_add");
        router.get("/v1/network", network, "network_info");
    }
}
<commit_msg>Fix typo in SystemApi<commit_after>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use serde_json::Value;

use std::net::SocketAddr;

use router::Router;
use iron::prelude::*;

use params::{Params, Value as ParamsValue};
use node::{NodeChannel, ApiSender};
use node::state::TxPool;
use blockchain::{Service, Blockchain, SharedNodeState};
use crypto::{Hash, HexValue};
use explorer::{TxInfo, BlockchainExplorer};
use api::{Api, ApiError};
use messages::{TEST_NETWORK_ID, PROTOCOL_MAJOR_VERSION};

#[derive(Serialize, Clone, Debug)]
struct ServiceInfo {
    name: String,
    id: u16,
}

/// `DTO` is used to transfer information about node.
#[derive(Serialize, Clone, Debug)]
pub struct NodeInfo {
    network_id: u8,
    protocol_version: u8,
    services: Vec<ServiceInfo>,
}

impl NodeInfo {
    /// Creates new `NodeInfo`, from services list.
    pub fn new<'a, I>(services: I) -> NodeInfo
    where
        I: IntoIterator<Item = &'a Box<Service>>,
    {
        NodeInfo {
            network_id: TEST_NETWORK_ID,
            protocol_version: PROTOCOL_MAJOR_VERSION,
            services: services
                .into_iter()
                .map(|s| {
                    ServiceInfo {
                        name: s.service_name().to_owned(),
                        id: s.service_id(),
                    }
                })
                .collect(),
        }
    }
}

#[derive(Serialize, Debug)]
struct PeerInfo {
    addr: SocketAddr,
    delay: u64,
}

#[derive(Serialize)]
struct PeersInfo {
    incoming_connections: Vec<SocketAddr>,
    outgoing_connections: Vec<SocketAddr>,
    reconnects: Vec<PeerInfo>,
}

#[derive(Serialize)]
struct MemPoolTxInfo {
    content: Value,
}

#[derive(Serialize)]
#[serde(tag = "type")]
enum MemPoolResult {
    Unknown,
    MemPool(MemPoolTxInfo),
    Committed(TxInfo),
}

#[derive(Serialize)]
struct MemPoolInfo {
    size: usize,
}

#[derive(Clone, Debug)]
pub struct SystemApi {
    blockchain: Blockchain,
    pool: TxPool,
    info: NodeInfo,
    shared_api_state: SharedNodeState,
    node_channel: ApiSender<NodeChannel>,
}

impl SystemApi {
    /// Creates new `SystemApi`, from `ApiContext`
    pub fn new(
        info: NodeInfo,
        blockchain: Blockchain,
        pool: TxPool,
        shared_api_state: SharedNodeState,
        node_channel: ApiSender<NodeChannel>,
    ) -> SystemApi {
        SystemApi {
            info,
            blockchain,
            node_channel,
            pool,
            shared_api_state,
        }
    }

    fn get_mempool_info(&self) -> MemPoolInfo {
        MemPoolInfo { size: self.pool.read().expect("Expected read lock").len() }
    }

    fn get_peers_info(&self) -> PeersInfo {
        PeersInfo {
            incoming_connections: self.shared_api_state.incoming_connections(),
            outgoing_connections: self.shared_api_state.outgoing_connections(),
            reconnects: self.shared_api_state
                .reconnects_timeout()
                .into_iter()
                .map(|(s, d)| PeerInfo { addr: s, delay: d })
                .collect(),
        }
    }

    fn get_network_info(&self) -> NodeInfo {
        self.info.clone()
    }

    fn get_mempool_tx(&self, hash_str: &str) -> Result<MemPoolResult, ApiError> {
        let hash = Hash::from_hex(hash_str)?;
        self.pool
            .read()
            .expect("Expected read lock")
            .get(&hash)
            .map_or_else(
                || {
                    let explorer = BlockchainExplorer::new(&self.blockchain);
                    Ok(explorer.tx_info(&hash)?.map_or(
                        MemPoolResult::Unknown,
                        MemPoolResult::Committed,
                    ))
                },
                |o| Ok(MemPoolResult::MemPool(MemPoolTxInfo { content: o.info() })),
            )

    }

    fn peer_add(&self, ip_str: &str) -> Result<(), ApiError> {
        let addr: SocketAddr = ip_str.parse()?;
        self.node_channel.peer_add(addr)?;
        Ok(())
    }
}

impl Api for SystemApi {
    fn wire(&self, router: &mut Router) {
        let _self = self.clone();
        let mempool = move |req: &mut Request| -> IronResult<Response> {
            let params = req.extensions.get::<Router>().unwrap();
            match params.find("hash") {
                Some(hash_str) => {
                    let info = _self.get_mempool_tx(hash_str)?;
                    _self.ok_response(&::serde_json::to_value(info).unwrap())
                }
                None => {
                    Err(ApiError::IncorrectRequest(
                        "Required parameter of transaction 'hash' is missing".into(),
                    ))?
                }
            }
        };

        let _self = self.clone();
        let mempool_info = move |_: &mut Request| -> IronResult<Response> {
            let info = _self.get_mempool_info();
            _self.ok_response(&::serde_json::to_value(info).unwrap())
        };

        let _self = self.clone();
        let peer_add = move |req: &mut Request| -> IronResult<Response> {
            let map = req.get_ref::<Params>().unwrap();
            match map.find(&["ip"]) {
                Some(&ParamsValue::String(ref ip_str)) => {
                    _self.peer_add(ip_str)?;
                    _self.ok_response(&::serde_json::to_value("Ok").unwrap())
                }
                _ => {
                    Err(ApiError::IncorrectRequest(
                        "Required parameter of peer 'ip' is missing".into(),
                    ))?
                }
            }
        };

        let _self = self.clone();
        let peers_info = move |_: &mut Request| -> IronResult<Response> {
            let info = _self.get_peers_info();
            _self.ok_response(&::serde_json::to_value(info).unwrap())
        };

        let _self = self.clone();
        let network = move |_: &mut Request| -> IronResult<Response> {
            let info = _self.get_network_info();
            _self.ok_response(&::serde_json::to_value(info).unwrap())
        };

        router.get("/v1/mempool", mempool_info, "mempool");
        router.get("/v1/mempool/:hash", mempool, "mempool_tx");
        router.get("/v1/peers", peers_info, "peers_info");
        router.post("/v1/peeradd", peer_add, "peer_add");
        router.get("/v1/network", network, "network_info");
    }
}
<|endoftext|>


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

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(unix)]
mod imp {
    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::{Ok, Err};

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    ///
    /// This does not block.
    #[cfg(unix)]
    pub struct OsRng {
        inner: ReaderRng<File>
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: reader_rng })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            self.inner.next_u32()
        }
        fn next_u64(&mut self) -> u64 {
            self.inner.next_u64()
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            self.inner.fill_bytes(v)
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use core_collections::Collection;
    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::{Ok, Err};
    use rt::stack;
    use self::libc::{c_ulong, DWORD, BYTE, LPCSTR, BOOL};
    use slice::MutableVector;

    type HCRYPTPROV = c_ulong;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;
    static NTE_BAD_SIGNATURE: DWORD = 0x80090006;

    #[allow(non_snake_case_functions)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let mut ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            // FIXME #13259:
            // It turns out that if we can't acquire a context with the
            // NTE_BAD_SIGNATURE error code, the documentation states:
            //
            //     The provider DLL signature could not be verified. Either the
            //     DLL or the digital signature has been tampered with.
            //
            // Sounds fishy, no? As it turns out, our signature can be bad
            // because our Thread Information Block (TIB) isn't exactly what it
            // expects. As to why, I have no idea. The only data we store in the
            // TIB is the stack limit for each thread, but apparently that's
            // enough to make the signature valid.
            //
            // Furthermore, this error only happens the *first* time we call
            // CryptAcquireContext, so we don't have to worry about future
            // calls.
            //
            // Anyway, the fix employed here is that if we see this error, we
            // pray that we're not close to the end of the stack, temporarily
            // set the stack limit to 0 (what the TIB originally was), acquire a
            // context, and then reset the stack limit.
            //
            // Again, I'm not sure why this is the fix, nor why we're getting
            // this error. All I can say is that this seems to allow libnative
            // to progress where it otherwise would be hindered. Who knew?
            if ret == 0 && os::errno() as DWORD == NTE_BAD_SIGNATURE {
                unsafe {
                    let limit = stack::get_sp_limit();
                    stack::record_sp_limit(0);
                    ret = CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                               PROV_RSA_FULL,
                                               CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
                    stack::record_sp_limit(limit);
                }
            }

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                fail!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                fail!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

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

    use super::OsRng;
    use rand::Rng;
    use task;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8, .. 1000];
        r.fill_bytes(v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in range(0, 20) {
            let (tx, rx) = channel();
            txs.push(tx);
            task::spawn(proc() {
                // wait until all the tasks are ready to go.
                rx.recv();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                task::deschedule();
                let mut v = [0u8, .. 1000];

                for _ in range(0, 100) {
                    r.next_u32();
                    task::deschedule();
                    r.next_u64();
                    task::deschedule();
                    r.fill_bytes(v);
                    task::deschedule();
                }
            })
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(())
        }
    }
}
<commit_msg>Basic iOS support<commit_after>// Copyright 2013-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.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(unix, not(target_os = "ios"))]
mod imp {
    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::{Ok, Err};

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    #[cfg(unix)]
    pub struct OsRng {
        inner: ReaderRng<File>
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: reader_rng })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            self.inner.next_u32()
        }
        fn next_u64(&mut self) -> u64 {
            self.inner.next_u64()
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            self.inner.fill_bytes(v)
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    extern crate libc;

    use collections::Collection;
    use io::{IoResult};
    use kinds::marker;
    use mem;
    use os;
    use rand::Rng;
    use result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::MutableVector;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    pub struct OsRng {
        marker: marker::NoCopy
    }

    struct SecRandom;

    static kSecRandomDefault: *SecRandom = 0 as *SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *SecRandom, count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            Ok(OsRng {marker: marker::NoCopy} )
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                fail!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use core_collections::Collection;
    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::{Ok, Err};
    use rt::stack;
    use self::libc::{c_ulong, DWORD, BYTE, LPCSTR, BOOL};
    use slice::MutableVector;

    type HCRYPTPROV = c_ulong;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;
    static NTE_BAD_SIGNATURE: DWORD = 0x80090006;

    #[allow(non_snake_case_functions)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let mut ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            // FIXME #13259:
            // It turns out that if we can't acquire a context with the
            // NTE_BAD_SIGNATURE error code, the documentation states:
            //
            //     The provider DLL signature could not be verified. Either the
            //     DLL or the digital signature has been tampered with.
            //
            // Sounds fishy, no? As it turns out, our signature can be bad
            // because our Thread Information Block (TIB) isn't exactly what it
            // expects. As to why, I have no idea. The only data we store in the
            // TIB is the stack limit for each thread, but apparently that's
            // enough to make the signature valid.
            //
            // Furthermore, this error only happens the *first* time we call
            // CryptAcquireContext, so we don't have to worry about future
            // calls.
            //
            // Anyway, the fix employed here is that if we see this error, we
            // pray that we're not close to the end of the stack, temporarily
            // set the stack limit to 0 (what the TIB originally was), acquire a
            // context, and then reset the stack limit.
            //
            // Again, I'm not sure why this is the fix, nor why we're getting
            // this error. All I can say is that this seems to allow libnative
            // to progress where it otherwise would be hindered. Who knew?
            if ret == 0 && os::errno() as DWORD == NTE_BAD_SIGNATURE {
                unsafe {
                    let limit = stack::get_sp_limit();
                    stack::record_sp_limit(0);
                    ret = CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                               PROV_RSA_FULL,
                                               CRYPT_VERIFYCONTEXT | CRYPT_SILENT);
                    stack::record_sp_limit(limit);
                }
            }

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                fail!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                fail!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

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

    use super::OsRng;
    use rand::Rng;
    use task;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8, .. 1000];
        r.fill_bytes(v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in range(0, 20) {
            let (tx, rx) = channel();
            txs.push(tx);
            task::spawn(proc() {
                // wait until all the tasks are ready to go.
                rx.recv();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                task::deschedule();
                let mut v = [0u8, .. 1000];

                for _ in range(0, 100) {
                    r.next_u32();
                    task::deschedule();
                    r.next_u64();
                    task::deschedule();
                    r.fill_bytes(v);
                    task::deschedule();
                }
            })
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(())
        }
    }
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2016 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! SOS Paging
//!
//! This is in its own crate so that it can depend on both the `memory` and
//! `alloc` crates.

#![no_std]

#[macro_use] extern crate bitflags;
#[macro_use] extern crate macro_attr;
// #[macro_use] extern crate newtype_derive;
#[macro_use] extern crate log;
extern crate spin;

#[macro_use] extern crate util;
#[macro_use] extern crate memory;
extern crate alloc;

#[macro_use] pub mod macros;
pub mod arch;

use memory::{Addr, VAddr, PAddr, PAGE_SHIFT, PAGE_SIZE };
use alloc::FrameAllocator;

use elf;

use core::{ops, cmp, convert};

pub trait Mapper {
    type Flags;

    /// Translates a virtual address to the corresponding physical address.
    ///
    /// # Return
    /// + `Some(PAddr)` containing the physical address corresponding to
    ///                 `vaddr`, if it is mapped.
    /// + `None`: if the address is not mapped.
    fn translate(&self, vaddr: VAddr) -> Option<PAddr>;

    /// Translates a virtual page to a physical frame.
    fn translate_page(&self, page: VirtualPage) -> Option<PhysicalPage>;

    /// Modifies the page tables so that `page` maps to `frame`.
    ///
    /// # Arguments
    /// + `page`: the virtual `Page` to map
    /// + `frame`: the physical `Frame` that `Page` should map to.
    /// + `flags`: the page table entry flags.
    /// + `alloc`: a memory allocator
    fn map<A>( &mut self, page: VirtualPage, frame: PhysicalPage
             , flags: Self::Flags, alloc: &A )
    where A: FrameAllocator;

    /// Identity map a given `frame`.
    ///
    /// # Arguments
    /// + `frame`: the physical `Frame` to identity map
    /// + `flags`: the page table entry flags.
    /// + `alloc`: a memory allocator
    fn identity_map<A>( &mut self, frame: PhysicalPage
                      , flags: Self::Flags, alloc: &A )
    where A: FrameAllocator;

    /// Map the given `VirtualPage` to any free frame.
    ///
    /// This is like the fire and forget version of `map_to`: we just pick the
    /// first available free frame and map the page to it.
    ///
    /// # Arguments
    /// + `page`: the`VirtualPage` to map
    /// + `flags`: the page table entry flags.
    /// + `alloc`: a memory allocator
    fn map_to_any<A>( &mut self, page: VirtualPage
                    , flags: Self::Flags
                    , alloc: &A)
    where A: FrameAllocator;

    /// Unmap the given `VirtualPage`.
    ///
    /// All freed frames are returned to the given `FrameAllocator`.
    fn unmap<A>(&mut self, page: VirtualPage, alloc: &A)
    where A: FrameAllocator;

}

/// Trait for a memory allocator which can allocate memory in terms of frames.
pub trait FrameAllocator<Frame> {

    /// Allocate a new `Frame`
    //  TODO: do we want to be able to request a frame size?
    fn alloc_frame(&mut self) -> Option<Frame>;

    /// Deallocate a given `Frame`.
    fn dealloc_frame(&mut self, frame: Frame);
}
<commit_msg>[paging] fix import issues in paging module<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2016 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! SOS Paging
//!
//! This is in its own crate so that it can depend on both the `memory` and
//! `alloc` crates.

#![no_std]

#[macro_use] extern crate bitflags;
#[macro_use] extern crate macro_attr;
// #[macro_use] extern crate newtype_derive;
#[macro_use] extern crate log;
extern crate spin;

#[macro_use] extern crate util;
#[macro_use] extern crate memory;
extern crate alloc;
extern crate elf;

#[macro_use] pub mod macros;
pub mod arch;

use memory::{VirtualPage, PhysicalPage};
use alloc::FrameAllocator;

use elf;

use core::{ops, cmp, convert};

pub trait Mapper {
    type Flags;

    /// Translates a virtual address to the corresponding physical address.
    ///
    /// # Return
    /// + `Some(PAddr)` containing the physical address corresponding to
    ///                 `vaddr`, if it is mapped.
    /// + `None`: if the address is not mapped.
    fn translate(&self, vaddr: VAddr) -> Option<PAddr>;

    /// Translates a virtual page to a physical frame.
    fn translate_page(&self, page: VirtualPage) -> Option<PhysicalPage>;

    /// Modifies the page tables so that `page` maps to `frame`.
    ///
    /// # Arguments
    /// + `page`: the virtual `Page` to map
    /// + `frame`: the physical `Frame` that `Page` should map to.
    /// + `flags`: the page table entry flags.
    /// + `alloc`: a memory allocator
    fn map<A>( &mut self, page: VirtualPage, frame: PhysicalPage
             , flags: Self::Flags, alloc: &A )
    where A: FrameAllocator<PhysicalPage>;

    /// Identity map a given `frame`.
    ///
    /// # Arguments
    /// + `frame`: the physical `Frame` to identity map
    /// + `flags`: the page table entry flags.
    /// + `alloc`: a memory allocator
    fn identity_map<A>( &mut self, frame: PhysicalPage
                      , flags: Self::Flags, alloc: &A )
    where A: FrameAllocator<PhysicalPage>;

    /// Map the given `VirtualPage` to any free frame.
    ///
    /// This is like the fire and forget version of `map_to`: we just pick the
    /// first available free frame and map the page to it.
    ///
    /// # Arguments
    /// + `page`: the`VirtualPage` to map
    /// + `flags`: the page table entry flags.
    /// + `alloc`: a memory allocator
    fn map_to_any<A>( &mut self, page: VirtualPage
                    , flags: Self::Flags
                    , alloc: &A)
    where A: FrameAllocator<PhysicalPage>;

    /// Unmap the given `VirtualPage`.
    ///
    /// All freed frames are returned to the given `FrameAllocator`.
    fn unmap<A>(&mut self, page: VirtualPage, alloc: &A)
    where A: FrameAllocator<PhysicalPage>;

}

// /// Trait for a memory allocator which can allocate memory in terms of frames.
// pub trait FrameAllocator<Frame> {
//
//     /// Allocate a new `Frame`
//     //  TODO: do we want to be able to request a frame size?
//     fn alloc_frame(&mut self) -> Option<Frame>;
//
//     /// Deallocate a given `Frame`.
//     fn dealloc_frame(&mut self, frame: Frame);
// }
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::cell::RefCell;
use std::fmt;
use std::slice;
use std::str;

use if_chain::if_chain;

use crate::types::{idx_from_token, sourcemap_from_token, Token};
use crate::utils::{get_javascript_token, is_valid_javascript_identifier};

/// An iterator that iterates over tokens in reverse.
pub struct RevTokenIter<'view, 'viewbase, 'map>
where
    'viewbase: 'view,
{
    sv: &'view SourceView<'viewbase>,
    token: Option<Token<'map>>,
    source_line: Option<(&'view str, usize, usize, usize)>,
}

impl<'view, 'viewbase, 'map> Iterator for RevTokenIter<'view, 'viewbase, 'map>
where
    'viewbase: 'view,
{
    type Item = (Token<'map>, Option<&'view str>);

    fn next(&mut self) -> Option<(Token<'map>, Option<&'view str>)> {
        let token = match self.token.take() {
            None => {
                return None;
            }
            Some(token) => token,
        };

        let idx = idx_from_token(&token);
        if idx > 0 {
            let sm = sourcemap_from_token(&token);
            self.token = sm.get_token(idx - 1);
        }

        // if we are going to the same line as we did last iteration, we don't have to scan
        // up to it again.  For normal sourcemaps this should mean we only ever go to the
        // line once.
        let (source_line, last_char_offset, last_byte_offset) = if_chain! {
            if let Some((source_line, dst_line, last_char_offset,
                         last_byte_offset)) = self.source_line;

            if dst_line == token.get_dst_line() as usize;
            then {
                (source_line, last_char_offset, last_byte_offset)
            } else {
                if let Some(source_line) = self.sv.get_line(token.get_dst_line()) {
                    (source_line, !0, !0)
                } else {
                    // if we can't find the line, return am empty one
                    ("", !0, !0)
                }
            }
        };

        // find the byte offset where our token starts
        let byte_offset = if last_byte_offset == !0 {
            let mut off = 0;
            let mut idx = 0;
            for c in source_line.chars() {
                if idx >= token.get_dst_col() as usize {
                    break;
                }
                off += c.len_utf8();
                idx += c.len_utf16();
            }
            off
        } else {
            let chars_to_move = last_char_offset - token.get_dst_col() as usize;
            let mut new_offset = last_byte_offset;
            let mut idx = 0;
            for c in source_line
                .get(..last_byte_offset)
                .unwrap_or("")
                .chars()
                .rev()
            {
                if idx >= chars_to_move {
                    break;
                }
                new_offset -= c.len_utf8();
                idx += c.len_utf16();
            }
            new_offset
        };

        // remember where we were
        self.source_line = Some((
            source_line,
            token.get_dst_line() as usize,
            token.get_dst_col() as usize,
            byte_offset,
        ));

        // in case we run out of bounds here we reset the cache
        if byte_offset >= source_line.len() {
            self.source_line = None;
            Some((token, None))
        } else {
            Some((
                token,
                source_line
                    .get(byte_offset..)
                    .and_then(|s| get_javascript_token(s)),
            ))
        }
    }
}

pub struct Lines<'a> {
    sv: &'a SourceView<'a>,
    idx: u32,
}

impl<'a> Iterator for Lines<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        if let Some(line) = self.sv.get_line(self.idx) {
            self.idx += 1;
            Some(line)
        } else {
            None
        }
    }
}

/// Provides efficient access to minified sources.
///
/// This type is used to implement farily efficient source mapping
/// operations.
pub struct SourceView<'a> {
    source: Cow<'a, str>,
    processed_until: RefCell<usize>,
    lines: RefCell<Vec<(*const u8, usize)>>,
}

impl<'a> Clone for SourceView<'a> {
    fn clone(&self) -> SourceView<'a> {
        SourceView {
            source: self.source.clone(),
            processed_until: RefCell::new(0),
            lines: RefCell::new(vec![]),
        }
    }
}

impl<'a> fmt::Debug for SourceView<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("SourceView")
            .field("source", &self.source())
            .finish()
    }
}

unsafe fn make_str<'a>(tup: (*const u8, usize)) -> &'a str {
    let (data, len) = tup;
    str::from_utf8_unchecked(slice::from_raw_parts(data, len))
}

impl<'a> SourceView<'a> {
    /// Creates an optimized view of a given source.
    pub fn new(source: &'a str) -> SourceView<'a> {
        SourceView {
            source: Cow::Borrowed(source),
            processed_until: RefCell::new(0),
            lines: RefCell::new(vec![]),
        }
    }

    /// Creates an optimized view from a given source string
    pub fn from_string(source: String) -> SourceView<'static> {
        SourceView {
            source: Cow::Owned(source),
            processed_until: RefCell::new(0),
            lines: RefCell::new(vec![]),
        }
    }

    /// Returns a requested minified line.
    pub fn get_line(&self, idx: u32) -> Option<&str> {
        let idx = idx as usize;
        {
            let lines = self.lines.borrow();
            if idx < lines.len() {
                return Some(unsafe { make_str(lines[idx]) });
            }
        }

        // fetched everything
        if *self.processed_until.borrow() > self.source.len() {
            return None;
        }

        let mut processed_until = self.processed_until.borrow_mut();
        let mut lines = self.lines.borrow_mut();
        let mut done = false;

        while !done {
            let rest = &self.source.as_bytes()[*processed_until..];

            let rv = if let Some(mut idx) = rest.iter().position(|&x| x == b'\n' || x == b'\r') {
                let rv = &rest[..idx];
                if rest[idx] == b'\r' && rest.get(idx + 1) == Some(&b'\n') {
                    idx += 1;
                }
                *processed_until += idx + 1;
                rv
            } else {
                *processed_until += rest.len() + 1;
                done = true;
                rest
            };
            lines.push((rv.as_ptr(), rv.len()));
            if let Some(&line) = lines.get(idx) {
                return Some(unsafe { make_str(line) });
            }
        }

        None
    }

    /// Returns a line slice.
    ///
    /// Note that columns are indexed as JavaScript WTF-16 columns.
    pub fn get_line_slice(&self, line: u32, col: u32, span: u32) -> Option<&str> {
        self.get_line(line).and_then(|line| {
            let mut off = 0;
            let mut idx = 0;
            let mut char_iter = line.chars().peekable();

            while let Some(&c) = char_iter.peek() {
                if idx >= col as usize {
                    break;
                }
                char_iter.next();
                off += c.len_utf8();
                idx += c.len_utf16();
            }

            let mut off_end = off;
            for c in char_iter {
                if idx >= (col + span) as usize {
                    break;
                }
                off_end += c.len_utf8();
                idx += c.len_utf16();
            }

            if idx < ((col + span) as usize) {
                None
            } else {
                line.get(off..off_end)
            }
        })
    }

    /// Returns an iterator over all lines.
    pub fn lines(&'a self) -> Lines<'a> {
        Lines { sv: self, idx: 0 }
    }

    /// Returns the source.
    pub fn source(&self) -> &str {
        &self.source
    }

    fn rev_token_iter<'this, 'map>(
        &'this self,
        token: Token<'map>,
    ) -> RevTokenIter<'this, 'a, 'map> {
        RevTokenIter {
            sv: self,
            token: Some(token),
            source_line: None,
        }
    }

    /// Given a token and minified function name this attemps to resolve the
    /// name to an original function name.
    ///
    /// This invokes some guesswork and requires access to the original minified
    /// source.  This will not yield proper results for anonymous functions or
    /// functions that do not have clear function names.  (For instance it's
    /// recommended that dotted function names are not passed to this
    /// function).
    pub fn get_original_function_name<'map>(
        &self,
        token: Token<'map>,
        minified_name: &str,
    ) -> Option<&'map str> {
        if !is_valid_javascript_identifier(minified_name) {
            return None;
        }

        let mut iter = self.rev_token_iter(token).take(128).peekable();

        while let Some((token, original_identifier)) = iter.next() {
            if_chain! {
                if original_identifier == Some(minified_name);
                if let Some(item) = iter.peek();
                if item.1 == Some("function");
                then {
                    return token.get_name();
                }
            }
        }

        None
    }

    /// Returns the number of lines.
    pub fn line_count(&self) -> usize {
        self.get_line(!0);
        self.lines.borrow().len()
    }
}

#[test]
#[allow(clippy::cyclomatic_complexity)]
fn test_minified_source_view() {
    let view = SourceView::new("a\nb\nc");
    assert_eq!(view.get_line(0), Some("a"));
    assert_eq!(view.get_line(0), Some("a"));
    assert_eq!(view.get_line(2), Some("c"));
    assert_eq!(view.get_line(1), Some("b"));
    assert_eq!(view.get_line(3), None);

    assert_eq!(view.line_count(), 3);

    let view = SourceView::new("a\r\nb\r\nc");
    assert_eq!(view.get_line(0), Some("a"));
    assert_eq!(view.get_line(0), Some("a"));
    assert_eq!(view.get_line(2), Some("c"));
    assert_eq!(view.get_line(1), Some("b"));
    assert_eq!(view.get_line(3), None);

    assert_eq!(view.line_count(), 3);

    let view = SourceView::new("abc👌def\nblah");
    assert_eq!(view.get_line_slice(0, 0, 3), Some("abc"));
    assert_eq!(view.get_line_slice(0, 3, 1), Some("👌"));
    assert_eq!(view.get_line_slice(0, 3, 2), Some("👌"));
    assert_eq!(view.get_line_slice(0, 3, 3), Some("👌d"));
    assert_eq!(view.get_line_slice(0, 0, 4), Some("abc👌"));
    assert_eq!(view.get_line_slice(0, 0, 5), Some("abc👌"));
    assert_eq!(view.get_line_slice(0, 0, 6), Some("abc👌d"));
    assert_eq!(view.get_line_slice(1, 0, 4), Some("blah"));
    assert_eq!(view.get_line_slice(1, 0, 5), None);
    assert_eq!(view.get_line_slice(1, 0, 12), None);

    let view = SourceView::new("a\nb\nc\n");
    assert_eq!(view.get_line(0), Some("a"));
    assert_eq!(view.get_line(1), Some("b"));
    assert_eq!(view.get_line(2), Some("c"));
    assert_eq!(view.get_line(3), Some(""));
    assert_eq!(view.get_line(4), None);
}
<commit_msg>fix: Rename cyclomatic_complexity to cognitive_complexity.<commit_after>use std::borrow::Cow;
use std::cell::RefCell;
use std::fmt;
use std::slice;
use std::str;

use if_chain::if_chain;

use crate::types::{idx_from_token, sourcemap_from_token, Token};
use crate::utils::{get_javascript_token, is_valid_javascript_identifier};

/// An iterator that iterates over tokens in reverse.
pub struct RevTokenIter<'view, 'viewbase, 'map>
where
    'viewbase: 'view,
{
    sv: &'view SourceView<'viewbase>,
    token: Option<Token<'map>>,
    source_line: Option<(&'view str, usize, usize, usize)>,
}

impl<'view, 'viewbase, 'map> Iterator for RevTokenIter<'view, 'viewbase, 'map>
where
    'viewbase: 'view,
{
    type Item = (Token<'map>, Option<&'view str>);

    fn next(&mut self) -> Option<(Token<'map>, Option<&'view str>)> {
        let token = match self.token.take() {
            None => {
                return None;
            }
            Some(token) => token,
        };

        let idx = idx_from_token(&token);
        if idx > 0 {
            let sm = sourcemap_from_token(&token);
            self.token = sm.get_token(idx - 1);
        }

        // if we are going to the same line as we did last iteration, we don't have to scan
        // up to it again.  For normal sourcemaps this should mean we only ever go to the
        // line once.
        let (source_line, last_char_offset, last_byte_offset) = if_chain! {
            if let Some((source_line, dst_line, last_char_offset,
                         last_byte_offset)) = self.source_line;

            if dst_line == token.get_dst_line() as usize;
            then {
                (source_line, last_char_offset, last_byte_offset)
            } else {
                if let Some(source_line) = self.sv.get_line(token.get_dst_line()) {
                    (source_line, !0, !0)
                } else {
                    // if we can't find the line, return am empty one
                    ("", !0, !0)
                }
            }
        };

        // find the byte offset where our token starts
        let byte_offset = if last_byte_offset == !0 {
            let mut off = 0;
            let mut idx = 0;
            for c in source_line.chars() {
                if idx >= token.get_dst_col() as usize {
                    break;
                }
                off += c.len_utf8();
                idx += c.len_utf16();
            }
            off
        } else {
            let chars_to_move = last_char_offset - token.get_dst_col() as usize;
            let mut new_offset = last_byte_offset;
            let mut idx = 0;
            for c in source_line
                .get(..last_byte_offset)
                .unwrap_or("")
                .chars()
                .rev()
            {
                if idx >= chars_to_move {
                    break;
                }
                new_offset -= c.len_utf8();
                idx += c.len_utf16();
            }
            new_offset
        };

        // remember where we were
        self.source_line = Some((
            source_line,
            token.get_dst_line() as usize,
            token.get_dst_col() as usize,
            byte_offset,
        ));

        // in case we run out of bounds here we reset the cache
        if byte_offset >= source_line.len() {
            self.source_line = None;
            Some((token, None))
        } else {
            Some((
                token,
                source_line
                    .get(byte_offset..)
                    .and_then(|s| get_javascript_token(s)),
            ))
        }
    }
}

pub struct Lines<'a> {
    sv: &'a SourceView<'a>,
    idx: u32,
}

impl<'a> Iterator for Lines<'a> {
    type Item = &'a str;

    fn next(&mut self) -> Option<&'a str> {
        if let Some(line) = self.sv.get_line(self.idx) {
            self.idx += 1;
            Some(line)
        } else {
            None
        }
    }
}

/// Provides efficient access to minified sources.
///
/// This type is used to implement farily efficient source mapping
/// operations.
pub struct SourceView<'a> {
    source: Cow<'a, str>,
    processed_until: RefCell<usize>,
    lines: RefCell<Vec<(*const u8, usize)>>,
}

impl<'a> Clone for SourceView<'a> {
    fn clone(&self) -> SourceView<'a> {
        SourceView {
            source: self.source.clone(),
            processed_until: RefCell::new(0),
            lines: RefCell::new(vec![]),
        }
    }
}

impl<'a> fmt::Debug for SourceView<'a> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("SourceView")
            .field("source", &self.source())
            .finish()
    }
}

unsafe fn make_str<'a>(tup: (*const u8, usize)) -> &'a str {
    let (data, len) = tup;
    str::from_utf8_unchecked(slice::from_raw_parts(data, len))
}

impl<'a> SourceView<'a> {
    /// Creates an optimized view of a given source.
    pub fn new(source: &'a str) -> SourceView<'a> {
        SourceView {
            source: Cow::Borrowed(source),
            processed_until: RefCell::new(0),
            lines: RefCell::new(vec![]),
        }
    }

    /// Creates an optimized view from a given source string
    pub fn from_string(source: String) -> SourceView<'static> {
        SourceView {
            source: Cow::Owned(source),
            processed_until: RefCell::new(0),
            lines: RefCell::new(vec![]),
        }
    }

    /// Returns a requested minified line.
    pub fn get_line(&self, idx: u32) -> Option<&str> {
        let idx = idx as usize;
        {
            let lines = self.lines.borrow();
            if idx < lines.len() {
                return Some(unsafe { make_str(lines[idx]) });
            }
        }

        // fetched everything
        if *self.processed_until.borrow() > self.source.len() {
            return None;
        }

        let mut processed_until = self.processed_until.borrow_mut();
        let mut lines = self.lines.borrow_mut();
        let mut done = false;

        while !done {
            let rest = &self.source.as_bytes()[*processed_until..];

            let rv = if let Some(mut idx) = rest.iter().position(|&x| x == b'\n' || x == b'\r') {
                let rv = &rest[..idx];
                if rest[idx] == b'\r' && rest.get(idx + 1) == Some(&b'\n') {
                    idx += 1;
                }
                *processed_until += idx + 1;
                rv
            } else {
                *processed_until += rest.len() + 1;
                done = true;
                rest
            };
            lines.push((rv.as_ptr(), rv.len()));
            if let Some(&line) = lines.get(idx) {
                return Some(unsafe { make_str(line) });
            }
        }

        None
    }

    /// Returns a line slice.
    ///
    /// Note that columns are indexed as JavaScript WTF-16 columns.
    pub fn get_line_slice(&self, line: u32, col: u32, span: u32) -> Option<&str> {
        self.get_line(line).and_then(|line| {
            let mut off = 0;
            let mut idx = 0;
            let mut char_iter = line.chars().peekable();

            while let Some(&c) = char_iter.peek() {
                if idx >= col as usize {
                    break;
                }
                char_iter.next();
                off += c.len_utf8();
                idx += c.len_utf16();
            }

            let mut off_end = off;
            for c in char_iter {
                if idx >= (col + span) as usize {
                    break;
                }
                off_end += c.len_utf8();
                idx += c.len_utf16();
            }

            if idx < ((col + span) as usize) {
                None
            } else {
                line.get(off..off_end)
            }
        })
    }

    /// Returns an iterator over all lines.
    pub fn lines(&'a self) -> Lines<'a> {
        Lines { sv: self, idx: 0 }
    }

    /// Returns the source.
    pub fn source(&self) -> &str {
        &self.source
    }

    fn rev_token_iter<'this, 'map>(
        &'this self,
        token: Token<'map>,
    ) -> RevTokenIter<'this, 'a, 'map> {
        RevTokenIter {
            sv: self,
            token: Some(token),
            source_line: None,
        }
    }

    /// Given a token and minified function name this attemps to resolve the
    /// name to an original function name.
    ///
    /// This invokes some guesswork and requires access to the original minified
    /// source.  This will not yield proper results for anonymous functions or
    /// functions that do not have clear function names.  (For instance it's
    /// recommended that dotted function names are not passed to this
    /// function).
    pub fn get_original_function_name<'map>(
        &self,
        token: Token<'map>,
        minified_name: &str,
    ) -> Option<&'map str> {
        if !is_valid_javascript_identifier(minified_name) {
            return None;
        }

        let mut iter = self.rev_token_iter(token).take(128).peekable();

        while let Some((token, original_identifier)) = iter.next() {
            if_chain! {
                if original_identifier == Some(minified_name);
                if let Some(item) = iter.peek();
                if item.1 == Some("function");
                then {
                    return token.get_name();
                }
            }
        }

        None
    }

    /// Returns the number of lines.
    pub fn line_count(&self) -> usize {
        self.get_line(!0);
        self.lines.borrow().len()
    }
}

#[test]
#[allow(clippy::cognitive_complexity)]
fn test_minified_source_view() {
    let view = SourceView::new("a\nb\nc");
    assert_eq!(view.get_line(0), Some("a"));
    assert_eq!(view.get_line(0), Some("a"));
    assert_eq!(view.get_line(2), Some("c"));
    assert_eq!(view.get_line(1), Some("b"));
    assert_eq!(view.get_line(3), None);

    assert_eq!(view.line_count(), 3);

    let view = SourceView::new("a\r\nb\r\nc");
    assert_eq!(view.get_line(0), Some("a"));
    assert_eq!(view.get_line(0), Some("a"));
    assert_eq!(view.get_line(2), Some("c"));
    assert_eq!(view.get_line(1), Some("b"));
    assert_eq!(view.get_line(3), None);

    assert_eq!(view.line_count(), 3);

    let view = SourceView::new("abc👌def\nblah");
    assert_eq!(view.get_line_slice(0, 0, 3), Some("abc"));
    assert_eq!(view.get_line_slice(0, 3, 1), Some("👌"));
    assert_eq!(view.get_line_slice(0, 3, 2), Some("👌"));
    assert_eq!(view.get_line_slice(0, 3, 3), Some("👌d"));
    assert_eq!(view.get_line_slice(0, 0, 4), Some("abc👌"));
    assert_eq!(view.get_line_slice(0, 0, 5), Some("abc👌"));
    assert_eq!(view.get_line_slice(0, 0, 6), Some("abc👌d"));
    assert_eq!(view.get_line_slice(1, 0, 4), Some("blah"));
    assert_eq!(view.get_line_slice(1, 0, 5), None);
    assert_eq!(view.get_line_slice(1, 0, 12), None);

    let view = SourceView::new("a\nb\nc\n");
    assert_eq!(view.get_line(0), Some("a"));
    assert_eq!(view.get_line(1), Some("b"));
    assert_eq!(view.get_line(2), Some("c"));
    assert_eq!(view.get_line(3), Some(""));
    assert_eq!(view.get_line(4), None);
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::vec::Vec;

#[cfg(not(target_os="linux"))]
use nix::c_int;
#[cfg(not(target_os="linux"))]
use nix::sys::signal::{SaFlags, SigHandler, SigAction, sigaction};
use nix::sys::signal::{SigSet, Signal};
use nix::sys::wait::{wait, WaitStatus};
use nix::unistd::{fork, ForkResult};

use errors::*;

pub trait Supervisable {
    fn init(&self) -> Result<()>;
    fn finalize(&self) -> Result<()>;
}

pub enum Strategy {
    OneForOne,
    OneForAll,
    RestForOne,
    SimpleOneForOne,
}

#[derive(Clone)]
pub enum ChildLifetime {
    Permanent,
    Temporary,
    Transient,
}

#[derive(Clone)]
pub enum ProcessType {
    Worker,
    Supervisor,
}

#[derive(Clone)]
pub enum ShutdownType {
    BrutalKill,
    Infinity,
    Timeout(u64),
}

pub struct SupervisorFlags {
    strategy: Strategy,
    intensity: u64,
    period: u64,
}

impl SupervisorFlags {
    pub fn new(strategy: Strategy, intensity: u64, period: u64) -> Option<SupervisorFlags> {
        if period > 0 {
            Some(SupervisorFlags {
                strategy: strategy,
                intensity: intensity,
                period: period,
            })
        } else {
            None
        }
    }
}

#[derive(Clone)]
pub struct ChildSpecs {
    id: String,
    child: Rc<Supervisable>,
    restart: ChildLifetime,
    shutdown: ShutdownType,
    process_type: ProcessType,
}

impl ChildSpecs {
    pub fn new(id: &str,
               child: Rc<Supervisable>,
               restart: ChildLifetime,
               shutdown: ShutdownType,
               process_type: ProcessType)
               -> ChildSpecs {
        ChildSpecs {
            id: id.to_owned(),
            child: child,
            restart: restart,
            shutdown: shutdown,
            process_type: process_type,
        }
    }
}

pub struct Supervisor {
    flags: SupervisorFlags,
    child_specs: Vec<ChildSpecs>,
}

impl Supervisor {
    pub fn new(flags: SupervisorFlags, child_specs: &[ChildSpecs]) -> Supervisor {
        Supervisor {
            flags: flags,
            child_specs: child_specs.to_vec(),
        }
    }

    /// Runs the supervisor for the given child tasks
    pub fn run(&self) -> Result<()> {
        info!("Supervisor start");
        self.init().chain_err(|| ErrorKind::SupervisorInitError)?;
        for idx in 0..self.child_specs.len() {
            info!("Supervisor spawning child: {}", self.child_specs[idx].id);
            match fork().chain_err(|| "Could not fork process.")? {
                ForkResult::Child => {
                    self.child_specs[idx].child.init()?;
                    return Ok(());
                }
                ForkResult::Parent { child: _ } => {}
            }
        }
        self.supervise()?;
        Ok(())
    }

    fn init(&self) -> Result<()> {
        #[cfg(not(target_os="linux"))]
        {
            let mask = SigSet::empty();
            let flags = SaFlags::empty();
            let handler = SigHandler::Handler(null_handler);
            let action = SigAction::new(handler, flags, mask);
            unsafe {
                sigaction(Signal::SIGCHLD, &action)?;
            }
        }
        self.mask_all_signals()?;
        Ok(())
    }

    fn supervise(&self) -> Result<()> {
        let mut sigchld = SigSet::empty();
        sigchld.add(Signal::SIGCHLD);
        sigchld.wait()?;

        let mut active_kids = self.child_specs.len();
        while active_kids > 0 {
            info!("Supervisor waiting for child processes. {} remaining.",
                  active_kids);
            match wait()? {
                WaitStatus::Exited(pid, ret) => {
                    info!("Status: {} exited with code {}", pid, ret);
                }
                _ => {
                    warn!("Unknown action");
                }
            }
            active_kids -= 1;
        }
        Ok(())
    }

    fn mask_all_signals(&self) -> Result<()> {
        Ok(SigSet::all().thread_set_mask()?)
    }
}

#[cfg(not(target_os="linux"))]
extern "C" fn null_handler(_: c_int) -> () {}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<commit_msg>Add SIGINT to supervisor signal waitlist<commit_after>use std::rc::Rc;
use std::vec::Vec;

#[cfg(not(target_os="linux"))]
use nix::c_int;
#[cfg(not(target_os="linux"))]
use nix::sys::signal::{SaFlags, SigAction, SigHandler, sigaction};
use nix::sys::signal::{SigSet, Signal};
use nix::sys::wait::{wait, WaitStatus};
use nix::unistd::{fork, ForkResult};

use errors::*;

pub trait Supervisable {
    fn init(&self) -> Result<()>;
    fn finalize(&self) -> Result<()>;
}

pub enum Strategy {
    OneForOne,
    OneForAll,
    RestForOne,
    SimpleOneForOne,
}

#[derive(Clone)]
pub enum ChildLifetime {
    Permanent,
    Temporary,
    Transient,
}

#[derive(Clone)]
pub enum ProcessType {
    Worker,
    Supervisor,
}

#[derive(Clone)]
pub enum ShutdownType {
    BrutalKill,
    Infinity,
    Timeout(u64),
}

pub struct SupervisorFlags {
    strategy: Strategy,
    intensity: u64,
    period: u64,
}

impl SupervisorFlags {
    pub fn new(strategy: Strategy, intensity: u64, period: u64) -> Option<SupervisorFlags> {
        if period > 0 {
            Some(SupervisorFlags {
                strategy: strategy,
                intensity: intensity,
                period: period,
            })
        } else {
            None
        }
    }
}

#[derive(Clone)]
pub struct ChildSpecs {
    id: String,
    child: Rc<Supervisable>,
    restart: ChildLifetime,
    shutdown: ShutdownType,
    process_type: ProcessType,
}

impl ChildSpecs {
    pub fn new(id: &str,
               child: Rc<Supervisable>,
               restart: ChildLifetime,
               shutdown: ShutdownType,
               process_type: ProcessType)
               -> ChildSpecs {
        ChildSpecs {
            id: id.to_owned(),
            child: child,
            restart: restart,
            shutdown: shutdown,
            process_type: process_type,
        }
    }
}

pub struct Supervisor {
    flags: SupervisorFlags,
    child_specs: Vec<ChildSpecs>,
}

impl Supervisor {
    pub fn new(flags: SupervisorFlags, child_specs: &[ChildSpecs]) -> Supervisor {
        Supervisor {
            flags: flags,
            child_specs: child_specs.to_vec(),
        }
    }

    /// Runs the supervisor for the given child tasks
    pub fn run(&self) -> Result<()> {
        info!("Supervisor start");
        self.init().chain_err(|| ErrorKind::SupervisorInitError)?;
        for idx in 0..self.child_specs.len() {
            info!("Supervisor spawning child: {}", self.child_specs[idx].id);
            match fork().chain_err(|| "Could not fork process.")? {
                ForkResult::Child => {
                    self.child_specs[idx].child.init()?;
                    return Ok(());
                }
                ForkResult::Parent { child: _ } => {}
            }
        }
        self.supervise()?;
        Ok(())
    }

    fn init(&self) -> Result<()> {
        #[cfg(not(target_os="linux"))]
        {
            let mask = SigSet::empty();
            let flags = SaFlags::empty();
            let handler = SigHandler::Handler(null_handler);
            let action = SigAction::new(handler, flags, mask);
            unsafe {
                sigaction(Signal::SIGCHLD, &action)?;
            }
        }

        SigSet::all().thread_set_mask()?;
        Ok(())
    }

    fn supervise(&self) -> Result<()> {
        let mut sigs = SigSet::empty();
        sigs.add(Signal::SIGCHLD);
        sigs.add(Signal::SIGINT);

        match sigs.wait()? {
            Signal::SIGINT => {
                warn!("SIGINT!!!!!");
            }
            _ => {}
        }

        let mut active_kids = self.child_specs.len();
        while active_kids > 0 {
            info!("Supervisor waiting for child processes. {} remaining.",
                  active_kids);
            match wait()? {
                WaitStatus::Exited(pid, ret) => {
                    info!("Status: {} exited with code {}", pid, ret);
                }
                _ => {
                    warn!("Unknown action");
                }
            }
            active_kids -= 1;
        }
        Ok(())
    }
}

#[cfg(not(target_os="linux"))]
extern "C" fn null_handler(_: c_int) -> () {}

#[cfg(test)]
mod tests {
    #[test]
    fn it_works() {}
}
<|endoftext|>


<commit_before>// Copyright (c) 2020 DDN. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

use crate::generated::css_classes::C;
use seed::{prelude::*, *};

static RADIUS: f64 = 90.0;
static CIRCUMFERENCE: f64 = 2.0 * std::f64::consts::PI * RADIUS;

pub fn used_to_color(used: f64) -> &'static str {
    match (used.round() as i64) * 100 {
        75..=100 => C.text_red_500,
        50..=74 => C.text_yellow_500,
        0..=49 => C.text_green_500,
        _ => C.text_gray_500,
    }
}

pub fn view<'a, T>(x: impl Into<Option<(f64, &'a str)>>) -> Node<T> {
    match x.into() {
        Some((used, color)) => {
            let stroke_length = (1.0 - used) * CIRCUMFERENCE;

            svg![
                class![C.stroke_current, C.fill_current],
                attrs! {
                  At::ViewBox => "0 0 190 190"
                },
                g![
                    class![C._rotate_90, C.transform, C.origin_center],
                    circle![
                        class![
                            C.stroke_5,
                            C.text_gray_200,
                            C.transition_stroke_dashoffset,
                            C.duration_500,
                            C.ease_linear
                        ],
                        attrs! {
                          At::R => "90",
                          At::Cx => "95",
                          At::Cy => "95",
                          At::Fill => "transparent",
                        }
                    ],
                    circle![
                        class![
                            C.stroke_5,
                            color,
                            C.transition_stroke_dashoffset,
                            C.duration_500,
                            C.ease_linear
                        ],
                        attrs! {
                          At::R => "90",
                          At::Cx => "95",
                          At::Cy => "95",
                          At::Fill => "transparent",
                          At::StrokeDashArray => CIRCUMFERENCE,
                          At::StrokeDashOffset => stroke_length
                        }
                    ],
                    text![
                        class![
                            C.rotate_90
                            C.origin_center,
                            C.stroke_2,
                            C.text_4xl,
                            C.transform,
                            color,
                        ],
                        attrs! {
                          At::X => "50%",
                          At::Y => "50%",
                          At::DominantBaseline => "central",
                          At::TextAnchor => "middle"
                        },
                        tspan![format!("{}", (100.0 * used) as u16)],
                        tspan![class![C.text_gray_400], "%"]
                    ]
                ],
            ]
        }
        None => div!["Loading"],
    }
}
<commit_msg>Fix NaN case in progress circle (#1658)<commit_after>// Copyright (c) 2020 DDN. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

use crate::generated::css_classes::C;
use seed::{prelude::*, *};

static RADIUS: f64 = 90.0;
static CIRCUMFERENCE: f64 = 2.0 * std::f64::consts::PI * RADIUS;

pub fn used_to_color(used: f64) -> &'static str {
    if used.is_nan() {
        C.text_gray_500
    } else {
        match (used.round() as u64) * 100 {
            75..=100 => C.text_red_500,
            50..=74 => C.text_yellow_500,
            0..=49 => C.text_green_500,
            _ => C.text_gray_500,
        }
    }
}

pub fn view<'a, T>(x: impl Into<Option<(f64, &'a str)>>) -> Node<T> {
    match x.into() {
        Some((used, color)) => {
            let stroke_length = (1.0 - used) * CIRCUMFERENCE;

            svg![
                class![C.stroke_current, C.fill_current],
                attrs! {
                  At::ViewBox => "0 0 190 190"
                },
                g![
                    class![C._rotate_90, C.transform, C.origin_center],
                    circle![
                        class![
                            C.stroke_5,
                            C.text_gray_200,
                            C.transition_stroke_dashoffset,
                            C.duration_500,
                            C.ease_linear
                        ],
                        attrs! {
                          At::R => "90",
                          At::Cx => "95",
                          At::Cy => "95",
                          At::Fill => "transparent",
                        }
                    ],
                    circle![
                        class![
                            C.stroke_5,
                            color,
                            C.transition_stroke_dashoffset,
                            C.duration_500,
                            C.ease_linear
                        ],
                        attrs! {
                          At::R => "90",
                          At::Cx => "95",
                          At::Cy => "95",
                          At::Fill => "transparent",
                          At::StrokeDashArray => CIRCUMFERENCE,
                          At::StrokeDashOffset => stroke_length
                        }
                    ],
                    text![
                        class![
                            C.rotate_90
                            C.origin_center,
                            C.stroke_2,
                            C.text_4xl,
                            C.transform,
                            color,
                        ],
                        attrs! {
                          At::X => "50%",
                          At::Y => "50%",
                          At::DominantBaseline => "central",
                          At::TextAnchor => "middle"
                        },
                        tspan![format!("{}", (100.0 * used) as u16)],
                        tspan![class![C.text_gray_400], "%"]
                    ]
                ],
            ]
        }
        None => div!["Loading"],
    }
}
<|endoftext|>