<commit_before>//! # No-op OpenTelemetry Trace Implementation
//!
//! This implementation is returned as the global tracer if no `Tracer`
//! has been set. It is also useful for testing purposes as it is intended
//! to have minimal resource utilization and runtime impact.
use crate::{
    sdk::export::trace::{ExportResult, SpanData, SpanExporter},
    trace,
    trace::{TraceContextExt, TraceState},
    Context, KeyValue,
};
use async_trait::async_trait;
use std::time::SystemTime;

/// A no-op instance of a `TracerProvider`.
#[derive(Debug, Default)]
pub struct NoopTracerProvider {
    _private: (),
}

impl NoopTracerProvider {
    /// Create a new no-op tracer provider
    pub fn new() -> Self {
        NoopTracerProvider { _private: () }
    }
}

impl trace::TracerProvider for NoopTracerProvider {
    type Tracer = NoopTracer;

    /// Returns a new `NoopTracer` instance.
    fn get_tracer(&self, _name: &'static str, _version: Option<&'static str>) -> Self::Tracer {
        NoopTracer::new()
    }
}

/// A no-op instance of a `Span`.
#[derive(Debug)]
pub struct NoopSpan {
    span_context: trace::SpanContext,
}

impl Default for NoopSpan {
    fn default() -> Self {
        NoopSpan::new()
    }
}

impl NoopSpan {
    /// Creates a new `NoopSpan` instance.
    pub fn new() -> Self {
        NoopSpan {
            span_context: trace::SpanContext::new(
                trace::TraceId::invalid(),
                trace::SpanId::invalid(),
                0,
                false,
                TraceState::default(),
            ),
        }
    }
}

impl trace::Span for NoopSpan {
    /// Ignores all events
    fn add_event(&self, _name: String, _attributes: Vec<KeyValue>) {
        // Ignore
    }

    /// Ignores all events with timestamps
    fn add_event_with_timestamp(
        &self,
        _name: String,
        _timestamp: SystemTime,
        _attributes: Vec<KeyValue>,
    ) {
        // Ignored
    }

    /// Returns an invalid `SpanContext`.
    fn span_context(&self) -> &trace::SpanContext {
        &self.span_context
    }

    /// Returns false, signifying that this span is never recording.
    fn is_recording(&self) -> bool {
        false
    }

    /// Ignores all attributes
    fn set_attribute(&self, _attribute: KeyValue) {
        // Ignored
    }

    /// Ignores status
    fn set_status(&self, _code: trace::StatusCode, _message: String) {
        // Ignored
    }

    /// Ignores name updates
    fn update_name(&self, _new_name: String) {
        // Ignored
    }

    /// Ignores `Span` endings
    fn end_with_timestamp(&self, _timestamp: SystemTime) {
        // Ignored
    }
}

/// A no-op instance of a `Tracer`.
#[derive(Debug, Default)]
pub struct NoopTracer {
    _private: (),
}

impl NoopTracer {
    /// Create a new no-op tracer
    pub fn new() -> Self {
        NoopTracer { _private: () }
    }
}

impl trace::Tracer for NoopTracer {
    type Span = trace::NoopSpan;

    /// Returns a `NoopSpan` as they are always invalid.
    fn invalid(&self) -> Self::Span {
        trace::NoopSpan::new()
    }

    /// Starts a new `NoopSpan` with a given context.
    ///
    /// If the context contains a valid span context, it is propagated.
    fn start_with_context(&self, name: &str, cx: Context) -> Self::Span {
        let mut builder = self.span_builder(name);
        builder.parent_context = Some(cx);
        self.build(builder)
    }

    /// Starts a `SpanBuilder`.
    fn span_builder(&self, name: &str) -> trace::SpanBuilder {
        trace::SpanBuilder::from_name(name.to_string())
    }

    /// Builds a `NoopSpan` from a `SpanBuilder`.
    ///
    /// If the span builder or context contains a valid span context, it is propagated.
    fn build(&self, mut builder: trace::SpanBuilder) -> Self::Span {
        let parent_span_context = builder.parent_context.take().and_then(|parent_cx| {
            if parent_cx.has_active_span() {
                Some(parent_cx.span().span_context().clone())
            } else {
                parent_cx.remote_span_context().cloned()
            }
        });
        if let Some(span_context) = parent_span_context {
            trace::NoopSpan { span_context }
        } else {
            self.invalid()
        }
    }
}

/// A no-op instance of an [`SpanExporter`].
///
/// [`SpanExporter`]: crate::sdk::export::trace::SpanExporter
#[derive(Debug, Default)]
pub struct NoopSpanExporter {
    _private: (),
}

impl NoopSpanExporter {
    /// Create a new noop span exporter
    pub fn new() -> Self {
        NoopSpanExporter { _private: () }
    }
}

#[async_trait]
impl SpanExporter for NoopSpanExporter {
    async fn export(&mut self, _batch: Vec<SpanData>) -> ExportResult {
        Ok(())
    }
}

#[cfg(all(test, feature = "testing", feature = "trace"))]
mod tests {
    use super::*;
    use crate::testing::trace::TestSpan;
    use crate::trace::{self, Span, Tracer};

    fn valid_span_context() -> trace::SpanContext {
        trace::SpanContext::new(
            trace::TraceId::from_u128(42),
            trace::SpanId::from_u64(42),
            0,
            true,
            TraceState::default(),
        )
    }

    #[test]
    fn noop_tracer_defaults_to_invalid_span() {
        let tracer = NoopTracer::new();
        let span = tracer.start_with_context("foo", Context::new());
        assert!(!span.span_context().is_valid());
    }

    #[test]
    fn noop_tracer_propagates_valid_span_context_from_builder() {
        let tracer = NoopTracer::new();
        let builder = tracer
            .span_builder("foo")
            .with_parent_context(Context::current_with_span(TestSpan(valid_span_context())));
        let span = tracer.build(builder);
        assert!(span.span_context().is_valid());
    }

    #[test]
    fn noop_tracer_propagates_valid_span_context_from_span() {
        let tracer = NoopTracer::new();
        let cx = Context::new().with_span(NoopSpan {
            span_context: valid_span_context(),
        });
        let span = tracer.start_with_context("foo", cx);
        assert!(span.span_context().is_valid());
    }

