<commit_before>//! API for tracing applications and libraries.
//!
//! The `trace` module includes types for tracking the progression of a single
//! request while it is handled by services that make up an application. A trace
//! is a tree of [`Span`]s which are objects that represent the work being done
//! by individual services or components involved in a request as it flows
//! through a system. This module implements the OpenTelemetry [trace
//! specification].
//!
//! [trace specification]: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.3.0/specification/trace/api.md
//!
//! ## Getting Started
//!
//! In application code:
//!
//! ```
//! use opentelemetry_api::trace::{Tracer, noop::NoopTracerProvider};
//! use opentelemetry_api::global;
//!
//! fn init_tracer() {
//!     // Swap this no-op provider for your tracing service of choice (jaeger, zipkin, etc)
//!     let provider = NoopTracerProvider::new();
//!
//!     // Configure the global `TracerProvider` singleton when your app starts
//!     // (there is a no-op default if this is not set by your application)
//!     let _ = global::set_tracer_provider(provider);
//! }
//!
//! fn do_something_tracked() {
//!     // Then you can get a named tracer instance anywhere in your codebase.
//!     let tracer = global::tracer("my-component");
//!
//!     tracer.in_span("doing_work", |cx| {
//!         // Traced app logic here...
//!     });
//! }
//!
//! // in main or other app start
//! init_tracer();
//! do_something_tracked();
//! ```
//!
//! In library code:
//!
//! ```
//! use opentelemetry_api::{global, trace::{Span, Tracer, TracerProvider}};
//!
//! fn my_library_function() {
//!     // Use the global tracer provider to get access to the user-specified
//!     // tracer configuration
//!     let tracer_provider = global::tracer_provider();
//!
//!     // Get a tracer for this library
//!     let tracer = tracer_provider.versioned_tracer(
//!         "my_name",
//!         Some(env!("CARGO_PKG_VERSION")),
//!         None
//!     );
//!
//!     // Create spans
//!     let mut span = tracer.start("doing_work");
//!
//!     // Do work...
//!
//!     // End the span
//!     span.end();
//! }
//! ```
//!
//! ## Overview
//!
//! The tracing API consists of a three main traits:
//!
//! * [`TracerProvider`]s are the entry point of the API. They provide access to
//!   `Tracer`s.
//! * [`Tracer`]s are types responsible for creating `Span`s.
//! * [`Span`]s provide the API to trace an operation.
//!
//! ## Working with Async Runtimes
//!
//! Exporting spans often involves sending data over a network or performing
//! other I/O tasks. OpenTelemetry allows you to schedule these tasks using
//! whichever runtime you area already using such as [Tokio] or [async-std].
//! When using an async runtime it's best to use the batch span processor
//! where the spans will be sent in batches as opposed to being sent once ended,
//! which often ends up being more efficient.
//!
//! [Tokio]: https://tokio.rs
//! [async-std]: https://async.rs
//!
//! ## Managing Active Spans
//!
//! Spans can be marked as "active" for a given [`Context`], and all newly
//! created spans will automatically be children of the currently active span.
//!
//! The active span for a given thread can be managed via [`get_active_span`]
//! and [`mark_span_as_active`].
//!
//! [`Context`]: crate::Context
//!
//! ```
//! use opentelemetry_api::{global, trace::{self, Span, Status, Tracer, TracerProvider}};
//!
//! fn may_error(rand: f32) {
//!     if rand < 0.5 {
//!         // Get the currently active span to record additional attributes,
//!         // status, etc.
//!         trace::get_active_span(|span| {
//!             span.set_status(Status::error("value too small"));
//!         });
//!     }
//! }
//!
//! // Get a tracer
//! let tracer = global::tracer("my_tracer");
//!
//! // Create a span
//! let span = tracer.start("parent_span");
//!
//! // Mark the span as active
//! let active = trace::mark_span_as_active(span);
//!
//! // Any span created here will be a child of `parent_span`...
//!
//! // Drop the guard and the span will no longer be active
//! drop(active)
//! ```
//!
//! Additionally [`Tracer::in_span`] can be used as shorthand to simplify
//! managing the parent context.
//!
//! ```
//! use opentelemetry_api::{global, trace::Tracer};
//!
//! // Get a tracer
//! let tracer = global::tracer("my_tracer");
//!
//! // Use `in_span` to create a new span and mark it as the parent, dropping it
//! // at the end of the block.
//! tracer.in_span("parent_span", |cx| {
//!     // spans created here will be children of `parent_span`
//! });
//! ```
//!
//! #### Async active spans
//!
//! Async spans can be propagated with [`TraceContextExt`] and [`FutureExt`].
//!
//! ```
//! use opentelemetry_api::{Context, global, trace::{FutureExt, TraceContextExt, Tracer}};
//!
//! async fn some_work() { }
//!
//! // Get a tracer
//! let tracer = global::tracer("my_tracer");
//!
//! // Start a span
//! let span = tracer.start("my_span");
//!
//! // Perform some async work with this span as the currently active parent.
//! some_work().with_context(Context::current_with_span(span));
//! ```

use futures_channel::{mpsc::TrySendError, oneshot::Canceled};
use std::borrow::Cow;
use std::time;
use thiserror::Error;

mod context;
pub mod noop;
mod order_map;
mod span;
mod span_context;
mod tracer;
mod tracer_provider;

pub use self::{
    context::{get_active_span, mark_span_as_active, FutureExt, SpanRef, TraceContextExt},
    order_map::OrderMap,
    span::{Span, SpanKind, Status},
    span_context::{SpanContext, SpanId, TraceFlags, TraceId, TraceState},
    tracer::{SamplingDecision, SamplingResult, SpanBuilder, Tracer},
    tracer_provider::TracerProvider,
};
use crate::{ExportError, KeyValue};

/// Describe the result of operations in tracing API.
pub type TraceResult<T> = Result<T, TraceError>;

/// Errors returned by the trace API.
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum TraceError {
    /// Export failed with the error returned by the exporter
    #[error("Exporter {} encountered the following error(s): {0}", .0.exporter_name())]
    ExportFailed(Box<dyn ExportError>),

    /// Export failed to finish after certain period and processor stopped the export.
    #[error("Exporting timed out after {} seconds", .0.as_secs())]
    ExportTimedOut(time::Duration),

    /// Other errors propagated from trace SDK that weren't covered above
    #[error(transparent)]
    Other(#[from] Box<dyn std::error::Error + Send + Sync + 'static>),
}

impl<T> From<T> for TraceError
where
    T: ExportError,
{
    fn from(err: T) -> Self {
        TraceError::ExportFailed(Box::new(err))
    }
}

impl<T> From<TrySendError<T>> for TraceError {
    fn from(err: TrySendError<T>) -> Self {
        TraceError::Other(Box::new(err.into_send_error()))
    }
}

impl From<Canceled> for TraceError {
    fn from(err: Canceled) -> Self {
        TraceError::Other(Box::new(err))
    }
}

impl From<String> for TraceError {
    fn from(err_msg: String) -> Self {
        TraceError::Other(Box::new(Custom(err_msg)))
    }
}

impl From<&'static str> for TraceError {
    fn from(err_msg: &'static str) -> Self {
        TraceError::Other(Box::new(Custom(err_msg.into())))
    }
}

/// Wrap type for string
#[derive(Error, Debug)]
#[error("{0}")]
struct Custom(String);

/// Events record things that happened during a [`Span`]'s lifetime.
#[non_exhaustive]
#[derive(Clone, Debug, PartialEq)]
pub struct Event {
    /// The name of this event.
    pub name: Cow<'static, str>,

    /// The time at which this event occurred.
    pub timestamp: time::SystemTime,

    /// Attributes that describe this event.
    pub attributes: Vec<KeyValue>,

    /// The number of attributes that were above the configured limit, and thus
    /// dropped.
    pub dropped_attributes_count: u32,
}

impl Event {
    /// Create new `Event`
    pub fn new<T: Into<Cow<'static, str>>>(
        name: T,
        timestamp: time::SystemTime,
        attributes: Vec<KeyValue>,
        dropped_attributes_count: u32,
    ) -> Self {
        Event {
            name: name.into(),
            timestamp,
            attributes,
            dropped_attributes_count,
        }
    }

    /// Create new `Event` with a given name.
    pub fn with_name<T: Into<Cow<'static, str>>>(name: T) -> Self {
        Event {
            name: name.into(),
            timestamp: crate::time::now(),
            attributes: Vec::new(),
            dropped_attributes_count: 0,
        }
    }
}

/// Link is the relationship between two Spans.
///
/// The relationship can be within the same trace or across different traces.
#[non_exhaustive]
#[derive(Clone, Debug, PartialEq)]
pub struct Link {
    /// The span context of the linked span.
    pub span_context: SpanContext,

    /// Attributes that describe this link.
    pub attributes: Vec<KeyValue>,

    /// The number of attributes that were above the configured limit, and thus
    /// dropped.
    pub dropped_attributes_count: u32,
}