    #[test]
    fn noop_tracer_propagates_valid_span_context_from_remote_span_context() {
        let tracer = NoopTracer::new();
        let cx = Context::new().with_remote_span_context(valid_span_context());
        let span = tracer.start_with_context("foo", cx);
        assert!(span.span_context().is_valid());
    }
}
<commit_msg>Impl clone for noop tracer/provider/span (#479)<commit_after>//! # No-op OpenTelemetry Trace Implementation
//!
//! This implementation is returned as the global tracer if no `Tracer`
//! has been set. It is also useful for testing purposes as it is intended
//! to have minimal resource utilization and runtime impact.
use crate::{
    sdk::export::trace::{ExportResult, SpanData, SpanExporter},
    trace,
    trace::{TraceContextExt, TraceState},
    Context, KeyValue,
};
use async_trait::async_trait;
use std::time::SystemTime;

/// A no-op instance of a `TracerProvider`.
#[derive(Clone, Debug, Default)]
pub struct NoopTracerProvider {
    _private: (),
}

impl NoopTracerProvider {
    /// Create a new no-op tracer provider
    pub fn new() -> Self {
        NoopTracerProvider { _private: () }
    }
}

impl trace::TracerProvider for NoopTracerProvider {
    type Tracer = NoopTracer;

    /// Returns a new `NoopTracer` instance.
    fn get_tracer(&self, _name: &'static str, _version: Option<&'static str>) -> Self::Tracer {
        NoopTracer::new()
    }
}

/// A no-op instance of a `Span`.
#[derive(Clone, Debug)]
pub struct NoopSpan {
    span_context: trace::SpanContext,
}

impl Default for NoopSpan {
    fn default() -> Self {
        NoopSpan::new()
    }
}

impl NoopSpan {
    /// Creates a new `NoopSpan` instance.
    pub fn new() -> Self {
        NoopSpan {
            span_context: trace::SpanContext::new(
                trace::TraceId::invalid(),
                trace::SpanId::invalid(),
                0,
                false,
                TraceState::default(),
            ),
        }
    }
}

impl trace::Span for NoopSpan {
    /// Ignores all events
    fn add_event(&self, _name: String, _attributes: Vec<KeyValue>) {
        // Ignore
    }

    /// Ignores all events with timestamps
    fn add_event_with_timestamp(
        &self,
        _name: String,
        _timestamp: SystemTime,
        _attributes: Vec<KeyValue>,
    ) {
        // Ignored
    }

    /// Returns an invalid `SpanContext`.
    fn span_context(&self) -> &trace::SpanContext {
        &self.span_context
    }

    /// Returns false, signifying that this span is never recording.
    fn is_recording(&self) -> bool {
        false
    }

    /// Ignores all attributes
    fn set_attribute(&self, _attribute: KeyValue) {
        // Ignored
    }

    /// Ignores status
    fn set_status(&self, _code: trace::StatusCode, _message: String) {
        // Ignored
    }

    /// Ignores name updates
    fn update_name(&self, _new_name: String) {
        // Ignored
    }

    /// Ignores `Span` endings
    fn end_with_timestamp(&self, _timestamp: SystemTime) {
        // Ignored
    }
}

/// A no-op instance of a `Tracer`.
#[derive(Clone, Debug, Default)]
pub struct NoopTracer {
    _private: (),
}

impl NoopTracer {
    /// Create a new no-op tracer
    pub fn new() -> Self {
        NoopTracer { _private: () }
    }
}

impl trace::Tracer for NoopTracer {
    type Span = trace::NoopSpan;

    /// Returns a `NoopSpan` as they are always invalid.
    fn invalid(&self) -> Self::Span {
        trace::NoopSpan::new()
    }

    /// Starts a new `NoopSpan` with a given context.
    ///
    /// If the context contains a valid span context, it is propagated.
    fn start_with_context(&self, name: &str, cx: Context) -> Self::Span {
        let mut builder = self.span_builder(name);
        builder.parent_context = Some(cx);
        self.build(builder)
    }

    /// Starts a `SpanBuilder`.
    fn span_builder(&self, name: &str) -> trace::SpanBuilder {
        trace::SpanBuilder::from_name(name.to_string())
    }

    /// Builds a `NoopSpan` from a `SpanBuilder`.
    ///
    /// If the span builder or context contains a valid span context, it is propagated.
    fn build(&self, mut builder: trace::SpanBuilder) -> Self::Span {
        let parent_span_context = builder.parent_context.take().and_then(|parent_cx| {
            if parent_cx.has_active_span() {
                Some(parent_cx.span().span_context().clone())
            } else {
                parent_cx.remote_span_context().cloned()
            }
        });
        if let Some(span_context) = parent_span_context {
            trace::NoopSpan { span_context }
        } else {
            self.invalid()
        }
    }
}

/// A no-op instance of an [`SpanExporter`].
///
/// [`SpanExporter`]: crate::sdk::export::trace::SpanExporter
#[derive(Debug, Default)]
pub struct NoopSpanExporter {
    _private: (),
}

impl NoopSpanExporter {
    /// Create a new noop span exporter
    pub fn new() -> Self {
        NoopSpanExporter { _private: () }
    }
}

#[async_trait]
impl SpanExporter for NoopSpanExporter {
    async fn export(&mut self, _batch: Vec<SpanData>) -> ExportResult {
        Ok(())
    }
}

#[cfg(all(test, feature = "testing", feature = "trace"))]
mod tests {
    use super::*;
    use crate::testing::trace::TestSpan;
    use crate::trace::{self, Span, Tracer};

    fn valid_span_context() -> trace::SpanContext {
        trace::SpanContext::new(
            trace::TraceId::from_u128(42),
            trace::SpanId::from_u64(42),
            0,
            true,
            TraceState::default(),
        )
    }

    #[test]
    fn noop_tracer_defaults_to_invalid_span() {
        let tracer = NoopTracer::new();
        let span = tracer.start_with_context("foo", Context::new());
        assert!(!span.span_context().is_valid());
    }

    #[test]
    fn noop_tracer_propagates_valid_span_context_from_builder() {
        let tracer = NoopTracer::new();
        let builder = tracer
            .span_builder("foo")
            .with_parent_context(Context::current_with_span(TestSpan(valid_span_context())));
        let span = tracer.build(builder);
        assert!(span.span_context().is_valid());
    }

    #[test]
    fn noop_tracer_propagates_valid_span_context_from_span() {
        let tracer = NoopTracer::new();
        let cx = Context::new().with_span(NoopSpan {
            span_context: valid_span_context(),
        });
        let span = tracer.start_with_context("foo", cx);
        assert!(span.span_context().is_valid());
    }

    #[test]
    fn noop_tracer_propagates_valid_span_context_from_remote_span_context() {
        let tracer = NoopTracer::new();
        let cx = Context::new().with_remote_span_context(valid_span_context());
        let span = tracer.start_with_context("foo", cx);
        assert!(span.span_context().is_valid());
    }
}
<|endoftext|>


<commit_before>fn main() {}
<commit_msg>finish rust version<commit_after>use std::collections::HashMap;

fn int_to_roman(number: i32) -> String {
    let table: HashMap<i32, &str> = [
        (1, "I"),
        (4, "IV"),
        (5, "V"),
        (9, "IX"),
        (10, "X"),
        (40, "XL"),
        (50, "L"),
        (90, "XC"),
        (100, "C"),
        (400, "CD"),
        (500, "D"),
        (900, "CM"),
        (1000, "M"),
    ]
        .iter()
        .cloned()
        .collect();

    let order = vec![1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
    let mut result = String::new();
    let mut num = number;
    loop {
        if num == 0 {
            break;
        }

        if table.contains_key(&num) {
            result = result + table.get(&num).unwrap();
            break;
        }

        for v in &order {
            if num > *v {
                for _i in 0..(num / v) {
                    result = result + table.get(&v).unwrap();
                }
                num %= v;
                break;
            }
        }
    }

    result
}

fn main() {
    println!("{}", int_to_roman(1));
    println!("{}", int_to_roman(3));
    println!("{}", int_to_roman(4));
    println!("{}", int_to_roman(9));
    println!("{}", int_to_roman(58));
    println!("{}", int_to_roman(1994));
}
<|endoftext|>


<commit_before>use Error;
use error::TransportErrorKind;
use hyper;
use serde;
use serde_json;
use std;
use super::{Method, RequestAccept, RequestBody, RequestOptions, Response, StatusCode, Transport};
use url;

pub struct HyperTransport {
    server_base_url: url::Url,
    hyper_client: hyper::Client,
}

impl HyperTransport {
    pub fn new(mut server_base_url: url::Url) -> Result<Self, Error> {

        if server_base_url.path_mut().is_none() {
            return Err(Error::UrlNotSchemeRelative);
        }

        // Sometimes the URL has an empty final path component, which will lead
        // to an empty path component (//) if we naively append path components
        // to the URL. Remove any empty final component now.

        {
            let mut path = server_base_url.path_mut().unwrap();
            if !path.is_empty() && path.last().unwrap().is_empty() {
                path.pop();
            }
        }

        Ok(HyperTransport {
            server_base_url: server_base_url,
            hyper_client: hyper::Client::new(),
        })
    }

    fn request<'a, B>(&self,
                      method: Method,
                      path: &[&str],
                      options: RequestOptions<'a, B>)
                      -> Result<<Self as Transport>::Response, Error>
        where B: serde::Serialize
    {
        let uri = {
            let mut u = self.server_base_url.clone();
            u.path_mut().unwrap().extend(path.iter().map(|x| x.to_string()));
            u.set_query_from_pairs({
                let mut pairs = std::collections::HashMap::new();
                if let Some(revision) = options.revision_query {
                    pairs.insert("rev".to_string(), revision.to_string());
                }
                pairs
            });
            u
        };

        let headers = {
            let mut h = hyper::header::Headers::new();

            match options.accept {
                None => (),
                Some(RequestAccept::Json) => {
                    let quality_items = vec![hyper::header::qitem(mime!(Application / Json))];
                    h.set(hyper::header::Accept(quality_items));
                }
            }

            match options.body {
                None => (),
                Some(RequestBody::Json(..)) => {
                    h.set(hyper::header::ContentType(mime!(Application / Json)));
                }
            }

            h
        };

        Ok(HyperResponse {
            hyper_response: try!({
                match options.body {
                    None => {
                        self.hyper_client
                            .request(method, uri)
                            .headers(headers)
                            .send()
                    }
                    Some(RequestBody::Json(body)) => {
                        let body = try!(serde_json::to_vec(body)
                                            .map_err(|e| Error::JsonEncode { cause: e }));
                        self.hyper_client
                            .request(method, uri)
                            .headers(headers)
                            .body(&body[..])
                            .send()
                    }
                }
                .map_err(|e| Error::Transport { kind: TransportErrorKind::Hyper(e) })
            }),
        })
    }
}

impl Transport for HyperTransport {
    type Response = HyperResponse;

    fn delete<'a, B>(&self,
                     path: &[&str],
                     options: RequestOptions<'a, B>)
                     -> Result<Self::Response, Error>
        where B: serde::Serialize
    {
        self.request(Method::Delete, path, options)
    }

    fn get<'a, B>(&self,
                  path: &[&str],
                  options: RequestOptions<'a, B>)
                  -> Result<Self::Response, Error>
        where B: serde::Serialize
    {
        self.request(Method::Get, path, options)
    }

    fn post<'a, B>(&self,
                   path: &[&str],
                   options: RequestOptions<'a, B>)
                   -> Result<Self::Response, Error>
        where B: serde::Serialize
    {
        self.request(Method::Post, path, options)
    }

    fn put<'a, B>(&self,
                  path: &[&str],
                  options: RequestOptions<'a, B>)
                  -> Result<Self::Response, Error>
        where B: serde::Serialize
    {
        self.request(Method::Put, path, options)
    }
}

#[derive(Debug)]
pub struct HyperResponse {
    hyper_response: hyper::client::Response,
}

impl Response for HyperResponse {
    fn status_code(&self) -> StatusCode {
        self.hyper_response.status
    }

    fn decode_json_body<B: serde::Deserialize>(self) -> Result<B, Error> {

        use hyper::header::ContentType;
        use mime::{Mime, SubLevel, TopLevel};

        try!(match self.hyper_response.headers.get() {
            Some(&ContentType(Mime(TopLevel::Application, SubLevel::Json, _))) => Ok(()),
            Some(&ContentType(ref mime)) => Err(Error::ResponseNotJson(Some(mime.clone()))),
            None => Err(Error::ResponseNotJson(None)),
        });

        serde_json::from_reader(self.hyper_response).map_err(|e| Error::JsonDecode { cause: e })
    }
}

#[cfg(test)]
mod tests {

    use super::HyperTransport;

    #[test]
    fn new_hyper_transport_sanitizes_base_url() {

        let url = "http://example.com:5984".parse().unwrap();
        let transport = HyperTransport::new(url).unwrap();
        assert_eq!(Some(&[] as &[String]), transport.server_base_url.path());

        let url = "http://example.com:5984/".parse().unwrap();
        let transport = HyperTransport::new(url).unwrap();
        assert_eq!(Some(&[] as &[String]), transport.server_base_url.path());

        let url = "http://example.com:5984/foo".parse().unwrap();
        let transport = HyperTransport::new(url).unwrap();
        assert_eq!(Some(&["foo".to_string()] as &[String]),
                   transport.server_base_url.path());

        let url = "http://example.com:5984/foo/".parse().unwrap();
        let transport = HyperTransport::new(url).unwrap();
        assert_eq!(Some(&["foo".to_string()] as &[String]),
                   transport.server_base_url.path());
    }
}
<commit_msg>Fixes and test cases for percent-encoding<commit_after>use Error;
use error::TransportErrorKind;
use hyper;
use serde;
use serde_json;
use std;
use super::{Method, RequestAccept, RequestBody, RequestOptions, Response, StatusCode, Transport};
use url;

pub struct HyperTransport {
    server_base_url: url::Url,
    hyper_client: hyper::Client,
}

impl HyperTransport {
    pub fn new(mut server_base_url: url::Url) -> Result<Self, Error> {

        if server_base_url.path_mut().is_none() {
            return Err(Error::UrlNotSchemeRelative);
        }

        Ok(HyperTransport {
            server_base_url: server_base_url,
            hyper_client: hyper::Client::new(),
        })
    }

    fn request<'a, B>(&self,
                      method: Method,
                      path: &[&str],
                      options: RequestOptions<'a, B>)
                      -> Result<<Self as Transport>::Response, Error>
        where B: serde::Serialize
    {
        let uri = self.make_request_url(path, &options);

        let headers = {
            let mut h = hyper::header::Headers::new();

            match options.accept {
                None => (),
                Some(RequestAccept::Json) => {
                    let quality_items = vec![hyper::header::qitem(mime!(Application / Json))];
                    h.set(hyper::header::Accept(quality_items));
                }
            }

            match options.body {
                None => (),
                Some(RequestBody::Json(..)) => {
                    h.set(hyper::header::ContentType(mime!(Application / Json)));
                }
            }

            h
        };

        Ok(HyperResponse {
            hyper_response: try!({
                match options.body {
                    None => {
                        self.hyper_client
                            .request(method, uri)
                            .headers(headers)
                            .send()
                    }
                    Some(RequestBody::Json(body)) => {
                        let body = try!(serde_json::to_vec(body)
                                            .map_err(|e| Error::JsonEncode { cause: e }));
                        self.hyper_client
                            .request(method, uri)
                            .headers(headers)
                            .body(&body[..])
                            .send()
                    }
                }
                .map_err(|e| Error::Transport { kind: TransportErrorKind::Hyper(e) })
            }),
        })
    }

    fn make_request_url<'a, B>(&self, path: &[&str], options: &RequestOptions<'a, B>) -> url::Url
        where B: serde::Serialize
    {
        let mut url = self.server_base_url.clone();

        // The base URL may have an empty final path component, which will lead
        // to an empty path component (//) if we naively append path components
        // to the URL.
        if !path.is_empty() && url.path().unwrap().last().map_or(false, |x| x.is_empty()) {
            url.path_mut().unwrap().pop();
        }

        url.path_mut().unwrap().extend(path.iter().map(|x| {
            let x = x.replace("%", "%25")
                     .replace("/", "%2F");
            url::percent_encoding::utf8_percent_encode(&x,
                                                       url::percent_encoding::DEFAULT_ENCODE_SET)
        }));

        let query_pairs = {
            let mut pairs = std::collections::HashMap::new();
            if let Some(revision) = options.revision_query {
                pairs.insert("rev".to_string(), revision.to_string());
            }
            pairs
        };

        if !query_pairs.is_empty() {
            url.set_query_from_pairs(query_pairs);
        }

        url
    }
}

impl Transport for HyperTransport {
    type Response = HyperResponse;

    fn delete<'a, B>(&self,
                     path: &[&str],
                     options: RequestOptions<'a, B>)
                     -> Result<Self::Response, Error>
        where B: serde::Serialize
    {
        self.request(Method::Delete, path, options)
    }

    fn get<'a, B>(&self,
                  path: &[&str],
                  options: RequestOptions<'a, B>)
                  -> Result<Self::Response, Error>
        where B: serde::Serialize
    {
        self.request(Method::Get, path, options)
    }

    fn post<'a, B>(&self,
                   path: &[&str],
                   options: RequestOptions<'a, B>)
                   -> Result<Self::Response, Error>
        where B: serde::Serialize
    {
        self.request(Method::Post, path, options)
    }

    fn put<'a, B>(&self,
                  path: &[&str],
                  options: RequestOptions<'a, B>)
                  -> Result<Self::Response, Error>
        where B: serde::Serialize
    {
        self.request(Method::Put, path, options)
    }
}

#[derive(Debug)]
pub struct HyperResponse {
    hyper_response: hyper::client::Response,
}

impl Response for HyperResponse {
    fn status_code(&self) -> StatusCode {
        self.hyper_response.status
    }

    fn decode_json_body<B: serde::Deserialize>(self) -> Result<B, Error> {

        use hyper::header::ContentType;
        use mime::{Mime, SubLevel, TopLevel};

        try!(match self.hyper_response.headers.get() {
            Some(&ContentType(Mime(TopLevel::Application, SubLevel::Json, _))) => Ok(()),
            Some(&ContentType(ref mime)) => Err(Error::ResponseNotJson(Some(mime.clone()))),
            None => Err(Error::ResponseNotJson(None)),
        });

        serde_json::from_reader(self.hyper_response).map_err(|e| Error::JsonDecode { cause: e })
    }
}

#[cfg(test)]
mod tests {

    use Revision;
    use transport::RequestOptions;
    use super::HyperTransport;
    use url;

    #[test]
    fn make_request_url_empty() {
        let url = "http://example.com:5984/".parse().unwrap();
        let transport = HyperTransport::new(url).unwrap();
        let expected: url::Url = "http://example.com:5984/".parse().unwrap();
        let got = transport.make_request_url(&[], &RequestOptions::<()>::default());
        assert_eq!(expected, got);
    }

    #[test]
    fn make_request_url_normal_path() {
        let url = "http://example.com:5984/".parse().unwrap();
        let transport = HyperTransport::new(url).unwrap();
        let expected: url::Url = "http://example.com:5984/db/docid".parse().unwrap();
        let got = transport.make_request_url(&["db", "docid"], &RequestOptions::<()>::default());
        assert_eq!(expected, got);
    }

    #[test]
    fn make_request_url_base_url_has_nonempty_path() {
        let url = "http://example.com:5984/foo".parse().unwrap();
        let transport = HyperTransport::new(url).unwrap();
        let expected: url::Url = "http://example.com:5984/foo/db/docid".parse().unwrap();
        let got = transport.make_request_url(&["db", "docid"], &RequestOptions::<()>::default());
        assert_eq!(expected, got);
    }

    #[test]
    fn make_request_url_base_url_has_nonempty_path_with_trailing_slash() {
        let url = "http://example.com:5984/foo/".parse().unwrap();
        let transport = HyperTransport::new(url).unwrap();
        let expected: url::Url = "http://example.com:5984/foo/db/docid".parse().unwrap();
        let got = transport.make_request_url(&["db", "docid"], &RequestOptions::<()>::default());
        assert_eq!(expected, got);
    }

    #[test]
    fn make_request_url_path_is_percent_encoded() {
        let url = "http://example.com:5984/".parse().unwrap();
        let transport = HyperTransport::new(url).unwrap();
        let expected: url::Url = "http://example.com:5984/foo%2F%3F%23%20%25bar"
                                     .parse()
                                     .unwrap();
        let got = transport.make_request_url(&["foo/?# %bar"], &RequestOptions::<()>::default());
        assert_eq!(expected, got);
    }

    #[test]
    fn make_request_url_with_revision_query() {
        let url = "http://example.com:5984/".parse().unwrap();
        let transport = HyperTransport::new(url).unwrap();
        let expected: url::Url = "http://example.com:\
                                  5984/db/doc?rev=42-1234567890abcdef1234567890abcdef"
                                     .parse()
                                     .unwrap();

        let got = transport.make_request_url(&["db", "doc"], {
            &RequestOptions::<()>::new()
                 .with_revision_query(&Revision::parse("42-1234567890abcdef1234567890abcdef")
                                           .unwrap())
        });
        assert_eq!(expected, got);
    }
}
<|endoftext|>


<commit_before>use test::Bencher;

const CHARS: [char; 9] = ['0', 'x', '2', '5', 'A', 'f', '7', '8', '9'];
const RADIX: [u32; 5] = [2, 8, 10, 16, 32];

#[bench]
fn bench_to_digit_radix_2(b: &mut Bencher) {
    b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_digit(2)).min())
}

#[bench]
fn bench_to_digit_radix_10(b: &mut Bencher) {
    b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_digit(10)).min())
}

#[bench]
fn bench_to_digit_radix_16(b: &mut Bencher) {
    b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_digit(16)).min())
}

#[bench]
fn bench_to_digit_radix_36(b: &mut Bencher) {
    b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_digit(36)).min())
}

#[bench]
fn bench_to_digit_radix_var(b: &mut Bencher) {
    b.iter(|| {
        CHARS
            .iter()
            .cycle()
            .zip(RADIX.iter().cycle())
            .take(10_000)
            .map(|(c, radix)| c.to_digit(*radix))
            .min()
    })
}

#[bench]
fn bench_to_ascii_uppercase(b: &mut Bencher) {
    b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_ascii_uppercase()).min())
}

#[bench]
fn bench_to_ascii_lowercase(b: &mut Bencher) {
    b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_ascii_lowercase()).min())
}
<commit_msg>Add to_lowercase and to_uppercase char benchmarks<commit_after>use test::Bencher;

const CHARS: [char; 9] = ['0', 'x', '2', '5', 'A', 'f', '7', '8', '9'];
const RADIX: [u32; 5] = [2, 8, 10, 16, 32];

#[bench]
fn bench_to_digit_radix_2(b: &mut Bencher) {
    b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_digit(2)).min())
}

#[bench]
fn bench_to_digit_radix_10(b: &mut Bencher) {
    b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_digit(10)).min())
}

#[bench]
fn bench_to_digit_radix_16(b: &mut Bencher) {
    b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_digit(16)).min())
}

#[bench]
fn bench_to_digit_radix_36(b: &mut Bencher) {
    b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_digit(36)).min())
}

#[bench]
fn bench_to_digit_radix_var(b: &mut Bencher) {
    b.iter(|| {
        CHARS
            .iter()
            .cycle()
            .zip(RADIX.iter().cycle())
            .take(10_000)
            .map(|(c, radix)| c.to_digit(*radix))
            .min()
    })
}

#[bench]
fn bench_to_ascii_uppercase(b: &mut Bencher) {
    b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_ascii_uppercase()).min())
}

#[bench]
fn bench_to_ascii_lowercase(b: &mut Bencher) {
    b.iter(|| CHARS.iter().cycle().take(10_000).map(|c| c.to_ascii_lowercase()).min())
}

#[bench]
fn bench_char_to_uppercase(b: &mut Bencher) {
    b.iter(|| (0..=255).cycle().take(10_000).map(|b| char::from(b).to_uppercase()).count())
}

#[bench]
fn bench_char_to_lowercase(b: &mut Bencher) {
    b.iter(|| (0..=255).cycle().take(10_000).map(|b| char::from(b).to_lowercase()).count())
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::from_str::FromStr;
use std::rc::Rc;

use super::action::Action;
use super::action::{TypedAction, IFlagAction, IArgAction, IArgsAction};
use super::action::{ParseResult, Parsed, Error};
use super::action::{Flag, Single, Push, Many};

pub struct StoreConst<T>(T);

pub struct Store<T>;

pub struct StoreOption<T>;

pub struct List<T>;

pub struct Collect<T>;

pub struct StoreConstAction<'a, T> {
    pub value: T,
    pub cell: Rc<RefCell<&'a mut T>>,
}

pub struct StoreAction<'a, T> {
    pub cell: Rc<RefCell<&'a mut T>>,
}

pub struct StoreOptionAction<'a, T> {
    cell: Rc<RefCell<&'a mut Option<T>>>,
}

pub struct ListAction<'a, T> {
    cell: Rc<RefCell<&'a mut ~[T]>>,
}

impl<T: 'static + Copy> TypedAction<T> for StoreConst<T> {
    fn bind<'x>(&self, cell: Rc<RefCell<&'x mut T>>) -> Action {
        let StoreConst(val) = *self;
        return Flag(box StoreConstAction { cell: cell, value: val });
    }
}

impl<T: 'static + FromStr> TypedAction<T> for Store<T> {
    fn bind<'x>(&self, cell: Rc<RefCell<&'x mut T>>) -> Action {
        return Single(box StoreAction { cell: cell });
    }
}

impl<T: 'static + FromStr> TypedAction<Option<T>> for StoreOption<T> {
    fn bind<'x>(&self, cell: Rc<RefCell<&'x mut Option<T>>>) -> Action {
        return Single(box StoreOptionAction { cell: cell });
    }
}

impl<T: 'static + FromStr + Clone> TypedAction<~[T]> for List<T> {
    fn bind<'x>(&self, cell: Rc<RefCell<&'x mut ~[T]>>) -> Action {
        return Many(box ListAction { cell: cell });
    }
}

impl<T: 'static + FromStr + Clone> TypedAction<~[T]> for Collect<T> {
    fn bind<'x>(&self, cell: Rc<RefCell<&'x mut ~[T]>>) -> Action {
        return Push(box ListAction { cell: cell });
    }
}