impl Link {
    /// Create a new link.
    pub fn new(span_context: SpanContext, attributes: Vec<KeyValue>) -> Self {
        Link {
            span_context,
            attributes,
            dropped_attributes_count: 0,
        }
    }
}
<commit_msg>added WithContext to the public api of opentelemetry-api (#893)<commit_after>//! API for tracing applications and libraries.
//!
//! The `trace` module includes types for tracking the progression of a single
//! request while it is handled by services that make up an application. A trace
//! is a tree of [`Span`]s which are objects that represent the work being done
//! by individual services or components involved in a request as it flows
//! through a system. This module implements the OpenTelemetry [trace
//! specification].
//!
//! [trace specification]: https://github.com/open-telemetry/opentelemetry-specification/blob/v1.3.0/specification/trace/api.md
//!
//! ## Getting Started
//!
//! In application code:
//!
//! ```
//! use opentelemetry_api::trace::{Tracer, noop::NoopTracerProvider};
//! use opentelemetry_api::global;
//!
//! fn init_tracer() {
//!     // Swap this no-op provider for your tracing service of choice (jaeger, zipkin, etc)
//!     let provider = NoopTracerProvider::new();
//!
//!     // Configure the global `TracerProvider` singleton when your app starts
//!     // (there is a no-op default if this is not set by your application)
//!     let _ = global::set_tracer_provider(provider);
//! }
//!
//! fn do_something_tracked() {
//!     // Then you can get a named tracer instance anywhere in your codebase.
//!     let tracer = global::tracer("my-component");
//!
//!     tracer.in_span("doing_work", |cx| {
//!         // Traced app logic here...
//!     });
//! }
//!
//! // in main or other app start
//! init_tracer();
//! do_something_tracked();
//! ```
//!
//! In library code:
//!
//! ```
//! use opentelemetry_api::{global, trace::{Span, Tracer, TracerProvider}};
//!
//! fn my_library_function() {
//!     // Use the global tracer provider to get access to the user-specified
//!     // tracer configuration
//!     let tracer_provider = global::tracer_provider();
//!
//!     // Get a tracer for this library
//!     let tracer = tracer_provider.versioned_tracer(
//!         "my_name",
//!         Some(env!("CARGO_PKG_VERSION")),
//!         None
//!     );
//!
//!     // Create spans
//!     let mut span = tracer.start("doing_work");
//!
//!     // Do work...
//!
//!     // End the span
//!     span.end();
//! }
//! ```
//!
//! ## Overview
//!
//! The tracing API consists of a three main traits:
//!
//! * [`TracerProvider`]s are the entry point of the API. They provide access to
//!   `Tracer`s.
//! * [`Tracer`]s are types responsible for creating `Span`s.
//! * [`Span`]s provide the API to trace an operation.
//!
//! ## Working with Async Runtimes
//!
//! Exporting spans often involves sending data over a network or performing
//! other I/O tasks. OpenTelemetry allows you to schedule these tasks using
//! whichever runtime you area already using such as [Tokio] or [async-std].
//! When using an async runtime it's best to use the batch span processor
//! where the spans will be sent in batches as opposed to being sent once ended,
//! which often ends up being more efficient.
//!
//! [Tokio]: https://tokio.rs
//! [async-std]: https://async.rs
//!
//! ## Managing Active Spans
//!
//! Spans can be marked as "active" for a given [`Context`], and all newly
//! created spans will automatically be children of the currently active span.
//!
//! The active span for a given thread can be managed via [`get_active_span`]
//! and [`mark_span_as_active`].
//!
//! [`Context`]: crate::Context
//!
//! ```
//! use opentelemetry_api::{global, trace::{self, Span, Status, Tracer, TracerProvider}};
//!
//! fn may_error(rand: f32) {
//!     if rand < 0.5 {
//!         // Get the currently active span to record additional attributes,
//!         // status, etc.
//!         trace::get_active_span(|span| {
//!             span.set_status(Status::error("value too small"));
//!         });
//!     }
//! }
//!
//! // Get a tracer
//! let tracer = global::tracer("my_tracer");
//!
//! // Create a span
//! let span = tracer.start("parent_span");
//!
//! // Mark the span as active
//! let active = trace::mark_span_as_active(span);
//!
//! // Any span created here will be a child of `parent_span`...
//!
//! // Drop the guard and the span will no longer be active
//! drop(active)
//! ```
//!
//! Additionally [`Tracer::in_span`] can be used as shorthand to simplify
//! managing the parent context.
//!
//! ```
//! use opentelemetry_api::{global, trace::Tracer};
//!
//! // Get a tracer
//! let tracer = global::tracer("my_tracer");
//!
//! // Use `in_span` to create a new span and mark it as the parent, dropping it
//! // at the end of the block.
//! tracer.in_span("parent_span", |cx| {
//!     // spans created here will be children of `parent_span`
//! });
//! ```
//!
//! #### Async active spans
//!
//! Async spans can be propagated with [`TraceContextExt`] and [`FutureExt`].
//!
//! ```
//! use opentelemetry_api::{Context, global, trace::{FutureExt, TraceContextExt, Tracer}};
//!
//! async fn some_work() { }
//!
//! // Get a tracer
//! let tracer = global::tracer("my_tracer");
//!
//! // Start a span
//! let span = tracer.start("my_span");
//!
//! // Perform some async work with this span as the currently active parent.
//! some_work().with_context(Context::current_with_span(span));
//! ```

use futures_channel::{mpsc::TrySendError, oneshot::Canceled};
use std::borrow::Cow;
use std::time;
use thiserror::Error;

mod context;
pub mod noop;
mod order_map;
mod span;
mod span_context;
mod tracer;
mod tracer_provider;

pub use self::{
    context::{
        get_active_span, mark_span_as_active, FutureExt, SpanRef, TraceContextExt, WithContext,
    },
    order_map::OrderMap,
    span::{Span, SpanKind, Status},
    span_context::{SpanContext, SpanId, TraceFlags, TraceId, TraceState},
    tracer::{SamplingDecision, SamplingResult, SpanBuilder, Tracer},
    tracer_provider::TracerProvider,
};
use crate::{ExportError, KeyValue};

/// Describe the result of operations in tracing API.
pub type TraceResult<T> = Result<T, TraceError>;

/// Errors returned by the trace API.
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum TraceError {
    /// Export failed with the error returned by the exporter
    #[error("Exporter {} encountered the following error(s): {0}", .0.exporter_name())]
    ExportFailed(Box<dyn ExportError>),

    /// Export failed to finish after certain period and processor stopped the export.
    #[error("Exporting timed out after {} seconds", .0.as_secs())]
    ExportTimedOut(time::Duration),

    /// Other errors propagated from trace SDK that weren't covered above
    #[error(transparent)]
    Other(#[from] Box<dyn std::error::Error + Send + Sync + 'static>),
}

impl<T> From<T> for TraceError
where
    T: ExportError,
{
    fn from(err: T) -> Self {
        TraceError::ExportFailed(Box::new(err))
    }
}

impl<T> From<TrySendError<T>> for TraceError {
    fn from(err: TrySendError<T>) -> Self {
        TraceError::Other(Box::new(err.into_send_error()))
    }
}

impl From<Canceled> for TraceError {
    fn from(err: Canceled) -> Self {
        TraceError::Other(Box::new(err))
    }
}

impl From<String> for TraceError {
    fn from(err_msg: String) -> Self {
        TraceError::Other(Box::new(Custom(err_msg)))
    }
}

impl From<&'static str> for TraceError {
    fn from(err_msg: &'static str) -> Self {
        TraceError::Other(Box::new(Custom(err_msg.into())))
    }
}

/// Wrap type for string
#[derive(Error, Debug)]
#[error("{0}")]
struct Custom(String);

/// Events record things that happened during a [`Span`]'s lifetime.
#[non_exhaustive]
#[derive(Clone, Debug, PartialEq)]
pub struct Event {
    /// The name of this event.
    pub name: Cow<'static, str>,

    /// The time at which this event occurred.
    pub timestamp: time::SystemTime,

    /// Attributes that describe this event.
    pub attributes: Vec<KeyValue>,

    /// The number of attributes that were above the configured limit, and thus
    /// dropped.
    pub dropped_attributes_count: u32,
}

impl Event {
    /// Create new `Event`
    pub fn new<T: Into<Cow<'static, str>>>(
        name: T,
        timestamp: time::SystemTime,
        attributes: Vec<KeyValue>,
        dropped_attributes_count: u32,
    ) -> Self {
        Event {
            name: name.into(),
            timestamp,
            attributes,
            dropped_attributes_count,
        }
    }

    /// Create new `Event` with a given name.
    pub fn with_name<T: Into<Cow<'static, str>>>(name: T) -> Self {
        Event {
            name: name.into(),
            timestamp: crate::time::now(),
            attributes: Vec::new(),
            dropped_attributes_count: 0,
        }
    }
}

/// Link is the relationship between two Spans.
///
/// The relationship can be within the same trace or across different traces.
#[non_exhaustive]
#[derive(Clone, Debug, PartialEq)]
pub struct Link {
    /// The span context of the linked span.
    pub span_context: SpanContext,

    /// Attributes that describe this link.
    pub attributes: Vec<KeyValue>,

    /// The number of attributes that were above the configured limit, and thus
    /// dropped.
    pub dropped_attributes_count: u32,
}

impl Link {
    /// Create a new link.
    pub fn new(span_context: SpanContext, attributes: Vec<KeyValue>) -> Self {
        Link {
            span_context,
            attributes,
            dropped_attributes_count: 0,
        }
    }
}
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::ffi::CStr;
use sys;

/// A destination for streaming data output. By default, this is
/// a string stream, but it can be redirected to a file.
#[derive(Debug)]
pub struct SBStream {
    /// The underlying raw `SBStreamRef`.
    pub raw: sys::SBStreamRef,
}

impl SBStream {
    /// Construct a new `SBStream`.
    pub fn new() -> SBStream {
        SBStream::wrap(unsafe { sys::CreateSBStream() })
    }

    /// Construct a new `SBStream`.
    pub fn wrap(raw: sys::SBStreamRef) -> SBStream {
        SBStream { raw: raw }
    }

    /// Construct a new `Some(SBStream)` or `None`.
    pub fn maybe_wrap(raw: sys::SBStreamRef) -> Option<SBStream> {
        if unsafe { sys::SBStreamIsValid(raw) != 0 } {
            Some(SBStream { raw: raw })
        } else {
            None
        }
    }

    /// Check whether or not this is a valid `SBStream` value.
    pub fn is_valid(&self) -> bool {
        unsafe { sys::SBStreamIsValid(self.raw) != 0 }
    }

    /// If the stream is directed to a file, forget about the file and
    /// if the ownership of the file was transferred to this object,
    /// close the file. If the stream is backed by a local cache, clear
    /// this cache.
    pub fn clear(&self) {
        unsafe { sys::SBStreamClear(self.raw) }
    }

    /// If this stream is not redirected to a file, this retrieves the
    /// locally cached data.
    pub fn data(&self) -> &str {
        unsafe {
            match CStr::from_ptr(sys::SBStreamGetData(self.raw)).to_str() {
                Ok(s) => s,
                _ => panic!("Invalid string?"),
            }
        }
    }

    /// If this stream is not redirected to a file, this retrieves the
    /// length of the locally cached data.
    pub fn len(&self) -> usize {
        unsafe { sys::SBStreamGetSize(self.raw) as usize }
    }
}

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

impl Drop for SBStream {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBStream(self.raw) };
    }
}
<commit_msg>Add SBStream::is_empty to make Clippy happy.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::ffi::CStr;
use sys;

/// A destination for streaming data output. By default, this is
/// a string stream, but it can be redirected to a file.
#[derive(Debug)]
pub struct SBStream {
    /// The underlying raw `SBStreamRef`.
    pub raw: sys::SBStreamRef,
}

impl SBStream {
    /// Construct a new `SBStream`.
    pub fn new() -> SBStream {
        SBStream::wrap(unsafe { sys::CreateSBStream() })
    }

    /// Construct a new `SBStream`.
    pub fn wrap(raw: sys::SBStreamRef) -> SBStream {
        SBStream { raw: raw }
    }

    /// Construct a new `Some(SBStream)` or `None`.
    pub fn maybe_wrap(raw: sys::SBStreamRef) -> Option<SBStream> {
        if unsafe { sys::SBStreamIsValid(raw) != 0 } {
            Some(SBStream { raw: raw })
        } else {
            None
        }
    }

    /// Check whether or not this is a valid `SBStream` value.
    pub fn is_valid(&self) -> bool {
        unsafe { sys::SBStreamIsValid(self.raw) != 0 }
    }

    /// If the stream is directed to a file, forget about the file and
    /// if the ownership of the file was transferred to this object,
    /// close the file. If the stream is backed by a local cache, clear
    /// this cache.
    pub fn clear(&self) {
        unsafe { sys::SBStreamClear(self.raw) }
    }

    /// If this stream is not redirected to a file, this retrieves the
    /// locally cached data.
    pub fn data(&self) -> &str {
        unsafe {
            match CStr::from_ptr(sys::SBStreamGetData(self.raw)).to_str() {
                Ok(s) => s,
                _ => panic!("Invalid string?"),
            }
        }
    }

    /// If this stream is not redirected to a file, this retrieves the
    /// length of the locally cached data.
    pub fn len(&self) -> usize {
        unsafe { sys::SBStreamGetSize(self.raw) as usize }
    }

    /// Is this stream empty?
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }
}

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

impl Drop for SBStream {
    fn drop(&mut self) {
        unsafe { sys::DisposeSBStream(self.raw) };
    }
}
<|endoftext|>


<commit_before>use ra_assists::auto_import;
use ra_syntax::{ast, AstNode, SmolStr};
use ra_text_edit::TextEditBuilder;
use rustc_hash::FxHashMap;

use crate::completion::{CompletionContext, CompletionItem, CompletionKind, Completions};

pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
    if ctx.is_trivial_path {
        let names = ctx.analyzer.all_names(ctx.db);
        names.into_iter().for_each(|(name, res)| acc.add_resolution(ctx, name.to_string(), &res));

        // auto-import
        // We fetch ident from the original file, because we need to pre-filter auto-imports
        if ast::NameRef::cast(ctx.token.parent()).is_some() {
            let import_resolver = ImportResolver::new();
            let import_names = import_resolver.all_names(ctx.token.text());
            import_names.into_iter().for_each(|(name, path)| {
                let edit = {
                    let mut builder = TextEditBuilder::default();
                    builder.replace(ctx.source_range(), name.to_string());
                    auto_import::auto_import_text_edit(
                        &ctx.token.parent(),
                        &ctx.token.parent(),
                        &path,
                        &mut builder,
                    );
                    builder.finish()
                };

                // Hack: copied this check form conv.rs beacause auto import can produce edits
                // that invalidate assert in conv_with.
                if edit
                    .as_atoms()
                    .iter()
                    .filter(|atom| !ctx.source_range().is_subrange(&atom.delete))
                    .all(|atom| ctx.source_range().intersection(&atom.delete).is_none())
                {
                    CompletionItem::new(
                        CompletionKind::Reference,
                        ctx.source_range(),
                        build_import_label(&name, &path),
                    )
                    .text_edit(edit)
                    .add_to(acc);
                }
            });
        }
    }
}

fn build_import_label(name: &str, path: &[SmolStr]) -> String {
    let mut buf = String::with_capacity(64);
    buf.push_str(name);
    buf.push_str(" (");
    fmt_import_path(path, &mut buf);
    buf.push_str(")");
    buf
}

fn fmt_import_path(path: &[SmolStr], buf: &mut String) {
    let mut segments = path.iter();
    if let Some(s) = segments.next() {
        buf.push_str(&s);
    }
    for s in segments {
        buf.push_str("::");
        buf.push_str(&s);
    }
}

#[derive(Debug, Clone, Default)]
pub(crate) struct ImportResolver {
    // todo: use fst crate or something like that
    dummy_names: Vec<(SmolStr, Vec<SmolStr>)>,
}

impl ImportResolver {
    pub(crate) fn new() -> Self {
        let dummy_names = vec![
            (SmolStr::new("fmt"), vec![SmolStr::new("std"), SmolStr::new("fmt")]),
            (SmolStr::new("io"), vec![SmolStr::new("std"), SmolStr::new("io")]),
            (SmolStr::new("iter"), vec![SmolStr::new("std"), SmolStr::new("iter")]),
            (SmolStr::new("hash"), vec![SmolStr::new("std"), SmolStr::new("hash")]),
            (
                SmolStr::new("Debug"),
                vec![SmolStr::new("std"), SmolStr::new("fmt"), SmolStr::new("Debug")],
            ),
            (
                SmolStr::new("Display"),
                vec![SmolStr::new("std"), SmolStr::new("fmt"), SmolStr::new("Display")],
            ),
            (
                SmolStr::new("Hash"),
                vec![SmolStr::new("std"), SmolStr::new("hash"), SmolStr::new("Hash")],
            ),
            (
                SmolStr::new("Hasher"),
                vec![SmolStr::new("std"), SmolStr::new("hash"), SmolStr::new("Hasher")],
            ),
            (
                SmolStr::new("Iterator"),
                vec![SmolStr::new("std"), SmolStr::new("iter"), SmolStr::new("Iterator")],
            ),
        ];

        ImportResolver { dummy_names }
    }

    // Returns a map of importable items filtered by name.
    // The map associates item name with its full path.
    // todo: should return Resolutions
    pub(crate) fn all_names(&self, name: &str) -> FxHashMap<SmolStr, Vec<SmolStr>> {
        if name.len() > 1 {
            self.dummy_names.iter().filter(|(n, _)| n.contains(name)).cloned().collect()
        } else {
            FxHashMap::default()
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::completion::{do_completion, CompletionItem, CompletionKind};
    use insta::assert_debug_snapshot;

    fn do_reference_completion(code: &str) -> Vec<CompletionItem> {
        do_completion(code, CompletionKind::Reference)
    }

    #[test]
    fn completes_bindings_from_let() {
        assert_debug_snapshot!(
            do_reference_completion(
                r"
                fn quux(x: i32) {
                    let y = 92;
                    1 + <|>;
                    let z = ();
                }
                "
            ),
            @r###"[
    CompletionItem {
        label: "quux",
        source_range: [91; 91),
        delete: [91; 91),
        insert: "quux($0)",
        kind: Function,
        detail: "fn quux(x: i32)",
    },
    CompletionItem {
        label: "x",
        source_range: [91; 91),
        delete: [91; 91),
        insert: "x",
        kind: Binding,
        detail: "i32",
    },
    CompletionItem {
        label: "y",
        source_range: [91; 91),
        delete: [91; 91),
        insert: "y",
        kind: Binding,
        detail: "i32",
    },
]"###
        );
    }

    #[test]
    fn completes_bindings_from_if_let() {
        assert_debug_snapshot!(
            do_reference_completion(
                r"
                fn quux() {
                    if let Some(x) = foo() {
                        let y = 92;
                    };
                    if let Some(a) = bar() {
                        let b = 62;
                        1 + <|>
                    }
                }
                "
            ),
            @r###"[
    CompletionItem {
        label: "a",
        source_range: [242; 242),
        delete: [242; 242),
        insert: "a",
        kind: Binding,
    },
    CompletionItem {
        label: "b",
        source_range: [242; 242),
        delete: [242; 242),
        insert: "b",
        kind: Binding,
        detail: "i32",
    },
    CompletionItem {
        label: "quux",
        source_range: [242; 242),
        delete: [242; 242),
        insert: "quux()$0",
        kind: Function,
        detail: "fn quux()",
    },
]"###
        );
    }