impl<'a, T: Copy> IFlagAction for StoreConstAction<'a, T> {
    fn parse_flag(&self) -> ParseResult {
        let mut targ = self.cell.borrow_mut();
        **targ = self.value;
        return Parsed;
    }
}

impl<'a, T: FromStr> IArgAction for StoreAction<'a, T> {
    fn parse_arg(&self, arg: &str) -> ParseResult {
        match FromStr::from_str(arg) {
            Some(x) => {
                **self.cell.borrow_mut() = x;
                return Parsed;
            }
            None => {
                return Error(format!("Bad value {}", arg));
            }
        }
    }
}

impl<'a, T: FromStr> IArgAction for StoreOptionAction<'a, T> {
    fn parse_arg(&self, arg: &str) -> ParseResult {
        match FromStr::from_str(arg) {
            Some(x) => {
                **self.cell.borrow_mut() = Some(x);
                return Parsed;
            }
            None => {
                return Error(format!("Bad value {}", arg));
            }
        }
    }
}

impl<'a, T: FromStr + Clone> IArgsAction for ListAction<'a, T> {
    fn parse_args(&self, args: &[&str]) -> ParseResult {
        let mut result = box Vec::new();
        for arg in args.iter() {
            match FromStr::from_str(*arg) {
                Some(x) => {
                    result.push(x);
                }
                None => {
                    return Error(format!("Bad value {}", arg));
                }
            }
        }
        **self.cell.borrow_mut() = result.as_slice().to_owned();
        return Parsed;
    }
}

<commit_msg>Fix StoreConst to have public field<commit_after>use std::cell::RefCell;
use std::from_str::FromStr;
use std::rc::Rc;

use super::action::Action;
use super::action::{TypedAction, IFlagAction, IArgAction, IArgsAction};
use super::action::{ParseResult, Parsed, Error};
use super::action::{Flag, Single, Push, Many};

pub struct StoreConst<T>(pub T);

pub struct Store<T>;

pub struct StoreOption<T>;

pub struct List<T>;

pub struct Collect<T>;

pub struct StoreConstAction<'a, T> {
    pub value: T,
    pub cell: Rc<RefCell<&'a mut T>>,
}

pub struct StoreAction<'a, T> {
    pub cell: Rc<RefCell<&'a mut T>>,
}

pub struct StoreOptionAction<'a, T> {
    cell: Rc<RefCell<&'a mut Option<T>>>,
}

pub struct ListAction<'a, T> {
    cell: Rc<RefCell<&'a mut ~[T]>>,
}

impl<T: 'static + Copy> TypedAction<T> for StoreConst<T> {
    fn bind<'x>(&self, cell: Rc<RefCell<&'x mut T>>) -> Action {
        let StoreConst(val) = *self;
        return Flag(box StoreConstAction { cell: cell, value: val });
    }
}

impl<T: 'static + FromStr> TypedAction<T> for Store<T> {
    fn bind<'x>(&self, cell: Rc<RefCell<&'x mut T>>) -> Action {
        return Single(box StoreAction { cell: cell });
    }
}

impl<T: 'static + FromStr> TypedAction<Option<T>> for StoreOption<T> {
    fn bind<'x>(&self, cell: Rc<RefCell<&'x mut Option<T>>>) -> Action {
        return Single(box StoreOptionAction { cell: cell });
    }
}

impl<T: 'static + FromStr + Clone> TypedAction<~[T]> for List<T> {
    fn bind<'x>(&self, cell: Rc<RefCell<&'x mut ~[T]>>) -> Action {
        return Many(box ListAction { cell: cell });
    }
}

impl<T: 'static + FromStr + Clone> TypedAction<~[T]> for Collect<T> {
    fn bind<'x>(&self, cell: Rc<RefCell<&'x mut ~[T]>>) -> Action {
        return Push(box ListAction { cell: cell });
    }
}

impl<'a, T: Copy> IFlagAction for StoreConstAction<'a, T> {
    fn parse_flag(&self) -> ParseResult {
        let mut targ = self.cell.borrow_mut();
        **targ = self.value;
        return Parsed;
    }
}

impl<'a, T: FromStr> IArgAction for StoreAction<'a, T> {
    fn parse_arg(&self, arg: &str) -> ParseResult {
        match FromStr::from_str(arg) {
            Some(x) => {
                **self.cell.borrow_mut() = x;
                return Parsed;
            }
            None => {
                return Error(format!("Bad value {}", arg));
            }
        }
    }
}

impl<'a, T: FromStr> IArgAction for StoreOptionAction<'a, T> {
    fn parse_arg(&self, arg: &str) -> ParseResult {
        match FromStr::from_str(arg) {
            Some(x) => {
                **self.cell.borrow_mut() = Some(x);
                return Parsed;
            }
            None => {
                return Error(format!("Bad value {}", arg));
            }
        }
    }
}

impl<'a, T: FromStr + Clone> IArgsAction for ListAction<'a, T> {
    fn parse_args(&self, args: &[&str]) -> ParseResult {
        let mut result = box Vec::new();
        for arg in args.iter() {
            match FromStr::from_str(*arg) {
                Some(x) => {
                    result.push(x);
                }
                None => {
                    return Error(format!("Bad value {}", arg));
                }
            }
        }
        **self.cell.borrow_mut() = result.as_slice().to_owned();
        return Parsed;
    }
}

<|endoftext|>


<commit_before>use num_bigint::BigInt;
use num_traits::ToPrimitive;
use std::{fmt, str::FromStr};

mod precision;
use self::precision::*;

pub mod error;
pub use self::error::*;

#[cfg(not(any(test, feature = "testnet")))]
pub const ASSET_SYMBOL: &str = "GRAEL";

#[cfg(any(test, feature = "testnet"))]
pub const ASSET_SYMBOL: &str = "TEST";

pub const MAX_STR_LEN: usize = 26;
pub const MAX_PRECISION: u8 = 5;

#[derive(Copy, Clone, Default, PartialEq, PartialOrd)]
pub struct Asset {
    pub amount: i64,
}

impl Asset {
    #[inline]
    pub const fn new(amount: i64) -> Asset {
        Asset { amount }
    }

    #[inline]
    pub fn checked_add(self, other: Self) -> Option<Self> {
        Some(Asset {
            amount: self.amount.checked_add(other.amount)?,
        })
    }

    #[inline]
    pub fn checked_sub(self, other: Self) -> Option<Self> {
        Some(Asset {
            amount: self.amount.checked_sub(other.amount)?,
        })
    }

    pub fn checked_mul(self, other: Self) -> Option<Self> {
        const MUL_PRECISION: u8 = MAX_PRECISION * 2;
        let mul = i128::from(self.amount).checked_mul(i128::from(other.amount))?;
        let final_mul = set_decimals_i128(mul, MUL_PRECISION, MAX_PRECISION)?;
        if final_mul > i128::from(::std::i64::MAX) {
            return None;
        }
        Some(Asset {
            amount: final_mul as i64,
        })
    }

    pub fn checked_div(self, other: Self) -> Option<Self> {
        if other.amount == 0 {
            return None;
        }
        const DIV_PRECISION: u8 = MAX_PRECISION * 2;
        let a = set_decimals_i64(self.amount, MAX_PRECISION, DIV_PRECISION)?;
        Some(Asset {
            amount: a.checked_div(other.amount)?,
        })
    }

    pub fn checked_pow(self, num: u16) -> Option<Self> {
        if num == 0 {
            return Some(Asset {
                amount: set_decimals_i64(1, 0, MAX_PRECISION)?,
            });
        }

        let decimals = u16::from(MAX_PRECISION).checked_mul(num)?;
        let mut res = BigInt::from(1);
        {
            let mut base = BigInt::from(self.amount);
            let mut exp = num;
            loop {
                if exp & 1 == 1 {
                    res = &res * &base;
                }
                exp >>= 1;
                if exp == 0 {
                    break;
                };
                base = &base * &base;
            }
        }

        res = set_decimals_big(&res, decimals, u16::from(MAX_PRECISION));
        Some(Asset {
            amount: res.to_i64()?,
        })
    }
}

impl fmt::Debug for Asset {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "Asset(\"{}\")", self.to_string())
    }
}

impl ToString for Asset {
    #[allow(clippy::comparison_chain)]
    fn to_string(&self) -> String {
        let mut s = self.amount.to_string();
        {
            let len = s.len();
            // See std::core::cmp for the most optimal comparisons
            if len < MAX_PRECISION as usize {
                let start = if self.amount < 0 { 1 } else { 0 };
                let diff = MAX_PRECISION as usize - len + start;
                s.insert_str(start, "0.");
                s.insert_str(start + 2, &"0".repeat(diff));
            } else if len == MAX_PRECISION as usize {
                s.insert_str(0, "0.");
            } else {
                s.insert(len - (MAX_PRECISION as usize), '.');
            }
        }
        s.push(' ');
        s.push_str(ASSET_SYMBOL);
        s
    }
}

impl FromStr for Asset {
    type Err = AssetError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.len() > MAX_STR_LEN {
            return Err(AssetError {
                kind: AssetErrorKind::StrTooLarge,
            });
        }
        let mut split = s.trim().splitn(2, ' ');

        let amount: i64;
        match split.next() {
            Some(x) => {
                match x.find('.') {
                    Some(pos) => {
                        // Check decimal precision is correct
                        {
                            let decimals = {
                                let len = x.len() - 1;
                                if pos > 0 {
                                    (len - pos) as u8
                                } else {
                                    len as u8
                                }
                            };

                            if decimals != MAX_PRECISION {
                                return Err(AssetError {
                                    kind: AssetErrorKind::InvalidFormat,
                                });
                            }
                        }

                        // Actually parse the amount
                        amount = match x.replace('.', "").parse() {
                            Ok(x) => x,
                            Err(_) => {
                                return Err(AssetError {
                                    kind: AssetErrorKind::InvalidAmount,
                                });
                            }
                        }
                    }
                    None => {
                        return Err(AssetError {
                            kind: AssetErrorKind::InvalidFormat,
                        });
                    }
                }
            }
            None => {
                return Err(AssetError {
                    kind: AssetErrorKind::InvalidFormat,
                });
            }
        };

        match split.next() {
            Some(x) => {
                if x != ASSET_SYMBOL {
                    return Err(AssetError {
                        kind: AssetErrorKind::InvalidAssetType,
                    });
                }
            }
            None => {
                return Err(AssetError {
                    kind: AssetErrorKind::InvalidFormat,
                });
            }
        };