    #[test]
    fn completes_bindings_from_for() {
        assert_debug_snapshot!(
            do_reference_completion(
                r"
                fn quux() {
                    for x in &[1, 2, 3] {
                        <|>
                    }
                }
                "
            ),
            @r###"[
    CompletionItem {
        label: "quux",
        source_range: [95; 95),
        delete: [95; 95),
        insert: "quux()$0",
        kind: Function,
        detail: "fn quux()",
    },
    CompletionItem {
        label: "x",
        source_range: [95; 95),
        delete: [95; 95),
        insert: "x",
        kind: Binding,
    },
]"###
        );
    }

    #[test]
    fn completes_generic_params() {
        assert_debug_snapshot!(
            do_reference_completion(
                r"
                fn quux<T>() {
                    <|>
                }
                "
            ),
            @r###"[
    CompletionItem {
        label: "T",
        source_range: [52; 52),
        delete: [52; 52),
        insert: "T",
        kind: TypeParam,
    },
    CompletionItem {
        label: "quux",
        source_range: [52; 52),
        delete: [52; 52),
        insert: "quux()$0",
        kind: Function,
        detail: "fn quux<T>()",
    },
]"###
        );
    }

    #[test]
    fn completes_generic_params_in_struct() {
        assert_debug_snapshot!(
            do_reference_completion(
                r"
                struct X<T> {
                    x: <|>
                }
                "
            ),
            @r###"[
    CompletionItem {
        label: "T",
        source_range: [54; 54),
        delete: [54; 54),
        insert: "T",
        kind: TypeParam,
    },
    CompletionItem {
        label: "X",
        source_range: [54; 54),
        delete: [54; 54),
        insert: "X",
        kind: Struct,
    },
]"###
        );
    }

    #[test]
    fn completes_module_items() {
        assert_debug_snapshot!(
        do_reference_completion(
            r"
                struct Foo;
                enum Baz {}
                fn quux() {
                    <|>
                }
                "
        ),
        @r###"[
    CompletionItem {
        label: "Baz",
        source_range: [105; 105),
        delete: [105; 105),
        insert: "Baz",
        kind: Enum,
    },
    CompletionItem {
        label: "Foo",
        source_range: [105; 105),
        delete: [105; 105),
        insert: "Foo",
        kind: Struct,
    },
    CompletionItem {
        label: "quux",
        source_range: [105; 105),
        delete: [105; 105),
        insert: "quux()$0",
        kind: Function,
        detail: "fn quux()",
    },
]"###
            );
    }

    #[test]
    fn completes_extern_prelude() {
        assert_debug_snapshot!(
            do_reference_completion(
                r"
                //- /lib.rs
                use <|>;

                //- /other_crate/lib.rs
                // nothing here
                "
            ),
            @r#"[
    CompletionItem {
        label: "other_crate",
        source_range: [4; 4),
        delete: [4; 4),
        insert: "other_crate",
        kind: Module,
    },
]"#
        );
    }

    #[test]
    fn completes_module_items_in_nested_modules() {
        assert_debug_snapshot!(
            do_reference_completion(
                r"
                struct Foo;
                mod m {
                    struct Bar;
                    fn quux() { <|> }
                }
                "
            ),
            @r###"[
    CompletionItem {
        label: "Bar",
        source_range: [117; 117),
        delete: [117; 117),
        insert: "Bar",
        kind: Struct,
    },
    CompletionItem {
        label: "quux",
        source_range: [117; 117),
        delete: [117; 117),
        insert: "quux()$0",
        kind: Function,
        detail: "fn quux()",
    },
]"###
        );
    }

    #[test]
    fn completes_return_type() {
        assert_debug_snapshot!(
            do_reference_completion(
                r"
                struct Foo;
                fn x() -> <|>
                "
            ),
            @r###"[
    CompletionItem {
        label: "Foo",
        source_range: [55; 55),
        delete: [55; 55),
        insert: "Foo",
        kind: Struct,
    },
    CompletionItem {
        label: "x",
        source_range: [55; 55),
        delete: [55; 55),
        insert: "x()$0",
        kind: Function,
        detail: "fn x()",
    },
]"###
        );
    }

    #[test]
    fn dont_show_both_completions_for_shadowing() {
        assert_debug_snapshot!(
            do_reference_completion(
                r"
                fn foo() {
                    let bar = 92;
                    {
                        let bar = 62;
                        <|>
                    }
                }
                "
            ),
            @r###"[
    CompletionItem {
        label: "bar",
        source_range: [146; 146),
        delete: [146; 146),
        insert: "bar",
        kind: Binding,
        detail: "i32",
    },
    CompletionItem {
        label: "foo",
        source_range: [146; 146),
        delete: [146; 146),
        insert: "foo()$0",
        kind: Function,
        detail: "fn foo()",
    },
]"###
        );
    }

    #[test]
    fn completes_self_in_methods() {
        assert_debug_snapshot!(
            do_reference_completion(r"impl S { fn foo(&self) { <|> } }"),
            @r#"[
    CompletionItem {
        label: "Self",
        source_range: [25; 25),
        delete: [25; 25),
        insert: "Self",
        kind: TypeParam,
    },
    CompletionItem {
        label: "self",
        source_range: [25; 25),
        delete: [25; 25),
        insert: "self",
        kind: Binding,
        detail: "&{unknown}",
    },
]"#
        );
    }

    #[test]
    fn completes_prelude() {
        assert_debug_snapshot!(
            do_reference_completion(
                "
                //- /main.rs
                fn foo() { let x: <|> }

                //- /std/lib.rs
                #[prelude_import]
                use prelude::*;

                mod prelude {
                    struct Option;
                }
                "
            ),
            @r#"[
    CompletionItem {
        label: "Option",
        source_range: [18; 18),
        delete: [18; 18),
        insert: "Option",
        kind: Struct,
    },
    CompletionItem {
        label: "foo",
        source_range: [18; 18),
        delete: [18; 18),
        insert: "foo()$0",
        kind: Function,
        detail: "fn foo()",
    },
    CompletionItem {
        label: "std",
        source_range: [18; 18),
        delete: [18; 18),
        insert: "std",
        kind: Module,
    },
]"#
        );
    }
}
<commit_msg>simplify<commit_after>use ra_assists::auto_import;
use ra_syntax::{ast, AstNode, SmolStr};
use ra_text_edit::TextEditBuilder;
use rustc_hash::FxHashMap;

use crate::completion::{CompletionContext, CompletionItem, CompletionKind, Completions};

pub(super) fn complete_scope(acc: &mut Completions, ctx: &CompletionContext) {
    if !ctx.is_trivial_path {
        return;
    }

    let names = ctx.analyzer.all_names(ctx.db);
    names.into_iter().for_each(|(name, res)| acc.add_resolution(ctx, name.to_string(), &res));

    // auto-import
    // We fetch ident from the original file, because we need to pre-filter auto-imports
    if ast::NameRef::cast(ctx.token.parent()).is_some() {
        let import_resolver = ImportResolver::new();
        let import_names = import_resolver.all_names(ctx.token.text());
        import_names.into_iter().for_each(|(name, path)| {
            let edit = {
                let mut builder = TextEditBuilder::default();
                builder.replace(ctx.source_range(), name.to_string());
                auto_import::auto_import_text_edit(
                    &ctx.token.parent(),
                    &ctx.token.parent(),
                    &path,
                    &mut builder,
                );
                builder.finish()
            };

            // Hack: copied this check form conv.rs beacause auto import can produce edits
            // that invalidate assert in conv_with.
            if edit
                .as_atoms()
                .iter()
                .filter(|atom| !ctx.source_range().is_subrange(&atom.delete))
                .all(|atom| ctx.source_range().intersection(&atom.delete).is_none())
            {
                CompletionItem::new(
                    CompletionKind::Reference,
                    ctx.source_range(),
                    build_import_label(&name, &path),
                )
                .text_edit(edit)
                .add_to(acc);
            }
        });
    }
}

fn build_import_label(name: &str, path: &[SmolStr]) -> String {
    let mut buf = String::with_capacity(64);
    buf.push_str(name);
    buf.push_str(" (");
    fmt_import_path(path, &mut buf);
    buf.push_str(")");
    buf
}

fn fmt_import_path(path: &[SmolStr], buf: &mut String) {
    let mut segments = path.iter();
    if let Some(s) = segments.next() {
        buf.push_str(&s);
    }
    for s in segments {
        buf.push_str("::");
        buf.push_str(&s);
    }
}

#[derive(Debug, Clone, Default)]
pub(crate) struct ImportResolver {
    // todo: use fst crate or something like that
    dummy_names: Vec<(SmolStr, Vec<SmolStr>)>,
}

impl ImportResolver {
    pub(crate) fn new() -> Self {
        let dummy_names = vec![
            (SmolStr::new("fmt"), vec![SmolStr::new("std"), SmolStr::new("fmt")]),
            (SmolStr::new("io"), vec![SmolStr::new("std"), SmolStr::new("io")]),
            (SmolStr::new("iter"), vec![SmolStr::new("std"), SmolStr::new("iter")]),
            (SmolStr::new("hash"), vec![SmolStr::new("std"), SmolStr::new("hash")]),
            (
                SmolStr::new("Debug"),
                vec![SmolStr::new("std"), SmolStr::new("fmt"), SmolStr::new("Debug")],
            ),
            (
                SmolStr::new("Display"),
                vec![SmolStr::new("std"), SmolStr::new("fmt"), SmolStr::new("Display")],
            ),
            (
                SmolStr::new("Hash"),
                vec![SmolStr::new("std"), SmolStr::new("hash"), SmolStr::new("Hash")],
            ),
            (
                SmolStr::new("Hasher"),
                vec![SmolStr::new("std"), SmolStr::new("hash"), SmolStr::new("Hasher")],
            ),
            (
                SmolStr::new("Iterator"),
                vec![SmolStr::new("std"), SmolStr::new("iter"), SmolStr::new("Iterator")],
            ),
        ];

        ImportResolver { dummy_names }
    }