        Ok(Asset { amount })
    }
}

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

    #[test]
    fn parse_valid_input() {
        let c = |asset: Asset, amount: &str| {
            assert_eq!(asset.amount.to_string(), amount);
        };

        c(get_asset("1.00000 TEST"), "100000");
        c(get_asset("-1.00000 TEST"), "-100000");
        c(get_asset(".10000 TEST"), "10000");
        c(get_asset("-.10000 TEST"), "-10000");
        c(get_asset("0.10000 TEST"), "10000");
        c(get_asset("0.00000 TEST"), "0");
        c(get_asset("-0.00000 TEST"), "0");
    }

    #[test]
    fn asset_to_str() {
        let c = |asset: Asset, s: &str| {
            assert_eq!(asset.to_string(), s);
        };
        c(get_asset("1.00001 TEST"), "1.00001 TEST");
        c(get_asset("0.00001 TEST"), "0.00001 TEST");
        c(get_asset("0.00010 TEST"), "0.00010 TEST");
        c(get_asset("-0.00001 TEST"), "-0.00001 TEST");
        c(get_asset(".00001 TEST"), "0.00001 TEST");
        c(get_asset(".10000 TEST"), "0.10000 TEST");
        c(get_asset("1.00000 TEST"), "1.00000 TEST");
    }

    #[test]
    fn fail_parsing_invalid_input() {
        let c = |asset: &str, err: AssetErrorKind| {
            let e = Asset::from_str(asset).err().unwrap();
            assert_eq!(e.kind, err, "Asset: {}", asset);
        };

        c("1b10.00000 TEST", AssetErrorKind::InvalidAmount);
        c("a100.00000 TEST", AssetErrorKind::InvalidAmount);
        c("100.0000a TEST", AssetErrorKind::InvalidAmount);

        c("1 TEST", AssetErrorKind::InvalidFormat);
        c("1. TEST", AssetErrorKind::InvalidFormat);
        c(".1 TEST", AssetErrorKind::InvalidFormat);
        c("-.1 TEST", AssetErrorKind::InvalidFormat);
        c("0.1 TEST", AssetErrorKind::InvalidFormat);
        c("1.0 TEST", AssetErrorKind::InvalidFormat);
        c("0 TEST", AssetErrorKind::InvalidFormat);
        c("-0.0 TEST", AssetErrorKind::InvalidFormat);
        c("-1.0 TEST", AssetErrorKind::InvalidFormat);

        c("1234567890123456789012 TEST", AssetErrorKind::StrTooLarge);
        c("1.000000 TEST", AssetErrorKind::InvalidFormat);
        c("1.0000", AssetErrorKind::InvalidFormat);

        c("1.00000 TEST a", AssetErrorKind::InvalidAssetType);
        c("1.00000 test", AssetErrorKind::InvalidAssetType);
    }

    #[test]
    fn perform_arithmetic() {
        let c = |asset: Asset, amount: &str| {
            assert_eq!(asset.to_string(), amount);
        };

        let a = get_asset("123.45600 TEST");
        c(
            a.checked_add(get_asset("2.00000 TEST")).unwrap(),
            "125.45600 TEST",
        );
        c(
            a.checked_add(get_asset("-2.00000 TEST")).unwrap(),
            "121.45600 TEST",
        );
        c(
            a.checked_add(get_asset(".00001 TEST")).unwrap(),
            "123.45601 TEST",
        );
        c(
            a.checked_sub(get_asset("2.00000 TEST")).unwrap(),
            "121.45600 TEST",
        );
        c(
            a.checked_sub(get_asset("-2.00000 TEST")).unwrap(),
            "125.45600 TEST",
        );
        c(
            a.checked_mul(get_asset("100000.11111 TEST")).unwrap(),
            "12345613.71719 TEST",
        );
        c(
            a.checked_mul(get_asset("-100000.11111 TEST")).unwrap(),
            "-12345613.71719 TEST",
        );
        c(
            a.checked_div(get_asset("23.00000 TEST")).unwrap(),
            "5.36765 TEST",
        );
        c(
            a.checked_div(get_asset("-23.00000 TEST")).unwrap(),
            "-5.36765 TEST",
        );
        c(a.checked_pow(2).unwrap(), "15241.38393 TEST");
        c(a.checked_pow(3).unwrap(), "1881640.29520 TEST");
        c(a, "123.45600 TEST");

        c(
            get_asset("1.00020 TEST").checked_pow(1000).unwrap(),
            "1.22137 TEST",
        );
        c(
            get_asset("10.00000 TEST")
                .checked_div(get_asset("2.00000 TEST"))
                .unwrap(),
            "5.00000 TEST",
        );
        c(
            get_asset("5.00000 TEST")
                .checked_div(get_asset("10.00000 TEST"))
                .unwrap(),
            "0.50000 TEST",
        );

        assert!(a.checked_div(get_asset("0.00000 TEST")).is_none());
    }

    #[test]
    fn invalid_arithmetic() {
        let a = get_asset("10.00000 TEST");
        let b = get_asset("92233720368547.75807 TEST");

        assert_eq!(a.checked_add(b), None);
        assert_eq!(a.checked_mul(Asset::new(-1)).unwrap().checked_sub(b), None);
        assert_eq!(a.checked_div(Asset::new(0)), None);
        assert_eq!(a.checked_mul(b), None);
    }

    fn get_asset(s: &str) -> Asset {
        Asset::from_str(s).unwrap()
    }
}
<commit_msg>Add more derives to Asset<commit_after>use num_bigint::BigInt;
use num_traits::ToPrimitive;
use std::{fmt, str::FromStr};

mod precision;
use self::precision::*;

pub mod error;
pub use self::error::*;

#[cfg(not(any(test, feature = "testnet")))]
pub const ASSET_SYMBOL: &str = "GRAEL";

#[cfg(any(test, feature = "testnet"))]
pub const ASSET_SYMBOL: &str = "TEST";

pub const MAX_STR_LEN: usize = 26;
pub const MAX_PRECISION: u8 = 5;

#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
pub struct Asset {
    pub amount: i64,
}

impl Asset {
    #[inline]
    pub const fn new(amount: i64) -> Asset {
        Asset { amount }
    }

    #[inline]
    pub fn checked_add(self, other: Self) -> Option<Self> {
        Some(Asset {
            amount: self.amount.checked_add(other.amount)?,
        })
    }

    #[inline]
    pub fn checked_sub(self, other: Self) -> Option<Self> {
        Some(Asset {
            amount: self.amount.checked_sub(other.amount)?,
        })
    }

    pub fn checked_mul(self, other: Self) -> Option<Self> {
        const MUL_PRECISION: u8 = MAX_PRECISION * 2;
        let mul = i128::from(self.amount).checked_mul(i128::from(other.amount))?;
        let final_mul = set_decimals_i128(mul, MUL_PRECISION, MAX_PRECISION)?;
        if final_mul > i128::from(::std::i64::MAX) {
            return None;
        }
        Some(Asset {
            amount: final_mul as i64,
        })
    }

    pub fn checked_div(self, other: Self) -> Option<Self> {
        if other.amount == 0 {
            return None;
        }
        const DIV_PRECISION: u8 = MAX_PRECISION * 2;
        let a = set_decimals_i64(self.amount, MAX_PRECISION, DIV_PRECISION)?;
        Some(Asset {
            amount: a.checked_div(other.amount)?,
        })
    }

    pub fn checked_pow(self, num: u16) -> Option<Self> {
        if num == 0 {
            return Some(Asset {
                amount: set_decimals_i64(1, 0, MAX_PRECISION)?,
            });
        }

        let decimals = u16::from(MAX_PRECISION).checked_mul(num)?;
        let mut res = BigInt::from(1);
        {
            let mut base = BigInt::from(self.amount);
            let mut exp = num;
            loop {
                if exp & 1 == 1 {
                    res = &res * &base;
                }
                exp >>= 1;
                if exp == 0 {
                    break;
                };
                base = &base * &base;
            }
        }

        res = set_decimals_big(&res, decimals, u16::from(MAX_PRECISION));
        Some(Asset {
            amount: res.to_i64()?,
        })
    }
}

impl fmt::Debug for Asset {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "Asset(\"{}\")", self.to_string())
    }
}

impl ToString for Asset {
    #[allow(clippy::comparison_chain)]
    fn to_string(&self) -> String {
        let mut s = self.amount.to_string();
        {
            let len = s.len();
            // See std::core::cmp for the most optimal comparisons
            if len < MAX_PRECISION as usize {
                let start = if self.amount < 0 { 1 } else { 0 };
                let diff = MAX_PRECISION as usize - len + start;
                s.insert_str(start, "0.");
                s.insert_str(start + 2, &"0".repeat(diff));
            } else if len == MAX_PRECISION as usize {
                s.insert_str(0, "0.");
            } else {
                s.insert(len - (MAX_PRECISION as usize), '.');
            }
        }
        s.push(' ');
        s.push_str(ASSET_SYMBOL);
        s
    }
}

impl FromStr for Asset {
    type Err = AssetError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        if s.len() > MAX_STR_LEN {
            return Err(AssetError {
                kind: AssetErrorKind::StrTooLarge,
            });
        }
        let mut split = s.trim().splitn(2, ' ');

        let amount: i64;
        match split.next() {
            Some(x) => {
                match x.find('.') {
                    Some(pos) => {
                        // Check decimal precision is correct
                        {
                            let decimals = {
                                let len = x.len() - 1;
                                if pos > 0 {
                                    (len - pos) as u8
                                } else {
                                    len as u8
                                }
                            };

                            if decimals != MAX_PRECISION {
                                return Err(AssetError {
                                    kind: AssetErrorKind::InvalidFormat,
                                });
                            }
                        }

                        // Actually parse the amount
                        amount = match x.replace('.', "").parse() {
                            Ok(x) => x,
                            Err(_) => {
                                return Err(AssetError {
                                    kind: AssetErrorKind::InvalidAmount,
                                });
                            }
                        }
                    }
                    None => {
                        return Err(AssetError {
                            kind: AssetErrorKind::InvalidFormat,
                        });
                    }
                }
            }
            None => {
                return Err(AssetError {
                    kind: AssetErrorKind::InvalidFormat,
                });
            }
        };

        match split.next() {
            Some(x) => {
                if x != ASSET_SYMBOL {
                    return Err(AssetError {
                        kind: AssetErrorKind::InvalidAssetType,
                    });
                }
            }
            None => {
                return Err(AssetError {
                    kind: AssetErrorKind::InvalidFormat,
                });
            }
        };