    // Returns a map of importable items filtered by name.
    // The map associates item name with its full path.
    // todo: should return Resolutions
    pub(crate) fn all_names(&self, name: &str) -> FxHashMap<SmolStr, Vec<SmolStr>> {
        if name.len() > 1 {
            self.dummy_names.iter().filter(|(n, _)| n.contains(name)).cloned().collect()
        } else {
            FxHashMap::default()
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::completion::{do_completion, CompletionItem, CompletionKind};
    use insta::assert_debug_snapshot;

    fn do_reference_completion(code: &str) -> Vec<CompletionItem> {
        do_completion(code, CompletionKind::Reference)
    }

    #[test]
    fn completes_bindings_from_let() {
        assert_debug_snapshot!(
            do_reference_completion(
                r"
                fn quux(x: i32) {
                    let y = 92;
                    1 + <|>;
                    let z = ();
                }
                "
            ),
            @r###"[
    CompletionItem {
        label: "quux",
        source_range: [91; 91),
        delete: [91; 91),
        insert: "quux($0)",
        kind: Function,
        detail: "fn quux(x: i32)",
    },
    CompletionItem {
        label: "x",
        source_range: [91; 91),
        delete: [91; 91),
        insert: "x",
        kind: Binding,
        detail: "i32",
    },
    CompletionItem {
        label: "y",
        source_range: [91; 91),
        delete: [91; 91),
        insert: "y",
        kind: Binding,
        detail: "i32",
    },
]"###
        );
    }

    #[test]
    fn completes_bindings_from_if_let() {
        assert_debug_snapshot!(
            do_reference_completion(
                r"
                fn quux() {
                    if let Some(x) = foo() {
                        let y = 92;
                    };
                    if let Some(a) = bar() {
                        let b = 62;
                        1 + <|>
                    }
                }
                "
            ),
            @r###"[
    CompletionItem {
        label: "a",
        source_range: [242; 242),
        delete: [242; 242),
        insert: "a",
        kind: Binding,
    },
    CompletionItem {
        label: "b",
        source_range: [242; 242),
        delete: [242; 242),
        insert: "b",
        kind: Binding,
        detail: "i32",
    },
    CompletionItem {
        label: "quux",
        source_range: [242; 242),
        delete: [242; 242),
        insert: "quux()$0",
        kind: Function,
        detail: "fn quux()",
    },
]"###
        );
    }

    #[test]
    fn completes_bindings_from_for() {
        assert_debug_snapshot!(
            do_reference_completion(
                r"
                fn quux() {
                    for x in &[1, 2, 3] {
                        <|>
                    }
                }
                "
            ),
            @r###"[
    CompletionItem {
        label: "quux",
        source_range: [95; 95),
        delete: [95; 95),
        insert: "quux()$0",
        kind: Function,
        detail: "fn quux()",
    },
    CompletionItem {
        label: "x",
        source_range: [95; 95),
        delete: [95; 95),
        insert: "x",
        kind: Binding,
    },
]"###
        );
    }

    #[test]
    fn completes_generic_params() {
        assert_debug_snapshot!(
            do_reference_completion(
                r"
                fn quux<T>() {
                    <|>
                }
                "
            ),
            @r###"[
    CompletionItem {
        label: "T",
        source_range: [52; 52),
        delete: [52; 52),
        insert: "T",
        kind: TypeParam,
    },
    CompletionItem {
        label: "quux",
        source_range: [52; 52),
        delete: [52; 52),
        insert: "quux()$0",
        kind: Function,
        detail: "fn quux<T>()",
    },
]"###
        );
    }

    #[test]
    fn completes_generic_params_in_struct() {
        assert_debug_snapshot!(
            do_reference_completion(
                r"
                struct X<T> {
                    x: <|>
                }
                "
            ),
            @r###"[
    CompletionItem {
        label: "T",
        source_range: [54; 54),
        delete: [54; 54),
        insert: "T",
        kind: TypeParam,
    },
    CompletionItem {
        label: "X",
        source_range: [54; 54),
        delete: [54; 54),
        insert: "X",
        kind: Struct,
    },
]"###
        );
    }

    #[test]
    fn completes_module_items() {
        assert_debug_snapshot!(
        do_reference_completion(
            r"
                struct Foo;
                enum Baz {}
                fn quux() {
                    <|>
                }
                "
        ),
        @r###"[
    CompletionItem {
        label: "Baz",
        source_range: [105; 105),
        delete: [105; 105),
        insert: "Baz",
        kind: Enum,
    },
    CompletionItem {
        label: "Foo",
        source_range: [105; 105),
        delete: [105; 105),
        insert: "Foo",
        kind: Struct,
    },
    CompletionItem {
        label: "quux",
        source_range: [105; 105),
        delete: [105; 105),
        insert: "quux()$0",
        kind: Function,
        detail: "fn quux()",
    },
]"###
            );
    }

    #[test]
    fn completes_extern_prelude() {
        assert_debug_snapshot!(
            do_reference_completion(
                r"
                //- /lib.rs
                use <|>;

                //- /other_crate/lib.rs
                // nothing here
                "
            ),
            @r#"[
    CompletionItem {
        label: "other_crate",
        source_range: [4; 4),
        delete: [4; 4),
        insert: "other_crate",
        kind: Module,
    },
]"#
        );
    }

    #[test]
    fn completes_module_items_in_nested_modules() {
        assert_debug_snapshot!(
            do_reference_completion(
                r"
                struct Foo;
                mod m {
                    struct Bar;
                    fn quux() { <|> }
                }
                "
            ),
            @r###"[
    CompletionItem {
        label: "Bar",
        source_range: [117; 117),
        delete: [117; 117),
        insert: "Bar",
        kind: Struct,
    },
    CompletionItem {
        label: "quux",
        source_range: [117; 117),
        delete: [117; 117),
        insert: "quux()$0",
        kind: Function,
        detail: "fn quux()",
    },
]"###
        );
    }

    #[test]
    fn completes_return_type() {
        assert_debug_snapshot!(
            do_reference_completion(
                r"
                struct Foo;
                fn x() -> <|>
                "
            ),
            @r###"[
    CompletionItem {
        label: "Foo",
        source_range: [55; 55),
        delete: [55; 55),
        insert: "Foo",
        kind: Struct,
    },
    CompletionItem {
        label: "x",
        source_range: [55; 55),
        delete: [55; 55),
        insert: "x()$0",
        kind: Function,
        detail: "fn x()",
    },
]"###
        );
    }

    #[test]
    fn dont_show_both_completions_for_shadowing() {
        assert_debug_snapshot!(
            do_reference_completion(
                r"
                fn foo() {
                    let bar = 92;
                    {
                        let bar = 62;
                        <|>
                    }
                }
                "
            ),
            @r###"[
    CompletionItem {
        label: "bar",
        source_range: [146; 146),
        delete: [146; 146),
        insert: "bar",
        kind: Binding,
        detail: "i32",
    },
    CompletionItem {
        label: "foo",
        source_range: [146; 146),
        delete: [146; 146),
        insert: "foo()$0",
        kind: Function,
        detail: "fn foo()",
    },
]"###
        );
    }

    #[test]
    fn completes_self_in_methods() {
        assert_debug_snapshot!(
            do_reference_completion(r"impl S { fn foo(&self) { <|> } }"),
            @r#"[
    CompletionItem {
        label: "Self",
        source_range: [25; 25),
        delete: [25; 25),
        insert: "Self",
        kind: TypeParam,
    },
    CompletionItem {
        label: "self",
        source_range: [25; 25),
        delete: [25; 25),
        insert: "self",
        kind: Binding,
        detail: "&{unknown}",
    },
]"#
        );
    }

    #[test]
    fn completes_prelude() {
        assert_debug_snapshot!(
            do_reference_completion(
                "
                //- /main.rs
                fn foo() { let x: <|> }

                //- /std/lib.rs
                #[prelude_import]
                use prelude::*;

                mod prelude {
                    struct Option;
                }
                "
            ),
            @r#"[
    CompletionItem {
        label: "Option",
        source_range: [18; 18),
        delete: [18; 18),
        insert: "Option",
        kind: Struct,
    },
    CompletionItem {
        label: "foo",
        source_range: [18; 18),
        delete: [18; 18),
        insert: "foo()$0",
        kind: Function,
        detail: "fn foo()",
    },
    CompletionItem {
        label: "std",
        source_range: [18; 18),
        delete: [18; 18),
        insert: "std",
        kind: Module,
    },
]"#
        );
    }
}
<|endoftext|>


<commit_before>//! Crypto protocol for ShadowSocks UDP
//!
//! Payload with stream cipher
//! ```plain
//! +-------+----------+
//! |  IV   | Payload  |
//! +-------+----------+
//! | Fixed | Variable |
//! +-------+----------+
//! ```
//!
//! Payload with AEAD cipher
//!
//! ```plain
//! UDP (after encryption, *ciphertext*)
//! +--------+-----------+-----------+
//! | NONCE  |  *Data*   |  Data_TAG |
//! +--------+-----------+-----------+
//! | Fixed  | Variable  |   Fixed   |
//! +--------+-----------+-----------+
//! ```
use std::io::{self, Cursor, ErrorKind};

use byte_string::ByteStr;
use bytes::{BufMut, BytesMut};
use log::{debug, trace};

use crate::{
    context::Context,
    crypto::v1::{random_iv_or_salt, Cipher, CipherCategory, CipherKind},
    relay::socks5::Address,
};

/// Encrypt payload into ShadowSocks UDP encrypted packet
pub fn encrypt_payload(
    context: &Context,
    method: CipherKind,
    key: &[u8],
    addr: &Address,
    payload: &[u8],
    dst: &mut BytesMut,
) {
    match method.category() {
        CipherCategory::None => {
            dst.reserve(addr.serialized_len() + payload.len());
            addr.write_to_buf(dst);
            dst.put_slice(payload);
        }
        CipherCategory::Stream => encrypt_payload_stream(context, method, key, addr, payload, dst),
        CipherCategory::Aead => encrypt_payload_aead(context, method, key, addr, payload, dst),
    }
}

fn encrypt_payload_stream(
    context: &Context,
    method: CipherKind,
    key: &[u8],
    addr: &Address,
    payload: &[u8],
    dst: &mut BytesMut,
) {
    let iv_len = method.iv_len();
    let addr_len = addr.serialized_len();

    // Packet = IV + ADDRESS + PAYLOAD
    dst.reserve(iv_len + addr_len + payload.len());

    // Generate IV
    dst.resize(iv_len, 0);
    let iv = &mut dst[..iv_len];

    if iv_len > 0 {
        loop {
            random_iv_or_salt(iv);
            if !context.check_nonce_and_set(iv) {
                break;
            }
        }

        trace!("UDP packet generated stream iv {:?}", ByteStr::new(iv));
    } else {
        context.check_nonce_and_set(iv);
    }

    let mut cipher = Cipher::new(method, key, &iv);

    addr.write_to_buf(dst);
    dst.put_slice(payload);
    let m = &mut dst[iv_len..];
    cipher.encrypt_packet(m);
}

fn encrypt_payload_aead(
    context: &Context,
    method: CipherKind,
    key: &[u8],
    addr: &Address,
    payload: &[u8],
    dst: &mut BytesMut,
) {
    let salt_len = method.salt_len();
    let addr_len = addr.serialized_len();

    // Packet = IV + ADDRESS + PAYLOAD + TAG
    dst.reserve(salt_len + addr_len + payload.len() + method.tag_len());

    // Generate IV
    dst.resize(salt_len, 0);
    let salt = &mut dst[..salt_len];

    if salt_len > 0 {
        loop {
            random_iv_or_salt(salt);
            if !context.check_nonce_and_set(salt) {
                break;
            }
        }

        trace!("UDP packet generated aead salt {:?}", ByteStr::new(salt));
    } else {
        context.check_nonce_and_set(salt);
    }

    let mut cipher = Cipher::new(method, key, salt);

    addr.write_to_buf(dst);
    dst.put_slice(payload);

    unsafe {
        dst.advance_mut(method.tag_len());
    }

    let m = &mut dst[salt_len..];
    cipher.encrypt_packet(m);
}

/// Decrypt payload from ShadowSocks UDP encrypted packet
pub async fn decrypt_payload(
    context: &Context,
    method: CipherKind,
    key: &[u8],
    payload: &mut [u8],
) -> io::Result<(usize, Address)> {
    match method.category() {
        CipherCategory::None => {
            let mut cur = Cursor::new(payload);
            match Address::read_from(&mut cur).await {
                Ok(address) => {
                    let pos = cur.position() as usize;
                    let payload = cur.into_inner();
                    payload.copy_within(pos.., 0);
                    Ok((payload.len() - pos, address))
                }
                Err(..) => {
                    let err = io::Error::new(ErrorKind::InvalidData, "parse udp packet Address failed");
                    Err(err)
                }
            }
        }
        CipherCategory::Stream => decrypt_payload_stream(context, method, key, payload).await,
        CipherCategory::Aead => decrypt_payload_aead(context, method, key, payload).await,
    }
}
async fn decrypt_payload_stream(
    context: &Context,
    method: CipherKind,
    key: &[u8],
    payload: &mut [u8],
) -> io::Result<(usize, Address)> {
    let plen = payload.len();
    let iv_len = method.iv_len();

    if plen < iv_len {
        let err = io::Error::new(ErrorKind::InvalidData, "udp packet too short for iv");
        return Err(err);
    }

    let (iv, data) = payload.split_at_mut(iv_len);
    if context.check_nonce_and_set(iv) {
        debug!("detected repeated iv {:?}", ByteStr::new(iv));
        return Err(io::Error::new(io::ErrorKind::Other, "detected repeated iv"));
    }

    trace!("UDP packet got stream IV {:?}", ByteStr::new(iv));
    let mut cipher = Cipher::new(method, key, iv);

    assert_eq!(cipher.decrypt_packet(data), true);

    let (dn, addr) = parse_packet(data).await?;

    let data_start_idx = iv_len + dn;
    let data_length = payload.len() - data_start_idx;
    payload.copy_within(data_start_idx.., 0);

    Ok((data_length, addr))
}

async fn decrypt_payload_aead(
    context: &Context,
    method: CipherKind,
    key: &[u8],
    payload: &mut [u8],
) -> io::Result<(usize, Address)> {
    let plen = payload.len();
    let salt_len = method.salt_len();
    if plen < salt_len {
        let err = io::Error::new(ErrorKind::InvalidData, "udp packet too short for salt");
        return Err(err);
    }

    let (salt, data) = payload.split_at_mut(salt_len);
    if context.check_nonce_and_set(salt) {
        debug!("detected repeated salt {:?}", ByteStr::new(salt));
        return Err(io::Error::new(io::ErrorKind::Other, "detected repeated salt"));
    }

    trace!("UDP packet got AEAD salt {:?}", ByteStr::new(salt));

    let mut cipher = Cipher::new(method, &key, &salt);
    let tag_len = cipher.tag_len();

    if !cipher.decrypt_packet(data) {
        return Err(io::Error::new(io::ErrorKind::Other, "invalid tag-in"));
    }

    // Truncate TAG
    let data_len = data.len() - tag_len;
    let data = &mut data[..data_len];

    let (dn, addr) = parse_packet(data).await?;

    let data_length = data_len - dn;
    let data_start_idx = salt_len + dn;
    let data_end_idx = data_start_idx + data_length;

    payload.copy_within(data_start_idx..data_end_idx, 0);

    Ok((data_length, addr))
}

async fn parse_packet(buf: &[u8]) -> io::Result<(usize, Address)> {
    let mut cur = Cursor::new(buf);
    match Address::read_from(&mut cur).await {
        Ok(address) => {
            let pos = cur.position() as usize;
            Ok((pos, address))
        }
        Err(..) => {
            let err = io::Error::new(ErrorKind::InvalidData, "parse udp packet Address failed");
            Err(err)
        }
    }
}
<commit_msg>check UDP packet's data length before decrypt_packet<commit_after>//! Crypto protocol for ShadowSocks UDP
//!
//! Payload with stream cipher
//! ```plain
//! +-------+----------+
//! |  IV   | Payload  |
//! +-------+----------+
//! | Fixed | Variable |
//! +-------+----------+
//! ```
//!
//! Payload with AEAD cipher
//!
//! ```plain
//! UDP (after encryption, *ciphertext*)
//! +--------+-----------+-----------+
//! | NONCE  |  *Data*   |  Data_TAG |
//! +--------+-----------+-----------+
//! | Fixed  | Variable  |   Fixed   |
//! +--------+-----------+-----------+
//! ```
use std::io::{self, Cursor, ErrorKind};

use byte_string::ByteStr;
use bytes::{BufMut, BytesMut};
use log::{debug, trace};

use crate::{
    context::Context,
    crypto::v1::{random_iv_or_salt, Cipher, CipherCategory, CipherKind},
    relay::socks5::Address,
};

/// Encrypt payload into ShadowSocks UDP encrypted packet
pub fn encrypt_payload(
    context: &Context,
    method: CipherKind,
    key: &[u8],
    addr: &Address,
    payload: &[u8],
    dst: &mut BytesMut,
) {
    match method.category() {
        CipherCategory::None => {
            dst.reserve(addr.serialized_len() + payload.len());
            addr.write_to_buf(dst);
            dst.put_slice(payload);
        }
        CipherCategory::Stream => encrypt_payload_stream(context, method, key, addr, payload, dst),
        CipherCategory::Aead => encrypt_payload_aead(context, method, key, addr, payload, dst),
    }
}

fn encrypt_payload_stream(
    context: &Context,
    method: CipherKind,
    key: &[u8],
    addr: &Address,
    payload: &[u8],
    dst: &mut BytesMut,
) {
    let iv_len = method.iv_len();
    let addr_len = addr.serialized_len();

    // Packet = IV + ADDRESS + PAYLOAD
    dst.reserve(iv_len + addr_len + payload.len());

    // Generate IV
    dst.resize(iv_len, 0);
    let iv = &mut dst[..iv_len];

    if iv_len > 0 {
        loop {
            random_iv_or_salt(iv);
            if !context.check_nonce_and_set(iv) {
                break;
            }
        }

        trace!("UDP packet generated stream iv {:?}", ByteStr::new(iv));
    } else {
        context.check_nonce_and_set(iv);
    }

    let mut cipher = Cipher::new(method, key, &iv);

    addr.write_to_buf(dst);
    dst.put_slice(payload);
    let m = &mut dst[iv_len..];
    cipher.encrypt_packet(m);
}

fn encrypt_payload_aead(
    context: &Context,
    method: CipherKind,
    key: &[u8],
    addr: &Address,
    payload: &[u8],
    dst: &mut BytesMut,
) {
    let salt_len = method.salt_len();
    let addr_len = addr.serialized_len();

    // Packet = IV + ADDRESS + PAYLOAD + TAG
    dst.reserve(salt_len + addr_len + payload.len() + method.tag_len());

    // Generate IV
    dst.resize(salt_len, 0);
    let salt = &mut dst[..salt_len];

    if salt_len > 0 {
        loop {
            random_iv_or_salt(salt);
            if !context.check_nonce_and_set(salt) {
                break;
            }
        }

        trace!("UDP packet generated aead salt {:?}", ByteStr::new(salt));
    } else {
        context.check_nonce_and_set(salt);
    }

    let mut cipher = Cipher::new(method, key, salt);

    addr.write_to_buf(dst);
    dst.put_slice(payload);

    unsafe {
        dst.advance_mut(method.tag_len());
    }

    let m = &mut dst[salt_len..];
    cipher.encrypt_packet(m);
}