        Ok(Asset { amount })
    }
}

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

    #[test]
    fn parse_valid_input() {
        let c = |asset: Asset, amount: &str| {
            assert_eq!(asset.amount.to_string(), amount);
        };

        c(get_asset("1.00000 TEST"), "100000");
        c(get_asset("-1.00000 TEST"), "-100000");
        c(get_asset(".10000 TEST"), "10000");
        c(get_asset("-.10000 TEST"), "-10000");
        c(get_asset("0.10000 TEST"), "10000");
        c(get_asset("0.00000 TEST"), "0");
        c(get_asset("-0.00000 TEST"), "0");
    }

    #[test]
    fn asset_to_str() {
        let c = |asset: Asset, s: &str| {
            assert_eq!(asset.to_string(), s);
        };
        c(get_asset("1.00001 TEST"), "1.00001 TEST");
        c(get_asset("0.00001 TEST"), "0.00001 TEST");
        c(get_asset("0.00010 TEST"), "0.00010 TEST");
        c(get_asset("-0.00001 TEST"), "-0.00001 TEST");
        c(get_asset(".00001 TEST"), "0.00001 TEST");
        c(get_asset(".10000 TEST"), "0.10000 TEST");
        c(get_asset("1.00000 TEST"), "1.00000 TEST");
    }

    #[test]
    fn fail_parsing_invalid_input() {
        let c = |asset: &str, err: AssetErrorKind| {
            let e = Asset::from_str(asset).err().unwrap();
            assert_eq!(e.kind, err, "Asset: {}", asset);
        };

        c("1b10.00000 TEST", AssetErrorKind::InvalidAmount);
        c("a100.00000 TEST", AssetErrorKind::InvalidAmount);
        c("100.0000a TEST", AssetErrorKind::InvalidAmount);

        c("1 TEST", AssetErrorKind::InvalidFormat);
        c("1. TEST", AssetErrorKind::InvalidFormat);
        c(".1 TEST", AssetErrorKind::InvalidFormat);
        c("-.1 TEST", AssetErrorKind::InvalidFormat);
        c("0.1 TEST", AssetErrorKind::InvalidFormat);
        c("1.0 TEST", AssetErrorKind::InvalidFormat);
        c("0 TEST", AssetErrorKind::InvalidFormat);
        c("-0.0 TEST", AssetErrorKind::InvalidFormat);
        c("-1.0 TEST", AssetErrorKind::InvalidFormat);

        c("1234567890123456789012 TEST", AssetErrorKind::StrTooLarge);
        c("1.000000 TEST", AssetErrorKind::InvalidFormat);
        c("1.0000", AssetErrorKind::InvalidFormat);

        c("1.00000 TEST a", AssetErrorKind::InvalidAssetType);
        c("1.00000 test", AssetErrorKind::InvalidAssetType);
    }

    #[test]
    fn perform_arithmetic() {
        let c = |asset: Asset, amount: &str| {
            assert_eq!(asset.to_string(), amount);
        };

        let a = get_asset("123.45600 TEST");
        c(
            a.checked_add(get_asset("2.00000 TEST")).unwrap(),
            "125.45600 TEST",
        );
        c(
            a.checked_add(get_asset("-2.00000 TEST")).unwrap(),
            "121.45600 TEST",
        );
        c(
            a.checked_add(get_asset(".00001 TEST")).unwrap(),
            "123.45601 TEST",
        );
        c(
            a.checked_sub(get_asset("2.00000 TEST")).unwrap(),
            "121.45600 TEST",
        );
        c(
            a.checked_sub(get_asset("-2.00000 TEST")).unwrap(),
            "125.45600 TEST",
        );
        c(
            a.checked_mul(get_asset("100000.11111 TEST")).unwrap(),
            "12345613.71719 TEST",
        );
        c(
            a.checked_mul(get_asset("-100000.11111 TEST")).unwrap(),
            "-12345613.71719 TEST",
        );
        c(
            a.checked_div(get_asset("23.00000 TEST")).unwrap(),
            "5.36765 TEST",
        );
        c(
            a.checked_div(get_asset("-23.00000 TEST")).unwrap(),
            "-5.36765 TEST",
        );
        c(a.checked_pow(2).unwrap(), "15241.38393 TEST");
        c(a.checked_pow(3).unwrap(), "1881640.29520 TEST");
        c(a, "123.45600 TEST");

        c(
            get_asset("1.00020 TEST").checked_pow(1000).unwrap(),
            "1.22137 TEST",
        );
        c(
            get_asset("10.00000 TEST")
                .checked_div(get_asset("2.00000 TEST"))
                .unwrap(),
            "5.00000 TEST",
        );
        c(
            get_asset("5.00000 TEST")
                .checked_div(get_asset("10.00000 TEST"))
                .unwrap(),
            "0.50000 TEST",
        );

        assert!(a.checked_div(get_asset("0.00000 TEST")).is_none());
    }

    #[test]
    fn invalid_arithmetic() {
        let a = get_asset("10.00000 TEST");
        let b = get_asset("92233720368547.75807 TEST");

        assert_eq!(a.checked_add(b), None);
        assert_eq!(a.checked_mul(Asset::new(-1)).unwrap().checked_sub(b), None);
        assert_eq!(a.checked_div(Asset::new(0)), None);
        assert_eq!(a.checked_mul(b), None);
    }

    fn get_asset(s: &str) -> Asset {
        Asset::from_str(s).unwrap()
    }
}
<|endoftext|>


<commit_before>//! This is the actual "grammar" of the Rust language.
//!
//! Each function in this module and its children corresponds
//! to a production of the format grammar. Submodules roughly
//! correspond to different *areas* of the grammar. By convention,
//! each submodule starts with `use super::*` import and exports
//! "public" productions via `pub(super)`.
//!
//! See docs for `Parser` to learn about API, available to the grammar,
//! and see docs for `Event` to learn how this actually manages to
//! produce parse trees.
//!
//! Code in this module also contains inline tests, which start with
//! `// test name-of-the-test` comment and look like this:
//!
//! ```
//! // test function_with_zero_parameters
//! // fn foo() {}
//! ```
//!
//! After adding a new inline-test, run `cargo collect-tests` to extract
//! it as a standalone text-fixture into `tests/data/parser/inline`, and
//! run `cargo test` once to create the "gold" value.
//!
//! Coding convention: rules like `where_clause` always produce either a
//! node or an error, rules like `opt_where_clause` may produce nothing.
//! Non-opt rules typically start with `assert!(p.at(FIRST_TOKEN))`, the
//! caller is responsible for branching on the first token.
mod attributes;
mod expressions;
mod items;
mod params;
mod paths;
mod patterns;
mod type_args;
mod type_params;
mod types;

use crate::{
    SyntaxKind::{self, *},
    TokenSet,
    parser::{CompletedMarker, Marker, Parser},
};

pub(crate) fn root(p: &mut Parser) {
    let m = p.start();
    p.eat(SHEBANG);
    items::mod_contents(p, false);
    m.complete(p, SOURCE_FILE);
}

pub(crate) fn reparser(
    node: SyntaxKind,
    first_child: Option<SyntaxKind>,
    parent: Option<SyntaxKind>,
) -> Option<fn(&mut Parser)> {
    let res = match node {
        BLOCK => expressions::block,
        NAMED_FIELD_DEF_LIST => items::named_field_def_list,
        NAMED_FIELD_LIST => items::named_field_list,
        ENUM_VARIANT_LIST => items::enum_variant_list,
        MATCH_ARM_LIST => items::match_arm_list,
        USE_TREE_LIST => items::use_tree_list,
        EXTERN_ITEM_LIST => items::extern_item_list,
        TOKEN_TREE if first_child? == L_CURLY => items::token_tree,
        ITEM_LIST => match parent? {
            IMPL_BLOCK => items::impl_item_list,
            TRAIT_DEF => items::trait_item_list,
            MODULE => items::mod_item_list,
            _ => return None,
        },
        _ => return None,
    };
    Some(res)
}

#[derive(Clone, Copy, PartialEq, Eq)]
enum BlockLike {
    Block,
    NotBlock,
}

impl BlockLike {
    fn is_block(self) -> bool {
        self == BlockLike::Block
    }
}

fn opt_visibility(p: &mut Parser) -> bool {
    match p.current() {
        PUB_KW => {
            let m = p.start();
            p.bump();
            if p.at(L_PAREN) {
                match p.nth(1) {
                    // test crate_visibility
                    // pub(crate) struct S;
                    // pub(self) struct S;
                    // pub(self) struct S;
                    // pub(self) struct S;
                    CRATE_KW | SELF_KW | SUPER_KW => {
                        p.bump();
                        p.bump();
                        p.expect(R_PAREN);
                    }
                    IN_KW => {
                        p.bump();
                        p.bump();
                        paths::use_path(p);
                        p.expect(R_PAREN);
                    }
                    _ => (),
                }
            }
            m.complete(p, VISIBILITY);
        }
        // test crate_keyword_vis
        // crate fn main() { }
        // struct S { crate field: u32 }
        // struct T(crate u32);
        //
        // test crate_keyword_path
        // fn foo() { crate::foo(); }
        CRATE_KW if p.nth(1) != COLONCOLON => {
            let m = p.start();
            p.bump();
            m.complete(p, VISIBILITY);
        }
        _ => return false,
    }
    true
}

fn opt_alias(p: &mut Parser) {
    if p.at(AS_KW) {
        let m = p.start();
        p.bump();
        if !p.eat(UNDERSCORE) {
            name(p);
        }
        m.complete(p, ALIAS);
    }
}

fn abi(p: &mut Parser) {
    assert!(p.at(EXTERN_KW));
    let abi = p.start();
    p.bump();
    match p.current() {
        STRING | RAW_STRING => p.bump(),
        _ => (),
    }
    abi.complete(p, ABI);
}

fn opt_fn_ret_type(p: &mut Parser) -> bool {
    if p.at(THIN_ARROW) {
        let m = p.start();
        p.bump();
        types::type_(p);
        m.complete(p, RET_TYPE);
        true
    } else {
        false
    }
}

fn name_r(p: &mut Parser, recovery: TokenSet) {
    if p.at(IDENT) {
        let m = p.start();
        p.bump();
        m.complete(p, NAME);
    } else {
        p.err_recover("expected a name", recovery);
    }
}

fn name(p: &mut Parser) {
    name_r(p, TokenSet::empty())
}

fn name_ref(p: &mut Parser) {
    if p.at(IDENT) {
        let m = p.start();
        p.bump();
        m.complete(p, NAME_REF);
    } else {
        p.err_and_bump("expected identifier");
    }
}

fn error_block(p: &mut Parser, message: &str) {
    assert!(p.at(L_CURLY));
    let m = p.start();
    p.error(message);
    p.bump();
    expressions::expr_block_contents(p);
    p.eat(R_CURLY);
    m.complete(p, ERROR);
}
<commit_msg>Add extern_crate_self to ra_parser.<commit_after>//! This is the actual "grammar" of the Rust language.
//!
//! Each function in this module and its children corresponds
//! to a production of the format grammar. Submodules roughly
//! correspond to different *areas* of the grammar. By convention,
//! each submodule starts with `use super::*` import and exports
//! "public" productions via `pub(super)`.
//!
//! See docs for `Parser` to learn about API, available to the grammar,
//! and see docs for `Event` to learn how this actually manages to
//! produce parse trees.
//!
//! Code in this module also contains inline tests, which start with
//! `// test name-of-the-test` comment and look like this:
//!
//! ```
//! // test function_with_zero_parameters
//! // fn foo() {}
//! ```
//!
//! After adding a new inline-test, run `cargo collect-tests` to extract
//! it as a standalone text-fixture into `tests/data/parser/inline`, and
//! run `cargo test` once to create the "gold" value.
//!
//! Coding convention: rules like `where_clause` always produce either a
//! node or an error, rules like `opt_where_clause` may produce nothing.
//! Non-opt rules typically start with `assert!(p.at(FIRST_TOKEN))`, the
//! caller is responsible for branching on the first token.
mod attributes;
mod expressions;
mod items;
mod params;
mod paths;
mod patterns;
mod type_args;
mod type_params;
mod types;