/// Decrypt payload from ShadowSocks UDP encrypted packet
pub async fn decrypt_payload(
    context: &Context,
    method: CipherKind,
    key: &[u8],
    payload: &mut [u8],
) -> io::Result<(usize, Address)> {
    match method.category() {
        CipherCategory::None => {
            let mut cur = Cursor::new(payload);
            match Address::read_from(&mut cur).await {
                Ok(address) => {
                    let pos = cur.position() as usize;
                    let payload = cur.into_inner();
                    payload.copy_within(pos.., 0);
                    Ok((payload.len() - pos, address))
                }
                Err(..) => {
                    let err = io::Error::new(ErrorKind::InvalidData, "parse udp packet Address failed");
                    Err(err)
                }
            }
        }
        CipherCategory::Stream => decrypt_payload_stream(context, method, key, payload).await,
        CipherCategory::Aead => decrypt_payload_aead(context, method, key, payload).await,
    }
}
async fn decrypt_payload_stream(
    context: &Context,
    method: CipherKind,
    key: &[u8],
    payload: &mut [u8],
) -> io::Result<(usize, Address)> {
    let plen = payload.len();
    let iv_len = method.iv_len();

    if plen < iv_len {
        let err = io::Error::new(ErrorKind::InvalidData, "udp packet too short for iv");
        return Err(err);
    }

    let (iv, data) = payload.split_at_mut(iv_len);
    if context.check_nonce_and_set(iv) {
        debug!("detected repeated iv {:?}", ByteStr::new(iv));
        return Err(io::Error::new(io::ErrorKind::Other, "detected repeated iv"));
    }

    trace!("UDP packet got stream IV {:?}", ByteStr::new(iv));
    let mut cipher = Cipher::new(method, key, iv);

    assert_eq!(cipher.decrypt_packet(data), true);

    let (dn, addr) = parse_packet(data).await?;

    let data_start_idx = iv_len + dn;
    let data_length = payload.len() - data_start_idx;
    payload.copy_within(data_start_idx.., 0);

    Ok((data_length, addr))
}

async fn decrypt_payload_aead(
    context: &Context,
    method: CipherKind,
    key: &[u8],
    payload: &mut [u8],
) -> io::Result<(usize, Address)> {
    let plen = payload.len();
    let salt_len = method.salt_len();
    if plen < salt_len {
        let err = io::Error::new(ErrorKind::InvalidData, "udp packet too short for salt");
        return Err(err);
    }

    let (salt, data) = payload.split_at_mut(salt_len);
    if context.check_nonce_and_set(salt) {
        debug!("detected repeated salt {:?}", ByteStr::new(salt));
        return Err(io::Error::new(io::ErrorKind::Other, "detected repeated salt"));
    }

    trace!("UDP packet got AEAD salt {:?}", ByteStr::new(salt));

    let mut cipher = Cipher::new(method, &key, &salt);
    let tag_len = cipher.tag_len();

    if data.len() < tag_len {
        return Err(io::Error::new(io::ErrorKind::Other, "udp packet too short for tag"));
    }

    if !cipher.decrypt_packet(data) {
        return Err(io::Error::new(io::ErrorKind::Other, "invalid tag-in"));
    }

    // Truncate TAG
    let data_len = data.len() - tag_len;
    let data = &mut data[..data_len];

    let (dn, addr) = parse_packet(data).await?;

    let data_length = data_len - dn;
    let data_start_idx = salt_len + dn;
    let data_end_idx = data_start_idx + data_length;

    payload.copy_within(data_start_idx..data_end_idx, 0);

    Ok((data_length, addr))
}

async fn parse_packet(buf: &[u8]) -> io::Result<(usize, Address)> {
    let mut cur = Cursor::new(buf);
    match Address::read_from(&mut cur).await {
        Ok(address) => {
            let pos = cur.position() as usize;
            Ok((pos, address))
        }
        Err(..) => {
            let err = io::Error::new(ErrorKind::InvalidData, "parse udp packet Address failed");
            Err(err)
        }
    }
}
<|endoftext|>


<commit_before>
use color::{ Color, Colorable };
use dimensions::Dimensions;
use mouse::Mouse;
use point::Point;
use rectangle;
use graphics::Graphics;
use graphics::character::CharacterCache;
use ui_context::{ UIID, UiContext };
use widget::Widget;

/// Represents the state of the Toggle widget.
#[derive(PartialEq, Clone, Copy)]
pub enum State {
    Normal,
    Highlighted,
    Clicked,
}

impl State {
    /// Return the associated Rectangle state.
    fn as_rectangle_state(&self) -> rectangle::State {
        match self {
            &State::Normal => rectangle::State::Normal,
            &State::Highlighted => rectangle::State::Highlighted,
            &State::Clicked => rectangle::State::Clicked,
        }
    }
}

widget_fns!(Toggle, State, Widget::Toggle(State::Normal));

/// Check the current state of the button.
fn get_new_state(is_over: bool,
                 prev: State,
                 mouse: Mouse) -> State {
    use mouse::ButtonState::{Down, Up};
    use self::State::{Normal, Highlighted, Clicked};
    match (is_over, prev, mouse.left) {
        (true,  Normal,  Down) => Normal,
        (true,  _,       Down) => Clicked,
        (true,  _,       Up)   => Highlighted,
        (false, Clicked, Down) => Clicked,
        _                      => Normal,
    }
}

/// A context on which the builder pattern can be implemented.
pub struct Toggle<'a, F> {
    ui_id: UIID,
    pos: Point,
    dim: Dimensions,
    maybe_callback: Option<F>,
    maybe_color: Option<Color>,
    maybe_frame: Option<f64>,
    maybe_frame_color: Option<Color>,
    maybe_label: Option<&'a str>,
    maybe_label_color: Option<Color>,
    maybe_label_font_size: Option<u32>,
    value: bool,
}

impl<'a, F> Toggle<'a, F> {

    /// Create a toggle context to be built upon.
    pub fn new(ui_id: UIID, value: bool) -> Toggle<'a, F> {
        Toggle {
            ui_id: ui_id,
            pos: [0.0, 0.0],
            dim: [64.0, 64.0],
            maybe_callback: None,
            maybe_color: None,
            maybe_frame: None,
            maybe_frame_color: None,
            maybe_label: None,
            maybe_label_color: None,
            maybe_label_font_size: None,
            value: value,
        }
    }

}

impl<'a, F> Colorable for Toggle<'a, F> {
    fn color(mut self, color: Color) -> Self {
        self.maybe_color = Some(color);
        self
    }
}

/*
quack! {
    toggle: Toggle['a, F]
    get:
        fn () -> Size [] { Size(toggle.dim) }
        fn () -> DefaultWidgetState [] {
            DefaultWidgetState(Widget::Toggle(State::Normal))
        }
        fn () -> Id [] { Id(toggle.ui_id) }
    set:
        fn (val: Callback<F>) [where F: FnMut(bool) + 'a] {
            toggle.maybe_callback = Some(val.0)
        }
        fn (val: FrameColor) [] { toggle.maybe_frame_color = Some(val.0) }
        fn (val: FrameWidth) [] { toggle.maybe_frame = Some(val.0) }
        fn (val: LabelText<'a>) [] { toggle.maybe_label = Some(val.0) }
        fn (val: LabelColor) [] { toggle.maybe_label_color = Some(val.0) }
        fn (val: LabelFontSize) [] {
            toggle.maybe_label_font_size = Some(val.0)
        }
        fn (val: Position) [] { toggle.pos = val.0 }
        fn (val: Size) [] { toggle.dim = val.0 }
    action:
}
*/

impl<'a, F> ::draw::Drawable for Toggle<'a, F> where F: FnMut(bool) + 'a {
    fn draw<B, C>(&mut self, uic: &mut UiContext<C>, graphics: &mut B)
        where
            B: Graphics<Texture = <C as CharacterCache>::Texture>,
            C: CharacterCache
    {
        let color = self.maybe_color.unwrap_or(uic.theme.shape_color);
        let color = match self.value {
            true => color,
            false => color * Color::new(0.1, 0.1, 0.1, 1.0)
        };
        let state = *get_state(uic, self.ui_id);
        let mouse = uic.get_mouse_state();
        let is_over = rectangle::is_over(self.pos, mouse.pos, self.dim);
        let new_state = get_new_state(is_over, state, mouse);
        let rect_state = new_state.as_rectangle_state();
        match self.maybe_callback {
            Some(ref mut callback) => {
                match (is_over, state, new_state) {
                    (true, State::Clicked, State::Highlighted) =>
                        (*callback)(match self.value { true => false, false => true }),
                    _ => (),
                }
            }, None => (),
        }
        let frame_w = self.maybe_frame.unwrap_or(uic.theme.frame_width);
        let maybe_frame = match frame_w > 0.0 {
            true => Some((frame_w, self.maybe_frame_color.unwrap_or(uic.theme.frame_color))),
            false => None,
        };
        match self.maybe_label {
            None => {
                rectangle::draw(
                    uic.win_w, uic.win_h, graphics, rect_state, self.pos,
                    self.dim, maybe_frame, color
                )
            },
            Some(text) => {
                let text_color = self.maybe_label_color.unwrap_or(uic.theme.label_color);
                let size = self.maybe_label_font_size.unwrap_or(uic.theme.font_size_medium);
                rectangle::draw_with_centered_label(
                    uic.win_w, uic.win_h, graphics, uic, rect_state,
                    self.pos, self.dim, maybe_frame, color,
                    text, size, text_color
                )
            },
        }

        set_state(uic, self.ui_id, Widget::Toggle(new_state), self.pos, self.dim);

    }
}
<commit_msg>Implemented `Frameable` for `Toggle`<commit_after>use frame::Frameable;
use color::{ Color, Colorable };
use dimensions::Dimensions;
use mouse::Mouse;
use point::Point;
use rectangle;
use graphics::Graphics;
use graphics::character::CharacterCache;
use ui_context::{ UIID, UiContext };
use widget::Widget;

/// Represents the state of the Toggle widget.
#[derive(PartialEq, Clone, Copy)]
pub enum State {
    Normal,
    Highlighted,
    Clicked,
}

impl State {
    /// Return the associated Rectangle state.
    fn as_rectangle_state(&self) -> rectangle::State {
        match self {
            &State::Normal => rectangle::State::Normal,
            &State::Highlighted => rectangle::State::Highlighted,
            &State::Clicked => rectangle::State::Clicked,
        }
    }
}

widget_fns!(Toggle, State, Widget::Toggle(State::Normal));

/// Check the current state of the button.
fn get_new_state(is_over: bool,
                 prev: State,
                 mouse: Mouse) -> State {
    use mouse::ButtonState::{Down, Up};
    use self::State::{Normal, Highlighted, Clicked};
    match (is_over, prev, mouse.left) {
        (true,  Normal,  Down) => Normal,
        (true,  _,       Down) => Clicked,
        (true,  _,       Up)   => Highlighted,
        (false, Clicked, Down) => Clicked,
        _                      => Normal,
    }
}

/// A context on which the builder pattern can be implemented.
pub struct Toggle<'a, F> {
    ui_id: UIID,
    pos: Point,
    dim: Dimensions,
    maybe_callback: Option<F>,
    maybe_color: Option<Color>,
    maybe_frame: Option<f64>,
    maybe_frame_color: Option<Color>,
    maybe_label: Option<&'a str>,
    maybe_label_color: Option<Color>,
    maybe_label_font_size: Option<u32>,
    value: bool,
}

impl<'a, F> Toggle<'a, F> {

    /// Create a toggle context to be built upon.
    pub fn new(ui_id: UIID, value: bool) -> Toggle<'a, F> {
        Toggle {
            ui_id: ui_id,
            pos: [0.0, 0.0],
            dim: [64.0, 64.0],
            maybe_callback: None,
            maybe_color: None,
            maybe_frame: None,
            maybe_frame_color: None,
            maybe_label: None,
            maybe_label_color: None,
            maybe_label_font_size: None,
            value: value,
        }
    }

}

impl<'a, F> Colorable for Toggle<'a, F> {
    fn color(mut self, color: Color) -> Self {
        self.maybe_color = Some(color);
        self
    }
}

impl<'a, F> Frameable for Toggle<'a, F> {
    fn frame(mut self, width: f64) -> Self {
        self.maybe_frame = Some(width);
        self
    }
    fn frame_color(mut self, color: Color) -> Self {
        self.maybe_frame_color = Some(color);
        self
    }
}

/*
quack! {
    toggle: Toggle['a, F]
    get:
        fn () -> Size [] { Size(toggle.dim) }
        fn () -> DefaultWidgetState [] {
            DefaultWidgetState(Widget::Toggle(State::Normal))
        }
        fn () -> Id [] { Id(toggle.ui_id) }
    set:
        fn (val: Callback<F>) [where F: FnMut(bool) + 'a] {
            toggle.maybe_callback = Some(val.0)
        }
        fn (val: LabelText<'a>) [] { toggle.maybe_label = Some(val.0) }
        fn (val: LabelColor) [] { toggle.maybe_label_color = Some(val.0) }
        fn (val: LabelFontSize) [] {
            toggle.maybe_label_font_size = Some(val.0)
        }
        fn (val: Position) [] { toggle.pos = val.0 }
        fn (val: Size) [] { toggle.dim = val.0 }
    action:
}
*/

impl<'a, F> ::draw::Drawable for Toggle<'a, F> where F: FnMut(bool) + 'a {
    fn draw<B, C>(&mut self, uic: &mut UiContext<C>, graphics: &mut B)
        where
            B: Graphics<Texture = <C as CharacterCache>::Texture>,
            C: CharacterCache
    {
        let color = self.maybe_color.unwrap_or(uic.theme.shape_color);
        let color = match self.value {
            true => color,
            false => color * Color::new(0.1, 0.1, 0.1, 1.0)
        };
        let state = *get_state(uic, self.ui_id);
        let mouse = uic.get_mouse_state();
        let is_over = rectangle::is_over(self.pos, mouse.pos, self.dim);
        let new_state = get_new_state(is_over, state, mouse);
        let rect_state = new_state.as_rectangle_state();
        match self.maybe_callback {
            Some(ref mut callback) => {
                match (is_over, state, new_state) {
                    (true, State::Clicked, State::Highlighted) =>
                        (*callback)(match self.value { true => false, false => true }),
                    _ => (),
                }
            }, None => (),
        }
        let frame_w = self.maybe_frame.unwrap_or(uic.theme.frame_width);
        let maybe_frame = match frame_w > 0.0 {
            true => Some((frame_w, self.maybe_frame_color.unwrap_or(uic.theme.frame_color))),
            false => None,
        };
        match self.maybe_label {
            None => {
                rectangle::draw(
                    uic.win_w, uic.win_h, graphics, rect_state, self.pos,
                    self.dim, maybe_frame, color
                )
            },
            Some(text) => {
                let text_color = self.maybe_label_color.unwrap_or(uic.theme.label_color);
                let size = self.maybe_label_font_size.unwrap_or(uic.theme.font_size_medium);
                rectangle::draw_with_centered_label(
                    uic.win_w, uic.win_h, graphics, uic, rect_state,
                    self.pos, self.dim, maybe_frame, color,
                    text, size, text_color
                )
            },
        }

        set_state(uic, self.ui_id, Widget::Toggle(new_state), self.pos, self.dim);

    }
}
<|endoftext|>


<commit_before>use serde::{Deserialize, Serialize};

pub trait EvolutionState {
    fn update(&mut self);
}

pub trait Cell: Serialize + Deserialize {
    type Coord: Coord;
    type State: EvolutionState;

    fn update<'a, I>(&'a mut self, old: &'a Self, neighbors: I, &Self::State)
        where I: Iterator<Item = Option<&'a Self>>;

    fn with_coord<C: Coord>(C) -> Self;
    fn coord(&self) -> &Self::Coord;
    fn set_coord<C: Coord>(&mut self, &C);
}

pub trait Nhood {
    type Coord: Coord;

    fn neighbors(&self, &Self::Coord) -> Vec<Self::Coord>;
    fn neighbors_count(&self) -> usize;
}

pub trait Coord: Clone + Serialize + Deserialize {
    fn from_2d(x: i32, y: i32) -> Self;

    fn x(&self) -> i32;
    fn y(&self) -> i32;
    fn z(&self) -> i32 { 0 }
}

pub trait Grid {
    type Cell: Cell;
    type Coord: Coord;

    fn update(&mut self);

    fn state(&self) -> &<<Self as Grid>::Cell as Cell>::State;
    fn cells(&self) -> &Vec<Self::Cell>;
    fn dimensions(&self) -> Self::Coord;

    fn set_cells(&mut self, Vec<Self::Cell>);
}

pub trait Consumer {
    type Cell: Cell;

    fn consume<G>(&mut self, &mut G)
        where G: Grid<Cell = Self::Cell>;
}

pub trait Engine {
    fn run_times(&mut self, i64);
}
<commit_msg>Note about EvolutionState.<commit_after>use serde::{Deserialize, Serialize};

/// Trait represents global state of the
/// entire simulation which can updated
/// independently from any particular cell.
/// Consider to store there as much as you can
/// because this data will be created only once
/// and will not be copied.
pub trait EvolutionState {
    /// Method is called once between cells' updates.
    fn update(&mut self);
}

pub trait Cell: Serialize + Deserialize {
    type Coord: Coord;
    type State: EvolutionState;

    fn update<'a, I>(&'a mut self, old: &'a Self, neighbors: I, &Self::State)
        where I: Iterator<Item = Option<&'a Self>>;

    fn with_coord<C: Coord>(C) -> Self;
    fn coord(&self) -> &Self::Coord;
    fn set_coord<C: Coord>(&mut self, &C);
}

pub trait Nhood {
    type Coord: Coord;

    fn neighbors(&self, &Self::Coord) -> Vec<Self::Coord>;
    fn neighbors_count(&self) -> usize;
}

pub trait Coord: Clone + Serialize + Deserialize {
    fn from_2d(x: i32, y: i32) -> Self;

    fn x(&self) -> i32;
    fn y(&self) -> i32;
    fn z(&self) -> i32 { 0 }
}

pub trait Grid {
    type Cell: Cell;
    type Coord: Coord;

    fn update(&mut self);

    fn state(&self) -> &<<Self as Grid>::Cell as Cell>::State;
    fn cells(&self) -> &Vec<Self::Cell>;
    fn dimensions(&self) -> Self::Coord;

    fn set_cells(&mut self, Vec<Self::Cell>);
}

pub trait Consumer {
    type Cell: Cell;

    fn consume<G>(&mut self, &mut G)
        where G: Grid<Cell = Self::Cell>;
}

pub trait Engine {
    fn run_times(&mut self, i64);
}
<|endoftext|>