use crate::{
    SyntaxKind::{self, *},
    TokenSet,
    parser::{CompletedMarker, Marker, Parser},
};

pub(crate) fn root(p: &mut Parser) {
    let m = p.start();
    p.eat(SHEBANG);
    items::mod_contents(p, false);
    m.complete(p, SOURCE_FILE);
}

pub(crate) fn reparser(
    node: SyntaxKind,
    first_child: Option<SyntaxKind>,
    parent: Option<SyntaxKind>,
) -> Option<fn(&mut Parser)> {
    let res = match node {
        BLOCK => expressions::block,
        NAMED_FIELD_DEF_LIST => items::named_field_def_list,
        NAMED_FIELD_LIST => items::named_field_list,
        ENUM_VARIANT_LIST => items::enum_variant_list,
        MATCH_ARM_LIST => items::match_arm_list,
        USE_TREE_LIST => items::use_tree_list,
        EXTERN_ITEM_LIST => items::extern_item_list,
        TOKEN_TREE if first_child? == L_CURLY => items::token_tree,
        ITEM_LIST => match parent? {
            IMPL_BLOCK => items::impl_item_list,
            TRAIT_DEF => items::trait_item_list,
            MODULE => items::mod_item_list,
            _ => return None,
        },
        _ => return None,
    };
    Some(res)
}

#[derive(Clone, Copy, PartialEq, Eq)]
enum BlockLike {
    Block,
    NotBlock,
}

impl BlockLike {
    fn is_block(self) -> bool {
        self == BlockLike::Block
    }
}

fn opt_visibility(p: &mut Parser) -> bool {
    match p.current() {
        PUB_KW => {
            let m = p.start();
            p.bump();
            if p.at(L_PAREN) {
                match p.nth(1) {
                    // test crate_visibility
                    // pub(crate) struct S;
                    // pub(self) struct S;
                    // pub(self) struct S;
                    // pub(self) struct S;
                    CRATE_KW | SELF_KW | SUPER_KW => {
                        p.bump();
                        p.bump();
                        p.expect(R_PAREN);
                    }
                    IN_KW => {
                        p.bump();
                        p.bump();
                        paths::use_path(p);
                        p.expect(R_PAREN);
                    }
                    _ => (),
                }
            }
            m.complete(p, VISIBILITY);
        }
        // test crate_keyword_vis
        // crate fn main() { }
        // struct S { crate field: u32 }
        // struct T(crate u32);
        //
        // test crate_keyword_path
        // fn foo() { crate::foo(); }
        CRATE_KW if p.nth(1) != COLONCOLON => {
            let m = p.start();
            p.bump();
            m.complete(p, VISIBILITY);
        }
        _ => return false,
    }
    true
}

fn opt_alias(p: &mut Parser) {
    if p.at(AS_KW) {
        let m = p.start();
        p.bump();
        if !p.eat(UNDERSCORE) {
            name(p);
        }
        m.complete(p, ALIAS);
    }
}

fn abi(p: &mut Parser) {
    assert!(p.at(EXTERN_KW));
    let abi = p.start();
    p.bump();
    match p.current() {
        STRING | RAW_STRING => p.bump(),
        _ => (),
    }
    abi.complete(p, ABI);
}

fn opt_fn_ret_type(p: &mut Parser) -> bool {
    if p.at(THIN_ARROW) {
        let m = p.start();
        p.bump();
        types::type_(p);
        m.complete(p, RET_TYPE);
        true
    } else {
        false
    }
}

fn name_r(p: &mut Parser, recovery: TokenSet) {
    if p.at(IDENT) {
        let m = p.start();
        p.bump();
        m.complete(p, NAME);
    } else {
        p.err_recover("expected a name", recovery);
    }
}

fn name(p: &mut Parser) {
    name_r(p, TokenSet::empty())
}

fn name_ref(p: &mut Parser) {
    if p.at(IDENT) {
        let m = p.start();
        p.bump();
        m.complete(p, NAME_REF);
    } else if p.at(SELF_KW) {
        let m = p.start();
        p.bump();
        m.complete(p, SELF_KW);
    } else {
        p.err_and_bump("expected identifier");
    }
}

fn error_block(p: &mut Parser, message: &str) {
    assert!(p.at(L_CURLY));
    let m = p.start();
    p.error(message);
    p.bump();
    expressions::expr_block_contents(p);
    p.eat(R_CURLY);
    m.complete(p, ERROR);
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// 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 std::env;
use std::ffi::OsString;

use hcore::os::process;
use hcore::package::{PackageIdent, PackageInstall};
use hcore::fs::find_command;

use error::{Error, Result};

pub fn start(ident: &PackageIdent, command: &str, args: Vec<OsString>) -> Result<()> {
    let pkg_install = try!(PackageInstall::load(&ident, None));
    let env_path = try!(pkg_install.runtime_path());
    info!("Setting: PATH='{}'", &env_path);
    env::set_var("PATH", env_path);
    let command = match find_command(command) {
        Some(path) => path,
        None => return Err(Error::ExecCommandNotFound(command.to_string())),
    };
    let mut display_args = command.to_string_lossy().into_owned();
    for arg in &args {
        display_args.push(' ');
        display_args.push_str(arg.to_string_lossy().as_ref());
    }
    info!("Running: {}", display_args);
    Ok(try!(process::become_command(command, args)))
}
<commit_msg>Add support for setting runtime environment<commit_after>// Copyright (c) 2016 Chef Software Inc. and/or applicable contributors
//
// 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 std::env;
use std::ffi::OsString;

use hcore::os::process;
use hcore::package::{PackageIdent, PackageInstall};
use hcore::fs::find_command;

use error::{Error, Result};

pub fn start(ident: &PackageIdent, command: &str, args: Vec<OsString>) -> Result<()> {
    let pkg_install = PackageInstall::load(&ident, None)?;
    let run_env = pkg_install.runtime_environment()?;
    for (key, value) in run_env.into_iter() {
        info!("Setting: {}='{}'", key, value);
        env::set_var(key, value);
    }
    let command = match find_command(command) {
        Some(path) => path,
        None => return Err(Error::ExecCommandNotFound(command.to_string())),
    };
    let mut display_args = command.to_string_lossy().into_owned();
    for arg in &args {
        display_args.push(' ');
        display_args.push_str(arg.to_string_lossy().as_ref());
    }
    info!("Running: {}", display_args);
    Ok(process::become_command(command, args)?)
}
<|endoftext|>


<commit_before>#![no_std]

use core::fmt;
use core::marker::PhantomData;
use libtock_platform as platform;
use libtock_platform::allow_ro::AllowRo;
use libtock_platform::allow_rw::AllowRw;
use libtock_platform::share;
use libtock_platform::subscribe::Subscribe;
use libtock_platform::{DefaultConfig, ErrorCode, Syscalls};

/// The console driver.
///
/// It allows libraries to pass strings to the kernel's console driver.
///
/// # Example
/// ```ignore
/// use libtock2::Console;
///
/// // Writes "foo", followed by a newline, to the console
/// let mut writer = Console::writer();
/// writeln!(writer, foo).unwrap();
/// ```
pub struct Console<
    S: Syscalls,
    C: platform::allow_ro::Config
        + platform::allow_rw::Config
        + platform::subscribe::Config
        = DefaultConfig,
>(S, C);

impl<
        S: Syscalls,
        C: platform::allow_ro::Config + platform::allow_rw::Config + platform::subscribe::Config,
    > Console<S, C>
{
    /// Run a check against the console capsule to ensure it is present.
    ///
    /// Returns `true` if the driver was present. This does not necessarily mean
    /// that the driver is working, as it may still fail to allocate grant
    /// memory.
    #[inline(always)]
    pub fn driver_check() -> bool {
        S::command(DRIVER_NUM, command::DRIVER_CHECK, 0, 0).is_success()
    }

    /// Writes bytes.
    /// This is an alternative to `fmt::Write::write`
    /// because this can actually return an error code.
    pub fn write(s: &[u8]) -> Result<(), ErrorCode> {
        let called = core::cell::Cell::new(Option::<(u32,)>::None);
        share::scope::<
            (
                AllowRo<_, DRIVER_NUM, { allow_ro::WRITE }>,
                Subscribe<_, DRIVER_NUM, { subscribe::WRITE }>,
            ),
            _,
            _,
        >(|handle| {
            let (allow_ro, subscribe) = handle.split();

            S::allow_ro::<C, DRIVER_NUM, { allow_ro::WRITE }>(allow_ro, s)?;

            S::subscribe::<_, _, C, DRIVER_NUM, { subscribe::WRITE }>(subscribe, &called)?;

            S::command(DRIVER_NUM, command::WRITE, s.len() as u32, 0).to_result()?;

            loop {
                S::yield_wait();
                if let Some((_,)) = called.get() {
                    return Ok(());
                }
            }
        })
    }

    /// Reads bytes
    /// Reads from the device and writes to `buf`, starting from index 0.
    /// No special guarantees about when the read stops.
    /// Returns count of bytes written to `buf`.
    pub fn read(buf: &mut [u8]) -> (usize, Result<(), ErrorCode>) {
        let called = core::cell::Cell::new(Option::<(u32, u32)>::None);
        let mut bytes_received = 0;
        let r = share::scope::<
            (
                AllowRw<_, DRIVER_NUM, { allow_rw::READ }>,
                Subscribe<_, DRIVER_NUM, { subscribe::READ }>,
            ),
            _,
            _,
        >(|handle| {
            let (allow_rw, subscribe) = handle.split();
            let len = buf.len();
            S::allow_rw::<C, DRIVER_NUM, { allow_rw::READ }>(allow_rw, buf)?;
            S::subscribe::<_, _, C, DRIVER_NUM, { subscribe::READ }>(subscribe, &called)?;

            // When this fails, `called` is guaranteed unmodified,
            // because upcalls are never processed until we call `yield`.
            S::command(DRIVER_NUM, command::READ, len as u32, 0).to_result()?;

            loop {
                S::yield_wait();
                if let Some((status, bytes_pushed_count)) = called.get() {
                    bytes_received = bytes_pushed_count as usize;
                    return match status {
                        0 => Ok(()),
                        e_status => Err(e_status.try_into().unwrap_or(ErrorCode::Fail)),
                    };
                }
            }
        });
        (bytes_received, r)
    }

    pub fn writer() -> ConsoleWriter<S> {
        ConsoleWriter {
            syscalls: Default::default(),
        }
    }
}

pub struct ConsoleWriter<S: Syscalls> {
    syscalls: PhantomData<S>,
}

impl<S: Syscalls> fmt::Write for ConsoleWriter<S> {
    fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
        Console::<S>::write(s.as_bytes()).map_err(|_e| fmt::Error)
    }
}

#[cfg(test)]
mod tests;

// -----------------------------------------------------------------------------
// Driver number and command IDs
// -----------------------------------------------------------------------------

const DRIVER_NUM: u32 = 1;

// Command IDs
#[allow(unused)]
mod command {
    pub const DRIVER_CHECK: u32 = 0;
    pub const WRITE: u32 = 1;
    pub const READ: u32 = 2;
    pub const ABORT: u32 = 3;
}

#[allow(unused)]
mod subscribe {
    pub const WRITE: u32 = 1;
    pub const READ: u32 = 2;
}

mod allow_ro {
    pub const WRITE: u32 = 1;
}

mod allow_rw {
    pub const READ: u32 = 1;
}
<commit_msg>Console: create a `Config` trait that aliases the Allow RO/Allow RW/Subscribe config traits.<commit_after>#![no_std]

use core::fmt;
use core::marker::PhantomData;
use libtock_platform as platform;
use libtock_platform::allow_ro::AllowRo;
use libtock_platform::allow_rw::AllowRw;
use libtock_platform::share;
use libtock_platform::subscribe::Subscribe;
use libtock_platform::{DefaultConfig, ErrorCode, Syscalls};

/// The console driver.
///
/// It allows libraries to pass strings to the kernel's console driver.
///
/// # Example
/// ```ignore
/// use libtock2::Console;
///
/// // Writes "foo", followed by a newline, to the console
/// let mut writer = Console::writer();
/// writeln!(writer, foo).unwrap();
/// ```
pub struct Console<S: Syscalls, C: Config = DefaultConfig>(S, C);

impl<S: Syscalls, C: Config> Console<S, C> {
    /// Run a check against the console capsule to ensure it is present.
    ///
    /// Returns `true` if the driver was present. This does not necessarily mean
    /// that the driver is working, as it may still fail to allocate grant
    /// memory.
    #[inline(always)]
    pub fn driver_check() -> bool {
        S::command(DRIVER_NUM, command::DRIVER_CHECK, 0, 0).is_success()
    }

    /// Writes bytes.
    /// This is an alternative to `fmt::Write::write`
    /// because this can actually return an error code.
    pub fn write(s: &[u8]) -> Result<(), ErrorCode> {
        let called = core::cell::Cell::new(Option::<(u32,)>::None);
        share::scope::<
            (
                AllowRo<_, DRIVER_NUM, { allow_ro::WRITE }>,
                Subscribe<_, DRIVER_NUM, { subscribe::WRITE }>,
            ),
            _,
            _,
        >(|handle| {
            let (allow_ro, subscribe) = handle.split();

            S::allow_ro::<C, DRIVER_NUM, { allow_ro::WRITE }>(allow_ro, s)?;

            S::subscribe::<_, _, C, DRIVER_NUM, { subscribe::WRITE }>(subscribe, &called)?;

            S::command(DRIVER_NUM, command::WRITE, s.len() as u32, 0).to_result()?;

            loop {
                S::yield_wait();
                if let Some((_,)) = called.get() {
                    return Ok(());
                }
            }
        })
    }

    /// Reads bytes
    /// Reads from the device and writes to `buf`, starting from index 0.
    /// No special guarantees about when the read stops.
    /// Returns count of bytes written to `buf`.
    pub fn read(buf: &mut [u8]) -> (usize, Result<(), ErrorCode>) {
        let called = core::cell::Cell::new(Option::<(u32, u32)>::None);
        let mut bytes_received = 0;
        let r = share::scope::<
            (
                AllowRw<_, DRIVER_NUM, { allow_rw::READ }>,
                Subscribe<_, DRIVER_NUM, { subscribe::READ }>,
            ),
            _,
            _,
        >(|handle| {
            let (allow_rw, subscribe) = handle.split();
            let len = buf.len();
            S::allow_rw::<C, DRIVER_NUM, { allow_rw::READ }>(allow_rw, buf)?;
            S::subscribe::<_, _, C, DRIVER_NUM, { subscribe::READ }>(subscribe, &called)?;

            // When this fails, `called` is guaranteed unmodified,
            // because upcalls are never processed until we call `yield`.
            S::command(DRIVER_NUM, command::READ, len as u32, 0).to_result()?;

            loop {
                S::yield_wait();
                if let Some((status, bytes_pushed_count)) = called.get() {
                    bytes_received = bytes_pushed_count as usize;
                    return match status {
                        0 => Ok(()),
                        e_status => Err(e_status.try_into().unwrap_or(ErrorCode::Fail)),
                    };
                }
            }
        });
        (bytes_received, r)
    }

    pub fn writer() -> ConsoleWriter<S> {
        ConsoleWriter {
            syscalls: Default::default(),
        }
    }
}

pub struct ConsoleWriter<S: Syscalls> {
    syscalls: PhantomData<S>,
}

impl<S: Syscalls> fmt::Write for ConsoleWriter<S> {
    fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
        Console::<S>::write(s.as_bytes()).map_err(|_e| fmt::Error)
    }
}

/// System call configuration trait for `Console`.
pub trait Config:
    platform::allow_ro::Config + platform::allow_rw::Config + platform::subscribe::Config
{
}
impl<T: platform::allow_ro::Config + platform::allow_rw::Config + platform::subscribe::Config>
    Config for T
{
}

#[cfg(test)]
mod tests;

// -----------------------------------------------------------------------------
// Driver number and command IDs
// -----------------------------------------------------------------------------

const DRIVER_NUM: u32 = 1;

// Command IDs
#[allow(unused)]
mod command {
    pub const DRIVER_CHECK: u32 = 0;
    pub const WRITE: u32 = 1;
    pub const READ: u32 = 2;
    pub const ABORT: u32 = 3;
}

#[allow(unused)]
mod subscribe {
    pub const WRITE: u32 = 1;
    pub const READ: u32 = 2;
}

mod allow_ro {
    pub const WRITE: u32 = 1;
}

mod allow_rw {
    pub const READ: u32 = 1;
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

use libra_config::config::{PersistableConfig, HANDSHAKE_VERSION};
use libra_network_address::NetworkAddress;
use libra_secure_json_rpc::JsonRpcClient;
use libra_types::{
    account_config::libra_root_address, on_chain_config::ValidatorSet,
    validator_info::ValidatorInfo, PeerId,
};
use std::{collections::HashMap, convert::TryFrom, path::PathBuf};
use structopt::StructOpt;

// TODO: Use the definition from network?
pub type SeedPeersConfig = HashMap<PeerId, Vec<NetworkAddress>>;

#[allow(clippy::large_enum_variant)]
#[derive(Debug, StructOpt)]
#[structopt(about = "Tool to generate configs from chain")]
struct Args {
    #[structopt(short = "o", long, parse(from_os_str))]
    /// The output directory
    output_dir: PathBuf,
    #[structopt(short = "e", long)]
    /// JSON RPC endpoint
    endpoint: String,
}

fn main() {
    let args = Args::from_args();
    let validator_set = get_validator_set(args.endpoint, libra_root_address())
        .unwrap()
        .expect("No validator set found.");

    // Collect the validators
    let seed_peers_config = validator_set
        .payload()
        .iter()
        .map(|v| to_seed_peer(v))
        .collect::<SeedPeersConfig>();

    // Save to a file for loading later
    seed_peers_config
        .save_config(args.output_dir.join("seed_peers.yaml"))
        .expect("Unable to save seed peers config");
}

/// Retrieve validator set from the JSON-RPC endpoint
fn get_validator_set(endpoint: String, peer_id: PeerId) -> anyhow::Result<Option<ValidatorSet>> {
    let json_rpc = JsonRpcClient::new(endpoint);
    let account_state = json_rpc.get_account_state(peer_id, None)?;
    Ok(account_state.get_validator_set()?)
}

/// Convert ValidatorInfo to a seed peer
fn to_seed_peer(validator_info: &ValidatorInfo) -> (PeerId, Vec<NetworkAddress>) {
    let peer_id = *validator_info.account_address();
    let seed_pubkey = validator_info.network_identity_public_key();
    let network_addr =
        NetworkAddress::try_from(&validator_info.config().full_node_network_address).unwrap();
    let seed_addr = network_addr.append_prod_protos(seed_pubkey, HANDSHAKE_VERSION);
    (peer_id, vec![seed_addr])
}
<commit_msg>[network] Remove duplicate protocols in seed-peer generation<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

#![forbid(unsafe_code)]

use libra_config::config::PersistableConfig;
use libra_logger::prelude::*;
use libra_network_address::NetworkAddress;
use libra_secure_json_rpc::JsonRpcClient;
use libra_types::{
    account_config::libra_root_address, on_chain_config::ValidatorSet,
    validator_info::ValidatorInfo, PeerId,
};
use std::{collections::HashMap, convert::TryFrom, path::PathBuf};
use structopt::StructOpt;

// TODO: Use the definition from network?
pub type SeedPeersConfig = HashMap<PeerId, Vec<NetworkAddress>>;

#[allow(clippy::large_enum_variant)]
#[derive(Debug, StructOpt)]
#[structopt(about = "Tool to generate configs from chain")]
struct Args {
    #[structopt(short = "o", long, parse(from_os_str))]
    /// The output directory
    output_dir: PathBuf,
    #[structopt(short = "e", long)]
    /// JSON RPC endpoint
    endpoint: String,
}

fn main() {
    let args = Args::from_args();
    let validator_set = get_validator_set(args.endpoint, libra_root_address())
        .unwrap()
        .expect("No validator set found.");

    // Collect the validators
    let seed_peers_config = validator_set
        .payload()
        .iter()
        .filter_map(|v| match to_seed_peer(v) {
            Ok(result) => Some(result),
            Err(error) => {
                warn!(
                    "Unable to read peer id for validator {} {}",
                    v.account_address(),
                    error
                );
                None
            }
        })
        .collect::<SeedPeersConfig>();

    // Save to a file for loading later
    seed_peers_config
        .save_config(args.output_dir.join("seed_peers.yaml"))
        .expect("Unable to save seed peers config");
}

/// Retrieve validator set from the JSON-RPC endpoint
fn get_validator_set(endpoint: String, peer_id: PeerId) -> anyhow::Result<Option<ValidatorSet>> {
    let json_rpc = JsonRpcClient::new(endpoint);
    let account_state = json_rpc.get_account_state(peer_id, None)?;
    Ok(account_state.get_validator_set()?)
}

/// Convert ValidatorInfo to a seed peer
fn to_seed_peer(
    validator_info: &ValidatorInfo,
) -> Result<(PeerId, Vec<NetworkAddress>), lcs::Error> {
    let peer_id = *validator_info.account_address();
    let network_addr =
        NetworkAddress::try_from(&validator_info.config().full_node_network_address)?;
    Ok((peer_id, vec![network_addr]))
}
<|endoftext|>