<commit_before>/// Define a type that supports parsing and printing a multi-character symbol
/// as if it were a punctuation token.
///
/// # Usage
///
/// ```edition2018
/// syn::custom_punctuation!(LeftRightArrow, <=>);
/// ```
///
/// The generated syntax tree node supports the following operations just like
/// any built-in punctuation token.
///
/// - [Peeking] — `input.peek(LeftRightArrow)`
///
/// - [Parsing] — `input.parse::<LeftRightArrow>()?`
///
/// - [Printing] — `quote!( ... #lrarrow ... )`
///
/// - Construction from a [`Span`] — `let lrarrow = LeftRightArrow(sp)`
///
/// - Construction from multiple [`Span`] — `let lrarrow = LeftRightArrow([sp, sp, sp])`
///
/// - Field access to its spans — `let spans = lrarrow.spans`
///
/// [Peeking]: parse/struct.ParseBuffer.html#method.peek
/// [Parsing]: parse/struct.ParseBuffer.html#method.parse
/// [Printing]: https://docs.rs/quote/0.6/quote/trait.ToTokens.html
/// [`Span`]: struct.Span.html
///
/// # Example
///
/// ```edition2018
/// use proc_macro2::{TokenStream, TokenTree};
/// use syn::parse::{Parse, ParseStream, Peek, Result};
/// use syn::punctuated::Punctuated;
/// use syn::Expr;
///
/// syn::custom_punctuation!(PathSeparator, </>);
///
/// // expr </> expr </> expr ...
/// struct PathSegments {
///     segments: Punctuated<Expr, PathSeparator>,
/// }
///
/// impl Parse for PathSegments {
///     fn parse(input: ParseStream) -> Result<Self> {
///         let mut segments = Punctuated::new();
///
///         let first = parse_until(input, PathSeparator)?;
///         segments.push_value(syn::parse2(first)?);
///
///         while input.peek(PathSeparator) {
///             segments.push_punct(input.parse()?);
///
///             let next = parse_until(input, PathSeparator)?;
///             segments.push_value(syn::parse2(next)?);
///         }
///
///         Ok(PathSegments { segments })
///     }
/// }
///
/// fn parse_until<E: Peek>(input: ParseStream, end: E) -> Result<TokenStream> {
///     let mut tokens = TokenStream::new();
///     while !input.is_empty() && !input.peek(end) {
///         let next: TokenTree = input.parse()?;
///         tokens.extend(Some(next));
///     }
///     Ok(tokens)
/// }
///
/// fn main() {
///     let input = r#" a::b </> c::d::e "#;
///     let _: PathSegments = syn::parse_str(input).unwrap();
/// }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        pub struct $ident {
            pub spans: custom_punctuation_repr!($($tt)+),
        }

        #[doc(hidden)]
        #[allow(non_snake_case)]
        pub fn $ident<__S: $crate::export::IntoSpans<custom_punctuation_repr!($($tt)+)>>(
            spans: __S,
        ) -> $ident {
            let _validate_len = 0 $(+ custom_punctuation_len!(strict, $tt))*;
            $ident {
                spans: $crate::export::IntoSpans::into_spans(spans)
            }
        }

        impl $crate::export::Default for $ident {
            fn default() -> Self {
                $ident($crate::export::Span::call_site())
            }
        }

        impl_parse_for_custom_punctuation!($ident, $($tt)+);
        impl_to_tokens_for_custom_punctuation!($ident, $($tt)+);
        impl_clone_for_custom_punctuation!($ident, $($tt)+);
        impl_extra_traits_for_custom_punctuation!($ident, $($tt)+);
    };
}

// Not public API.
#[cfg(feature = "parsing")]
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_parse_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        impl $crate::token::CustomToken for $ident {
            fn peek(cursor: $crate::buffer::Cursor) -> bool {
                $crate::token::parsing::peek_punct(cursor, stringify_punct!($($tt)+))
            }

            fn display() -> &'static $crate::export::str {
                custom_punctuation_concat!("`", stringify_punct!($($tt)+), "`")
            }
        }

        impl $crate::parse::Parse for $ident {
            fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> {
                let spans: custom_punctuation_repr!($($tt)+) =
                    $crate::token::parsing::punct(input, stringify_punct!($($tt)+))?;
                Ok($ident(spans))
            }
        }
    };
}

// Not public API.
#[cfg(not(feature = "parsing"))]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_parse_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {};
}

// Not public API.
#[cfg(feature = "printing")]
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_to_tokens_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        impl $crate::export::ToTokens for $ident {
            fn to_tokens(&self, tokens: &mut $crate::export::TokenStream2) {
                $crate::token::printing::punct(stringify_punct!($($tt)+), &self.spans, tokens)
            }
        }
    };
}

// Not public API.
#[cfg(not(feature = "printing"))]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_to_tokens_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {};
}

// Not public API.
#[cfg(feature = "clone-impls")]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_clone_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        impl $crate::export::Copy for $ident {}

        impl $crate::export::Clone for $ident {
            fn clone(&self) -> Self {
                *self
            }
        }
    };
}

// Not public API.
#[cfg(not(feature = "clone-impls"))]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_clone_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {};
}

// Not public API.
#[cfg(feature = "extra-traits")]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_extra_traits_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        impl $crate::export::Debug for $ident {
            fn fmt(&self, f: &mut $crate::export::Formatter) -> $crate::export::fmt::Result {
                $crate::export::Formatter::write_str(f, stringify!($ident))
            }
        }

        impl $crate::export::Eq for $ident {}

        impl $crate::export::PartialEq for $ident {
            fn eq(&self, _other: &Self) -> $crate::export::bool {
                true
            }
        }

        impl $crate::export::Hash for $ident {
            fn hash<__H: $crate::export::Hasher>(&self, _state: &mut __H) {}
        }
    };
}

// Not public API.
#[cfg(not(feature = "extra-traits"))]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_extra_traits_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {};
}

// Not public API.
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! custom_punctuation_repr {
    ($($tt:tt)+) => {
        [$crate::export::Span; 0 $(+ custom_punctuation_len!(lenient, $tt))+]
    };
}

// Not public API.
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! custom_punctuation_len {
    ($mode:ident, +)     => { 1 };
    ($mode:ident, +=)    => { 2 };
    ($mode:ident, &)     => { 1 };
    ($mode:ident, &&)    => { 2 };
    ($mode:ident, &=)    => { 2 };
    ($mode:ident, @)     => { 1 };
    ($mode:ident, !)     => { 1 };
    ($mode:ident, ^)     => { 1 };
    ($mode:ident, ^=)    => { 2 };
    ($mode:ident, :)     => { 1 };
    ($mode:ident, ::)    => { 2 };
    ($mode:ident, ,)     => { 1 };
    ($mode:ident, /)     => { 1 };
    ($mode:ident, /=)    => { 2 };
    ($mode:ident, .)     => { 1 };
    ($mode:ident, ..)    => { 2 };
    ($mode:ident, ...)   => { 3 };
    ($mode:ident, ..=)   => { 3 };
    ($mode:ident, =)     => { 1 };
    ($mode:ident, ==)    => { 2 };
    ($mode:ident, >=)    => { 2 };
    ($mode:ident, >)     => { 1 };
    ($mode:ident, <=)    => { 2 };
    ($mode:ident, <)     => { 1 };
    ($mode:ident, *=)    => { 2 };
    ($mode:ident, !=)    => { 2 };
    ($mode:ident, |)     => { 1 };
    ($mode:ident, |=)    => { 2 };
    ($mode:ident, ||)    => { 2 };
    ($mode:ident, #)     => { 1 };
    ($mode:ident, ?)     => { 1 };
    ($mode:ident, ->)    => { 2 };
    ($mode:ident, <-)    => { 2 };
    ($mode:ident, %)     => { 1 };
    ($mode:ident, %=)    => { 2 };
    ($mode:ident, =>)    => { 2 };
    ($mode:ident, ;)     => { 1 };
    ($mode:ident, <<)    => { 2 };
    ($mode:ident, <<=)   => { 3 };
    ($mode:ident, >>)    => { 2 };
    ($mode:ident, >>=)   => { 3 };
    ($mode:ident, *)     => { 1 };
    ($mode:ident, -)     => { 1 };
    ($mode:ident, -=)    => { 2 };
    ($mode:ident, ~)     => { 1 };
    (lenient, $tt:tt)    => { 0 };
    (strict, $tt:tt)     => {{ custom_punctuation_unexpected!($tt); 0 }};
}

// Not public API.
#[doc(hidden)]
#[macro_export]
macro_rules! custom_punctuation_unexpected {
    () => {};
}

// Not public API.
#[doc(hidden)]
#[macro_export]
macro_rules! stringify_punct {
    ($($tt:tt)+) => {
        concat!($(stringify!($tt)),+)
    };
}

// Not public API.
// Without this, local_inner_macros breaks when looking for concat!
#[doc(hidden)]
#[macro_export]
macro_rules! custom_punctuation_concat {
    ($($tt:tt)*) => {
        concat!($($tt)*)
    };
}
<commit_msg>Hide custom_punctuation_len from rustfmt<commit_after>/// Define a type that supports parsing and printing a multi-character symbol
/// as if it were a punctuation token.
///
/// # Usage
///
/// ```edition2018
/// syn::custom_punctuation!(LeftRightArrow, <=>);
/// ```
///
/// The generated syntax tree node supports the following operations just like
/// any built-in punctuation token.
///
/// - [Peeking] — `input.peek(LeftRightArrow)`
///
/// - [Parsing] — `input.parse::<LeftRightArrow>()?`
///
/// - [Printing] — `quote!( ... #lrarrow ... )`
///
/// - Construction from a [`Span`] — `let lrarrow = LeftRightArrow(sp)`
///
/// - Construction from multiple [`Span`] — `let lrarrow = LeftRightArrow([sp, sp, sp])`
///
/// - Field access to its spans — `let spans = lrarrow.spans`
///
/// [Peeking]: parse/struct.ParseBuffer.html#method.peek
/// [Parsing]: parse/struct.ParseBuffer.html#method.parse
/// [Printing]: https://docs.rs/quote/0.6/quote/trait.ToTokens.html
/// [`Span`]: struct.Span.html
///
/// # Example
///
/// ```edition2018
/// use proc_macro2::{TokenStream, TokenTree};
/// use syn::parse::{Parse, ParseStream, Peek, Result};
/// use syn::punctuated::Punctuated;
/// use syn::Expr;
///
/// syn::custom_punctuation!(PathSeparator, </>);
///
/// // expr </> expr </> expr ...
/// struct PathSegments {
///     segments: Punctuated<Expr, PathSeparator>,
/// }
///
/// impl Parse for PathSegments {
///     fn parse(input: ParseStream) -> Result<Self> {
///         let mut segments = Punctuated::new();
///
///         let first = parse_until(input, PathSeparator)?;
///         segments.push_value(syn::parse2(first)?);
///
///         while input.peek(PathSeparator) {
///             segments.push_punct(input.parse()?);
///
///             let next = parse_until(input, PathSeparator)?;
///             segments.push_value(syn::parse2(next)?);
///         }
///
///         Ok(PathSegments { segments })
///     }
/// }
///
/// fn parse_until<E: Peek>(input: ParseStream, end: E) -> Result<TokenStream> {
///     let mut tokens = TokenStream::new();
///     while !input.is_empty() && !input.peek(end) {
///         let next: TokenTree = input.parse()?;
///         tokens.extend(Some(next));
///     }
///     Ok(tokens)
/// }
///
/// fn main() {
///     let input = r#" a::b </> c::d::e "#;
///     let _: PathSegments = syn::parse_str(input).unwrap();
/// }
/// ```
#[macro_export(local_inner_macros)]
macro_rules! custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        pub struct $ident {
            pub spans: custom_punctuation_repr!($($tt)+),
        }

        #[doc(hidden)]
        #[allow(non_snake_case)]
        pub fn $ident<__S: $crate::export::IntoSpans<custom_punctuation_repr!($($tt)+)>>(
            spans: __S,
        ) -> $ident {
            let _validate_len = 0 $(+ custom_punctuation_len!(strict, $tt))*;
            $ident {
                spans: $crate::export::IntoSpans::into_spans(spans)
            }
        }

        impl $crate::export::Default for $ident {
            fn default() -> Self {
                $ident($crate::export::Span::call_site())
            }
        }

        impl_parse_for_custom_punctuation!($ident, $($tt)+);
        impl_to_tokens_for_custom_punctuation!($ident, $($tt)+);
        impl_clone_for_custom_punctuation!($ident, $($tt)+);
        impl_extra_traits_for_custom_punctuation!($ident, $($tt)+);
    };
}

// Not public API.
#[cfg(feature = "parsing")]
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_parse_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        impl $crate::token::CustomToken for $ident {
            fn peek(cursor: $crate::buffer::Cursor) -> bool {
                $crate::token::parsing::peek_punct(cursor, stringify_punct!($($tt)+))
            }

            fn display() -> &'static $crate::export::str {
                custom_punctuation_concat!("`", stringify_punct!($($tt)+), "`")
            }
        }

        impl $crate::parse::Parse for $ident {
            fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> {
                let spans: custom_punctuation_repr!($($tt)+) =
                    $crate::token::parsing::punct(input, stringify_punct!($($tt)+))?;
                Ok($ident(spans))
            }
        }
    };
}

// Not public API.
#[cfg(not(feature = "parsing"))]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_parse_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {};
}

// Not public API.
#[cfg(feature = "printing")]
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! impl_to_tokens_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        impl $crate::export::ToTokens for $ident {
            fn to_tokens(&self, tokens: &mut $crate::export::TokenStream2) {
                $crate::token::printing::punct(stringify_punct!($($tt)+), &self.spans, tokens)
            }
        }
    };
}

// Not public API.
#[cfg(not(feature = "printing"))]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_to_tokens_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {};
}

// Not public API.
#[cfg(feature = "clone-impls")]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_clone_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        impl $crate::export::Copy for $ident {}

        impl $crate::export::Clone for $ident {
            fn clone(&self) -> Self {
                *self
            }
        }
    };
}

// Not public API.
#[cfg(not(feature = "clone-impls"))]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_clone_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {};
}

// Not public API.
#[cfg(feature = "extra-traits")]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_extra_traits_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {
        impl $crate::export::Debug for $ident {
            fn fmt(&self, f: &mut $crate::export::Formatter) -> $crate::export::fmt::Result {
                $crate::export::Formatter::write_str(f, stringify!($ident))
            }
        }

        impl $crate::export::Eq for $ident {}

        impl $crate::export::PartialEq for $ident {
            fn eq(&self, _other: &Self) -> $crate::export::bool {
                true
            }
        }

        impl $crate::export::Hash for $ident {
            fn hash<__H: $crate::export::Hasher>(&self, _state: &mut __H) {}
        }
    };
}

// Not public API.
#[cfg(not(feature = "extra-traits"))]
#[doc(hidden)]
#[macro_export]
macro_rules! impl_extra_traits_for_custom_punctuation {
    ($ident:ident, $($tt:tt)+) => {};
}

// Not public API.
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! custom_punctuation_repr {
    ($($tt:tt)+) => {
        [$crate::export::Span; 0 $(+ custom_punctuation_len!(lenient, $tt))+]
    };
}

// Not public API.
#[doc(hidden)]
#[macro_export(local_inner_macros)]
#[cfg_attr(rustfmt, rustfmt_skip)]
macro_rules! custom_punctuation_len {
    ($mode:ident, +)     => { 1 };
    ($mode:ident, +=)    => { 2 };
    ($mode:ident, &)     => { 1 };
    ($mode:ident, &&)    => { 2 };
    ($mode:ident, &=)    => { 2 };
    ($mode:ident, @)     => { 1 };
    ($mode:ident, !)     => { 1 };
    ($mode:ident, ^)     => { 1 };
    ($mode:ident, ^=)    => { 2 };
    ($mode:ident, :)     => { 1 };
    ($mode:ident, ::)    => { 2 };
    ($mode:ident, ,)     => { 1 };
    ($mode:ident, /)     => { 1 };
    ($mode:ident, /=)    => { 2 };
    ($mode:ident, .)     => { 1 };
    ($mode:ident, ..)    => { 2 };
    ($mode:ident, ...)   => { 3 };
    ($mode:ident, ..=)   => { 3 };
    ($mode:ident, =)     => { 1 };
    ($mode:ident, ==)    => { 2 };
    ($mode:ident, >=)    => { 2 };
    ($mode:ident, >)     => { 1 };
    ($mode:ident, <=)    => { 2 };
    ($mode:ident, <)     => { 1 };
    ($mode:ident, *=)    => { 2 };
    ($mode:ident, !=)    => { 2 };
    ($mode:ident, |)     => { 1 };
    ($mode:ident, |=)    => { 2 };
    ($mode:ident, ||)    => { 2 };
    ($mode:ident, #)     => { 1 };
    ($mode:ident, ?)     => { 1 };
    ($mode:ident, ->)    => { 2 };
    ($mode:ident, <-)    => { 2 };
    ($mode:ident, %)     => { 1 };
    ($mode:ident, %=)    => { 2 };
    ($mode:ident, =>)    => { 2 };
    ($mode:ident, ;)     => { 1 };
    ($mode:ident, <<)    => { 2 };
    ($mode:ident, <<=)   => { 3 };
    ($mode:ident, >>)    => { 2 };
    ($mode:ident, >>=)   => { 3 };
    ($mode:ident, *)     => { 1 };
    ($mode:ident, -)     => { 1 };
    ($mode:ident, -=)    => { 2 };
    ($mode:ident, ~)     => { 1 };
    (lenient, $tt:tt)    => { 0 };
    (strict, $tt:tt)     => {{ custom_punctuation_unexpected!($tt); 0 }};
}

// Not public API.
#[doc(hidden)]
#[macro_export]
macro_rules! custom_punctuation_unexpected {
    () => {};
}

// Not public API.
#[doc(hidden)]
#[macro_export]
macro_rules! stringify_punct {
    ($($tt:tt)+) => {
        concat!($(stringify!($tt)),+)
    };
}

// Not public API.
// Without this, local_inner_macros breaks when looking for concat!
#[doc(hidden)]
#[macro_export]
macro_rules! custom_punctuation_concat {
    ($($tt:tt)*) => {
        concat!($($tt)*)
    };
}
<|endoftext|>


<commit_before>use std::sync::{Arc, Mutex};
use std::thread::{self, JoinHandle};
use std::time::Duration;
use crossbeam::sync::MsQueue;
use env_logger;
use rustc_serialize::Decodable;

//pub trait MessageTrait: 'static + Sync + Send + Decodable {}

pub trait Transporter<M: 'static + Sync + Send + Decodable, E: 'static + Sized + Sync + Send> {
  fn tx(&self, m: &M) -> Result<(), E>;
  fn rx(&self) -> Result<M, E>;
}

pub struct EventBus<M: 'static + Sync + Send + Decodable, E: 'static + Sized + Sync + Send> {
  actors: Arc<Mutex<Vec<Box<Actor<M, E>>>>>,
  queue: Arc<MsQueue<M>>,
  stopped: Arc<Mutex<bool>>,
  thread: JoinHandle<Result<(), E>>,
  txpt: Option<Arc<Box<Transporter<M, E>>>>
}

unsafe impl<M: 'static + Sync + Send + Decodable, E: 'static + Sized + Sync + Send> Sync for EventBus<M, E> {}
unsafe impl<M: 'static + Sync + Send + Decodable, E: 'static + Sized + Sync + Send> Send for EventBus<M, E> {}

pub struct NullTransporter;

impl<M: 'static + Sync + Send + Decodable, E: 'static + Sized + Sync + Send> Transporter<M, E> for NullTransporter {
  fn tx(&self, m: &M) -> Result<(), E> {
    Ok(())
  }

  fn rx(&self) -> Result<M, E> {
    panic!("NullTransporter::rx shouldn't be called!");
  }
}

impl<M: Sync + Send + Decodable, E: Sized + Sync + Send> EventBus<M, E> {

  pub fn new(actors: Vec<Box<Actor<M,E>>>) -> EventBus<M, E> {
    let actors = Arc::new(Mutex::new(actors));
    let queue = Arc::new(MsQueue::new());
    let stopped = Arc::new(Mutex::new(false));
    let sleep_time = Duration::from_millis(50);

    EventBus {
      actors: actors.clone(),
      queue: queue.clone(),
      stopped: stopped.clone(),
      thread: run(stopped, queue, actors),
      txpt: None
    }
  }

  pub fn stop(&mut self) {
    debug!("stop enter");
    let mut stopped = self.stopped.lock().unwrap();
    *stopped = true;
    debug!("stop leave");
  }

  pub fn join(self) -> Result<(), E> {
    self.thread.join().unwrap()
  }

  pub fn send(&self, m: M) {
    self.queue.push(m);
  }
}

pub fn run<M, E>(stop: Arc<Mutex<bool>>, queue: Arc<MsQueue<M>>,
    actors: Arc<Mutex<Vec<Box<Actor<M, E>>>>>) -> JoinHandle<Result<(), E>>
    where M: 'static + Send + Sync + Decodable, E: 'static + Sync + Send {

  let sleep_time = Duration::from_millis(50);

  thread::spawn(move || -> Result<(), E> {

     loop {
        if let Some(m) = queue.try_pop() {
          for actor in actors.lock().unwrap().iter_mut().filter(|x| x.accept(&m)) {
            match actor.on_receive(&m) {
              Err(e) => return Err(e),
              _ => {}
            }
          }
       } else {
         thread::sleep(sleep_time);
        }

        if *stop.lock().unwrap() == true {
          break;
        }
      }

      Ok(())
  })
}

pub trait Actor<M: Sync + Send + Decodable, E: Sized + Send + Sync>: Send + Sync {
  fn accept(&self, m: &M) -> bool { true }
  fn on_receive(&mut self, m: &M) -> Result<(), E>;
}

#[cfg(test)]
mod tests {
  use std::thread;
  use std::time::Duration;

  use env_logger;
  use super::*;

  #[derive(RustcDecodable, RustcEncodable)]
  pub enum Message {
    Ask(String),
    Others
  }

  impl Message {
    pub fn ask(message: &str) -> Message {
      Message::Ask(message.to_owned())
    }
  }

  unsafe impl Send for Message {}
  unsafe impl Sync for Message {}

  pub struct TestActor;

  pub enum ActorErr {
    Err(String)
  }

  unsafe impl Send for ActorErr {}
  unsafe impl Sync for ActorErr {}

  impl Actor<Message, ActorErr> for TestActor {
    fn on_receive(&mut self, m: &Message) -> Result<(), ActorErr> {
      match *m {
        Message::Ask(ref s) => {
          debug!(">>> received: {}", s);
          Ok(())
        }
        _ => panic!("unknown message")
      }
    }
  }

  #[test]
  fn test() {
    env_logger::init().unwrap();

    let actors: Vec<Box<Actor<Message, ActorErr>>> = vec![Box::new(TestActor)];
    let mut dispatcher = EventBus::new(actors);

    let time = Duration::from_secs(5);
    dispatcher.send(Message::Ask("abc".to_owned()));
    thread::sleep(time);

    debug!("after sleep");
    dispatcher.stop();
    debug!("after stop");
    dispatcher.join().ok().unwrap();
  }
}<commit_msg>Simplify traits for message and error in react.<commit_after>use std::sync::{Arc, Mutex};
use std::thread::{self, JoinHandle};
use std::time::Duration;
use crossbeam::sync::MsQueue;
use env_logger;
use rustc_serialize::Decodable;

pub trait MsgTrait: 'static + Sync + Send + Decodable {}
pub trait Error: 'static + Sized + Sync + Send {}

pub trait Router<M: MsgTrait, E: Error> {
  fn tx(&self, m: &M) -> Result<(), E>;
  fn rx(&self) -> Result<M, E>;
}

pub struct EventBus<M: MsgTrait, E: Error> {
  actors: Arc<Mutex<Vec<Box<Actor<M, E>>>>>,
  queue: Arc<MsQueue<M>>,
  stopped: Arc<Mutex<bool>>,
  thread: JoinHandle<Result<(), E>>,
  txpt: Option<Arc<Box<Router<M, E>>>>
}

unsafe impl<M: MsgTrait, E: Error> Sync for EventBus<M, E> {}
unsafe impl<M: MsgTrait, E: Error> Send for EventBus<M, E> {}

pub struct NullRouter;

impl<M: MsgTrait, E: Error> Router<M, E> for NullRouter {
  fn tx(&self, m: &M) -> Result<(), E> {
    Ok(())
  }

  fn rx(&self) -> Result<M, E> {
    panic!("NullRouter::rx shouldn't be called!");
  }
}

impl<M: MsgTrait, E: Error> EventBus<M, E> {

  pub fn new(actors: Vec<Box<Actor<M,E>>>) -> EventBus<M, E> {
    let actors = Arc::new(Mutex::new(actors));
    let queue = Arc::new(MsQueue::new());
    let stopped = Arc::new(Mutex::new(false));
    let sleep_time = Duration::from_millis(50);

    EventBus {
      actors: actors.clone(),
      queue: queue.clone(),
      stopped: stopped.clone(),
      thread: run(stopped, queue, actors),
      txpt: None
    }
  }

  pub fn stop(&mut self) {
    debug!("stop enter");
    let mut stopped = self.stopped.lock().unwrap();
    *stopped = true;
    debug!("stop leave");
  }

  pub fn join(self) -> Result<(), E> {
    self.thread.join().unwrap()
  }

  pub fn send(&self, m: M) {
    self.queue.push(m);
  }
}

pub fn run<M, E>(stop: Arc<Mutex<bool>>, queue: Arc<MsQueue<M>>,
    actors: Arc<Mutex<Vec<Box<Actor<M, E>>>>>) -> JoinHandle<Result<(), E>>
    where M: MsgTrait, E: Error {

  let sleep_time = Duration::from_millis(50);

  thread::spawn(move || -> Result<(), E> {

     loop {
        if let Some(m) = queue.try_pop() {
          for actor in actors.lock().unwrap().iter_mut().filter(|x| x.accept(&m)) {
            match actor.on_receive(&m) {
              Err(e) => return Err(e),
              _ => {}
            }
          }
       } else {
         thread::sleep(sleep_time);
        }

        if *stop.lock().unwrap() == true {
          break;
        }
      }

      Ok(())
  })
}

pub trait Actor<M: MsgTrait, E: Error>: Send + Sync {
  fn accept(&self, m: &M) -> bool { true }
  fn on_receive(&mut self, m: &M) -> Result<(), E>;
}

#[cfg(test)]
mod tests {
  use std::thread;
  use std::time::Duration;

  use env_logger;
  use super::*;

  #[derive(RustcDecodable, RustcEncodable)]
  pub enum Message {
    Ask(String),
    Others
  }

  impl Message {
    pub fn ask(message: &str) -> Message {
      Message::Ask(message.to_owned())
    }
  }

  impl MsgTrait for Message {}
  unsafe impl Send for Message {}
  unsafe impl Sync for Message {}

  pub struct TestActor;

  pub enum ActorErr {
    Err(String)
  }
  impl Error for ActorErr {}
  unsafe impl Send for ActorErr {}
  unsafe impl Sync for ActorErr {}

  impl Actor<Message, ActorErr> for TestActor {
    fn on_receive(&mut self, m: &Message) -> Result<(), ActorErr> {
      match *m {
        Message::Ask(ref s) => {
          debug!(">>> received: {}", s);
          Ok(())
        }
        _ => panic!("unknown message")
      }
    }
  }

  #[test]
  fn test() {
    env_logger::init().unwrap();

    let actors: Vec<Box<Actor<Message, ActorErr>>> = vec![Box::new(TestActor)];
    let mut dispatcher = EventBus::new(actors);

    let time = Duration::from_secs(5);
    dispatcher.send(Message::Ask("abc".to_owned()));
    thread::sleep(time);

    debug!("after sleep");
    dispatcher.stop();
    debug!("after stop");
    dispatcher.join().ok().unwrap();
  }
}<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;
use std::hash::Hash;
use std::rc::Rc;
use std::fmt::Debug;

mod graph;
use graph::Graph;

#[derive(Debug, Copy, Clone)]
enum Tile<K> {
  Wall,
  Passage,
  Door(K),
  Key(K)
}

type Position = (usize, usize);
type PositionKeys<K> = (Position, Rc<Vec<K>>);
type PositionsKeys<K> = (Vec<Position>, Rc<Vec<K>>);
type Labyrinth<K> = HashMap<Position, Tile<K>>;

impl<K: Hash + Eq + Clone + Ord> Graph<PositionKeys<K>> for Labyrinth<K> {
  fn get_neighbors(&self, ((x, y), keys): PositionKeys<K>) -> Vec<PositionKeys<K>> {
    [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)].into_iter()
    .cloned()
    .filter(|&(x, y)| x > 0 && y > 0)
    .filter_map(|pos| match self.get(&pos) {
      Some(Tile::Passage) => {
        Some((pos, keys.clone()))
      },
      Some(Tile::Door(x)) if keys.contains(x) => {
        Some((pos, keys.clone()))
      },
      Some(Tile::Key(k)) => {
        Some((pos, {
          let mut keys = (*keys).clone();

          keys.push(k.clone());
          keys.sort();
          keys.dedup();

          Rc::new(keys)
        }))
      },
      _ => None
    })
    .collect()
  }
}

impl<K: Hash + Eq + Clone + Ord> Graph<PositionsKeys<K>> for Labyrinth<K> {
  fn get_neighbors(&self, (positions, keys): PositionsKeys<K>) -> Vec<PositionsKeys<K>> {
    positions.iter().cloned()
    .map(|position| (position, keys.clone()))
    .enumerate()
    .flat_map(|(i, position_keys)| {
      self.get_neighbors(position_keys).into_iter()
      .map(move |x| (i, x))
      .map(|(i, (position, keys))| {
        let mut positions = positions.clone();
        positions[i] = position;

        (positions, keys)
      })
    })
    .collect()
  }
}

fn get_input() -> std::io::Result<String> {
  let mut file = File::open("18.txt")?;
  let mut contents = String::new();
  file.read_to_string(&mut contents)?;

  Ok(contents)
}

fn parse_labyrinth(input: &str) -> (Labyrinth<char>, Option<Position>) {
  let labyrinth = input.lines()
    .enumerate()
    .flat_map(|(y, line)| {
      line.chars()
      .enumerate()
      .map(move |(x, c)| (
        (x, y),
        match c {
          '#' => Tile::Wall,
          '@' => Tile::Passage,
          c if c.is_ascii_uppercase() => Tile::Door(c.to_ascii_lowercase()),
          c if c.is_ascii_lowercase() => Tile::Key(c),
          _ => Tile::Passage
        }
      ))
    })
    .collect::<Labyrinth<_>>();

  let entrance = input.lines()
    .enumerate()
    .find_map(|(y, line)| {
      line.chars()
      .position(|c| c == '@')
      .map(|x| (x, y))
    });

  (labyrinth, entrance)
}

fn get_all_keys<K>(labyrinth: &Labyrinth<K>, position: Position, key_count: usize) -> Option<Vec<Position>>
where K: Hash + Eq + Clone + Ord {
  let mut bfs_iter = labyrinth.bfs((position, Rc::new(vec![])));

  bfs_iter
  .find(|(_, keys)| keys.len() == key_count)
  .and_then(|target| {
    bfs_iter.construct_path(target)
    .map(|path| {
      path.into_iter()
      .map(|(position, _)| position)
      .collect()
    })
  })
}

fn real_get_all_keys<K>(labyrinth: &Labyrinth<K>, positions: Vec<Position>, key_count: usize) -> Option<Vec<Vec<Position>>>
where K: Hash + Eq + Clone + Ord + Debug {
  let mut bfs_iter = labyrinth.bfs((positions, Rc::new(vec![])));

  bfs_iter
  .find(|(_, keys)| {
    if keys.len() > 5 {
      println!("{:?}", keys);
    }
    keys.len() == key_count
  })
  .and_then(|target| {
    bfs_iter.construct_path(target)
    .map(|path| {
      path.into_iter()
      .map(|(positions, _)| positions)
      .collect()
    })
  })
}

fn main() {
  let input = get_input().unwrap();
  let (mut labyrinth, position) = parse_labyrinth(&input);

  let path = get_all_keys(&labyrinth, position.unwrap(), 26);
  println!("Part 1: {}", path.unwrap().len() - 1);

  let (x, y) = position.unwrap();
  labyrinth.insert((x, y), Tile::Wall);
  labyrinth.insert((x - 1, y), Tile::Wall);
  labyrinth.insert((x + 1, y), Tile::Wall);
  labyrinth.insert((x, y - 1), Tile::Wall);
  labyrinth.insert((x, y + 1), Tile::Wall);

  let positions = vec![(x - 1, y - 1), (x + 1, y - 1), (x - 1, y + 1), (x + 1, y + 1)];
  let path = real_get_all_keys(&labyrinth, positions, 26);

  println!("Part 2: {}", path.unwrap().len() - 1);
}
<commit_msg>Add day 18 part 2 solution<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::collections::HashMap;
use std::hash::Hash;
use std::rc::Rc;

mod graph;
use graph::Graph;

#[derive(Debug, Copy, Clone)]
enum Tile<K> {
  Wall,
  Passage,
  Door(K),
  Key(K)
}

type Position = (usize, usize);
type PositionKeys<K> = (Position, Rc<Vec<K>>);
type Labyrinth<K> = HashMap<Position, Tile<K>>;

impl<K: Hash + Eq + Clone + Ord> Graph<PositionKeys<K>> for Labyrinth<K> {
  fn get_neighbors(&self, ((x, y), keys): PositionKeys<K>) -> Vec<PositionKeys<K>> {
    [(x - 1, y), (x + 1, y), (x, y - 1), (x, y + 1)].into_iter()
    .cloned()
    .filter(|&(x, y)| x > 0 && y > 0)
    .filter_map(|pos| match self.get(&pos) {
      Some(Tile::Passage) => {
        Some((pos, keys.clone()))
      },
      Some(Tile::Door(x)) if keys.contains(x) => {
        Some((pos, keys.clone()))
      },
      Some(Tile::Key(k)) => {
        Some((pos, {
          let mut keys = (*keys).clone();

          keys.push(k.clone());
          keys.sort();
          keys.dedup();

          Rc::new(keys)
        }))
      },
      _ => None
    })
    .collect()
  }
}

fn get_input() -> std::io::Result<String> {
  let mut file = File::open("18.txt")?;
  let mut contents = String::new();
  file.read_to_string(&mut contents)?;

  Ok(contents)
}

fn parse_labyrinth(input: &str) -> (Labyrinth<char>, Option<Position>) {
  let labyrinth = input.lines()
    .enumerate()
    .flat_map(|(y, line)| {
      line.chars()
      .enumerate()
      .map(move |(x, c)| (
        (x, y),
        match c {
          '#' => Tile::Wall,
          '@' => Tile::Passage,
          c if c.is_ascii_uppercase() => Tile::Door(c.to_ascii_lowercase()),
          c if c.is_ascii_lowercase() => Tile::Key(c),
          _ => Tile::Passage
        }
      ))
    })
    .collect::<Labyrinth<_>>();

  let entrance = input.lines()
    .enumerate()
    .find_map(|(y, line)| {
      line.chars()
      .position(|c| c == '@')
      .map(|x| (x, y))
    });

  (labyrinth, entrance)
}

fn get_all_keys<K>(labyrinth: &Labyrinth<K>, position_key: PositionKeys<K>, key_count: usize) -> Option<Vec<Position>>
where K: Hash + Eq + Clone + Ord {
  let mut bfs_iter = labyrinth.bfs(position_key);

  bfs_iter
  .find(|(_, keys)| keys.len() == key_count)
  .and_then(|target| {
    bfs_iter.construct_path(target)
    .map(|path| {
      path.into_iter()
      .map(|(position, _)| position)
      .collect()
    })
  })
}

fn get_size<K>(labyrinth: &Labyrinth<K>) -> (usize, usize) {
  let size = labyrinth.keys().cloned()
    .fold((None, None), |(max_x, max_y), (x, y)| {
      (
        [max_x, Some(x)].into_iter().filter_map(|&x| x).max(),
        [max_y, Some(y)].into_iter().filter_map(|&y| y).max()
      )
    });

  match size {
    (Some(x), Some(y)) => (x + 1, y + 1),
    _ => (0, 0)
  }
}

fn real_get_all_keys<K>(
  labyrinth: &Labyrinth<K>,
  (x, y): Position,
  key_count: usize
) -> (Option<Vec<Position>>, Option<Vec<Position>>, Option<Vec<Position>>, Option<Vec<Position>>)
where K: Hash + Eq + Clone + Ord {
  let (width, height) = get_size(labyrinth);
  let positions = vec![(x - 1, y - 1), (x + 1, y - 1), (x - 1, y + 1), (x + 1, y + 1)];

  let keys = labyrinth.iter()
    .filter_map(|(&position, tile)| match tile {
      Tile::Key(k) => Some((position, k.clone())),
      _ => None
    })
    .collect::<Vec<_>>();

  let position_keys = positions.into_iter()
    .enumerate()
    .map(|(i, position)| {
      let ignore_keys = keys.iter().cloned()
        .filter(|&((x, y), _)| {
          if i == 0 {
            x > width / 2 || y > height / 2
          } else if i == 1 {
            x <= width / 2 || y > height / 2
          } else if i == 2 {
            x > width / 2 || y <= height / 2
          } else if i == 3 {
            x <= width / 2 || y <= height / 2
          } else {
            panic!()
          }
        })
        .map(|(_, k)| k.clone())
        .collect::<Vec<_>>();

      (position, Rc::new(ignore_keys))
    });

  let mut results = position_keys
    .filter_map(|position_key| get_all_keys(labyrinth, position_key, key_count));

  (results.next(), results.next(), results.next(), results.next())
}

fn main() {
  let input = get_input().unwrap();
  let (mut labyrinth, position) = parse_labyrinth(&input);

  let path = get_all_keys(&labyrinth, (position.unwrap(), Rc::new(vec![])), 26);
  println!("Part 1: {}", path.unwrap().len() - 1);

  let (x, y) = position.unwrap();
  labyrinth.insert((x, y), Tile::Wall);
  labyrinth.insert((x - 1, y), Tile::Wall);
  labyrinth.insert((x + 1, y), Tile::Wall);
  labyrinth.insert((x, y - 1), Tile::Wall);
  labyrinth.insert((x, y + 1), Tile::Wall);

  let (p1, p2, p3, p4) = real_get_all_keys(&labyrinth, (x, y), 26);
  println!("Part 2: {}", p1.unwrap().len() + p2.unwrap().len() + p3.unwrap().len() + p4.unwrap().len() - 4);
}
<|endoftext|>


<commit_before>use gl::types::*;

pub struct Renderbuffer {
    gl_id: GLuint
}
<commit_msg>Add `Renderbuffer.gl_id()`<commit_after>use gl::types::*;

pub struct Renderbuffer {
    gl_id: GLuint
}

impl Renderbuffer {
    pub fn gl_id(&self) -> GLuint {
        self.gl_id
    }
}
<|endoftext|>


<commit_before>use ast;
use ast::{
	NumberType,
	VectorType,
	Value,
		NumberValue,
		VectorValue,
};
use eval;
use resolve::context::Context;
use resolve::scope::{ Scope, Item, ConstantItem, ValueItem, TupleItem, ValueRef, Dynamic, Ignored, Poison, propagate_pair};
use resolve::types::{Type, TopType, common_type, common_type_all };

pub fn resolve_expr<'s>(ctx: &mut Context<'s>, scope: &Scope<'s>, e: &ast::Expr) -> Item<'s> {
	match *e {
		ast::IgnoreExpr => ValueItem(TopType, Ignored, Ignored),
		ast::ValueExpr(ref val) => ConstantItem(val.clone()),

		ast::FlipExpr(box ref down, box ref up) => {
			let (down_type, down_ref) = match resolve_expr(ctx, scope, down) {
				ConstantItem(v) => (v.get_type(), ctx.down_op(eval::ConstOp(v))),
				ValueItem(down_type, down_ref, _) => (down_type, down_ref),
				_ => fail!("Non-value type in flip")

			};

			let (up_type, up_ref) = match resolve_expr(ctx, scope, up) {
				ConstantItem(v) => (v.get_type(), ctx.up_op(0, |cell| eval::CheckOp(cell, v.clone()))),
				ValueItem(up_type, _, up_ref) => (up_type, up_ref),
				_ => fail!("Non-value type in flip")
			};

			let common_type = common_type(down_type, up_type).expect("Flip expr sides must be of common type");
			ValueItem(common_type, down_ref, up_ref)
		}

		ast::RangeExpr(box ref min_expr, box ref max_expr) => {
			fn get_const_default_num(i: Item, _default: f64) -> f64 {
				match i {
					ConstantItem(NumberValue(v)) => v,
					_ => fail!("Range expressions must be numeric constant")
				}
			}

			let min = get_const_default_num(resolve_expr(ctx, scope, min_expr), Float::neg_infinity());
			let max = get_const_default_num(resolve_expr(ctx, scope, max_expr), Float::infinity());

			let up = ctx.up_op(0, |cell| eval::RangeCheckOp(cell, min, max));

			ValueItem(NumberType, Poison("Range can only be up-evaluated"), up)
		}

		ast::ChooseExpr(box ref e, ref c) => {
			let pairs: Vec<(Value, Value)> = c.iter().map(|&(ref le, ref re)| {
				let l = resolve_expr(ctx, scope, le);
				let r = resolve_expr(ctx, scope, re);

				match (l, r) {
					(ConstantItem(lv), ConstantItem(rv)) => (lv, rv),
					_ => fail!("Choose expression arms must be constant, for now")
				}
			}).collect();

			match resolve_expr(ctx, scope, e) {
				ConstantItem(v) => ConstantItem(eval::eval_choose(&v, pairs.as_slice()).expect("Choice up not complete")),
				ValueItem(_t, d, u) => {
					ValueItem(common_type_all(pairs.iter().map(|&(_, ref r)| r.get_type())).expect("Right sides are not of common type"),
						d.propagate(|d| ctx.down_op(eval::ChooseOp(d, pairs.clone()))),
						u.propagate(|u| ctx.up_op(u, |cell| eval::ChooseOp(cell,
							pairs.iter().map(|&(ref l, ref r)| (r.clone(), l.clone())).collect()
						)))
					)
				}
				_ => fail!("Invalid type in choice expr")
			}

			// TODO: non-constant arms, check types for case coverage
		}

		ast::ConcatExpr(ref v) =>  {
			let mut len = 0;
			let mut consts = Vec::new();

			let mut down_parts = Vec::new();
			let mut down_poison = None;

			let mut up_parts = Vec::new();
			let mut up_poison = None;

			for e in v.iter() {
				match resolve_expr(ctx, scope, e) {
					ConstantItem(v) => {
						consts.push(v);
					}
					ValueItem(_t, d, u) => {
						if down_poison.is_none() {
							if consts.len() != 0 { down_parts.push(eval::ConstSlice(consts.clone())); }
							match d {
								Dynamic(id) => down_parts.push(eval::DynElem(id)),
								Ignored => { down_poison = Some(Poison("Some elements are ignored in down evaluation")) }
								Poison(..) => { down_poison = Some(d) }
							}
						}

						if up_poison.is_none() {
							if consts.len() != 0 { up_parts.push(eval::ConstSlice(consts.clone())); }
							match u {
								Dynamic(id) => up_parts.push(eval::DynElem(id)),
								Ignored => (),
								Poison(..) => { up_poison = Some(u) }
							}
						}

						len += consts.len() + 1;
						consts.clear();
					}
					_ => fail!("Concatinating values that are not vectors")
				}
			}

			if len == 0 { // Length is only incremented on non-constant elements
				ConstantItem(VectorValue(consts))
			} else {
				let d = match down_poison {
					Some(p) => p,
					None => {
						if consts.len() != 0 { down_parts.push(eval::ConstSlice(consts.clone())); }
						ctx.down_op(eval::ConcatOp(down_parts))
					}
				};

				let u = match up_poison {
					Some(p) => p,
					None => {
						if consts.len() != 0 { up_parts.push(eval::ConstSlice(consts.clone())); }
						if up_parts.len() != 0 {
							let up_ref = ctx.make_register();
							let mut pos = 0;
							for elem in up_parts.into_iter() {
								match elem {
									eval::ConstSlice(v) => {
										let slice = ctx.make_register();
										ctx.add_up_op(slice, eval::ElemOp(up_ref, pos));
										pos += v.len();
										ctx.add_up_op(0, eval::CheckOp(slice, VectorValue(v)));
									}
									eval::DynElem(id) => {
										ctx.add_up_op(id, eval::ElemOp(up_ref, pos));
										pos += 1;
									}
									eval::DynSlice(id, len) => {
										ctx.add_up_op(id, eval::SliceOp(up_ref, pos, len));
										pos += len;
									}
								}
							}
							Dynamic(up_ref)
						} else { Ignored }
					}
				};

				ValueItem(VectorType(len), d, u)
			}
		}

		ast::BinExpr(box ref a, op, box ref b) => {
			fn one_const<'s>(ctx: &mut Context<'s>, op: eval::BinOp, _a_type: Type, a_down: ValueRef, a_up: ValueRef, b: f64) -> Item<'s> {
				// TODO: check type
				ValueItem(NumberType,
					a_down.propagate(|a| ctx.down_op(eval::BinaryConstOp(a, op, b))),
					a_up.propagate(|a| ctx.up_op(a, |i| eval::BinaryConstOp(i, op.invert(), b)))
				)
			}

			match (resolve_expr(ctx, scope, a), resolve_expr(ctx, scope, b)) {
				(ConstantItem(NumberValue(a)), ConstantItem(NumberValue(b))) => {
					ConstantItem(NumberValue(op.eval(a, b)))
				}
				(ValueItem(a_type, a_down, a_up), ConstantItem(NumberValue(b))) => {
					one_const(ctx, op, a_type, a_down, a_up, b)
				}
				(ConstantItem(NumberValue(a)), ValueItem(b_type, b_down, b_up)) => {
					one_const(ctx, op.swap(), b_type, b_down, b_up, a)
				}
				(ValueItem(_a_type, a_down, _), ValueItem(_b_type, b_down, _)) => {
					// TODO: check type
					ValueItem(NumberType,
						propagate_pair(a_down, b_down, |a, b| ctx.down_op(eval::BinaryOp(a, op, b))),
						Poison("At least one side of an up-evaluated binary operator must be constant")
					)
				}
				_ => fail!("Invalid types in binary {}", op)
			}
		}

		ast::VarExpr(ref name) => {
			scope.get(name.as_slice()).expect("Undefined variable")
		}

		ast::TupExpr(ref items) => {
			TupleItem(items.iter().map(|i| resolve_expr(ctx, scope, i)).collect())
		}

		ast::DotExpr(box ref _lexpr, ref _name) => unimplemented!(),
	}
}

pub fn resolve_pattern<'s>(ctx: &mut Context<'s>, scope: &mut Scope<'s>, l: &ast::Expr, r: Item<'s>) {
	match *l {
		ast::IgnoreExpr => (),
		ast::ValueExpr(ref _val) => fail!("patterns cannot be falsifiable"),
		ast::RangeExpr(box ref _min_expr, box ref _max_expr) => fail!("patterns cannot be refutable"),

		ast::FlipExpr(box ref _down, box ref _up) => unimplemented!(),
		ast::ChooseExpr(box ref _e, ref _c) => unimplemented!(),
		ast::ConcatExpr(ref _v) =>  unimplemented!(),
		ast::BinExpr(box ref _a, _op, box ref _b) => unimplemented!(),

		ast::VarExpr(ref name) => {
			scope.bind(name.as_slice(), r);
		}

		ast::TupExpr(ref exprs) => {
			match r {
				TupleItem(v) => {
					if exprs.len() != v.len() {
						fail!("can't bind a tuple with a different length");
					}
					for (expr, item) in exprs.iter().zip(v.into_iter()) {
						resolve_pattern(ctx, scope, expr, item);
					}
				}
				_ => fail!("can't bind a tuple with a non-tuple")
			}
		}

		ast::DotExpr(box ref _lexpr, ref _name) => fail!("Cannot declare a property"),
	}
}

#[cfg(test)]
mod test {
	use super::resolve_expr;
	use session::Session;
	use resolve::context::{Context, ValueID};
	use resolve::types::{Type, TopType, NumberType, SymbolType};
	use ast::{
		Value,
			NumberValue,
			IntegerValue,
			VectorValue,
			SymbolValue,
	};
	use resolve::scope::{
		Scope,
		Item,
			ConstantItem,
			ValueItem,
		ValueRef,
			Dynamic,
			Ignored,
	};
	use grammar;

	static XD: ValueID = 100;
	static XU: ValueID = 101;
	static YD: ValueID = 102;
	static YU: ValueID = 103;

	fn check(s: &str, test: proc(Item)) {
		let ses = Session::new();
		let mut ctx = Context::new(&ses);
		let mut scope = Scope::new();
		scope.bind("x", ValueItem(TopType, Dynamic(XD), Dynamic(XU)));
		scope.bind("y", ValueItem(TopType, Dynamic(YD), Dynamic(YU)));
		let e = grammar::valexpr(s).unwrap();
		let r = resolve_expr(&mut ctx, &scope, &e);
		test(r)
	}

	fn check_const(s: &str, v: Value) {
		check(s, proc(r) assert_eq!(r, ConstantItem(v)));
	}

	fn check_dyn(s: &str, t: Type, d: ValueRef, u: ValueRef) {
		check(s, proc(r) {
			assert_eq!(r, ValueItem(t, d, u))
		})
	}

	#[test] fn literal_number() { check_const("55",   NumberValue(55f64)); }
	#[test] fn literal_symbol() { check_const("#foo", SymbolValue("foo".to_string())); }
	#[test] fn literal_int()    { check_const("#10",  IntegerValue(10)); }

	#[test] fn const_add()      { check_const("2 + 3", NumberValue(5f64)); }
	#[test] fn const_switch()   { check_const("(#bar)[#foo=#a, #bar=#b, #baz=#c]", SymbolValue("b".to_string())); }
	#[test] fn const_concat()   { check_const("[#1, #2]", VectorValue(vec![IntegerValue(1), IntegerValue(2)])); }

	#[test] fn flip() {
		check_dyn("x!y", TopType, Dynamic(XD), Dynamic(YU));
		check_dyn("<:x", TopType, Dynamic(XD), Ignored);
		check_dyn(":>x", TopType, Ignored, Dynamic(XU));
	}

	#[test] fn ignore_propagate() {
		check_dyn("2+ignore", NumberType, Ignored, Ignored);
		check_dyn("ignore[#foo=#a]", SymbolType, Ignored, Ignored);
	}

	#[test]
	#[should_fail]
	fn test_add_wrongtype() {
		check_const("2 + #test", NumberValue(2.)); // TODO: make sure it fails for the right reason
	}
}
<commit_msg>resolve_pattern for literals and flip<commit_after>use ast;
use ast::{
	NumberType,
	VectorType,
	Value,
		NumberValue,
		VectorValue,
};
use eval;
use resolve::context::Context;
use resolve::scope::{ Scope, Item, ConstantItem, ValueItem, TupleItem, ValueRef, Dynamic, Ignored, Poison, propagate_pair};
use resolve::types::{Type, TopType, common_type, common_type_all };

pub fn resolve_expr<'s>(ctx: &mut Context<'s>, scope: &Scope<'s>, e: &ast::Expr) -> Item<'s> {
	match *e {
		ast::IgnoreExpr => ValueItem(TopType, Ignored, Ignored),
		ast::ValueExpr(ref val) => ConstantItem(val.clone()),

		ast::FlipExpr(box ref down, box ref up) => {
			let (down_type, down_ref) = match resolve_expr(ctx, scope, down) {
				ConstantItem(v) => (v.get_type(), ctx.down_op(eval::ConstOp(v))),
				ValueItem(down_type, down_ref, _) => (down_type, down_ref),
				_ => fail!("Non-value type in flip")

			};

			let (up_type, up_ref) = match resolve_expr(ctx, scope, up) {
				ConstantItem(v) => (v.get_type(), ctx.up_op(0, |cell| eval::CheckOp(cell, v.clone()))),
				ValueItem(up_type, _, up_ref) => (up_type, up_ref),
				_ => fail!("Non-value type in flip")
			};

			let common_type = common_type(down_type, up_type).expect("Flip expr sides must be of common type");
			ValueItem(common_type, down_ref, up_ref)
		}

		ast::RangeExpr(box ref min_expr, box ref max_expr) => {
			fn get_const_default_num(i: Item, _default: f64) -> f64 {
				match i {
					ConstantItem(NumberValue(v)) => v,
					_ => fail!("Range expressions must be numeric constant")
				}
			}

			let min = get_const_default_num(resolve_expr(ctx, scope, min_expr), Float::neg_infinity());
			let max = get_const_default_num(resolve_expr(ctx, scope, max_expr), Float::infinity());

			let up = ctx.up_op(0, |cell| eval::RangeCheckOp(cell, min, max));

			ValueItem(NumberType, Poison("Range can only be up-evaluated"), up)
		}

		ast::ChooseExpr(box ref e, ref c) => {
			let pairs: Vec<(Value, Value)> = c.iter().map(|&(ref le, ref re)| {
				let l = resolve_expr(ctx, scope, le);
				let r = resolve_expr(ctx, scope, re);

				match (l, r) {
					(ConstantItem(lv), ConstantItem(rv)) => (lv, rv),
					_ => fail!("Choose expression arms must be constant, for now")
				}
			}).collect();

			match resolve_expr(ctx, scope, e) {
				ConstantItem(v) => ConstantItem(eval::eval_choose(&v, pairs.as_slice()).expect("Choice up not complete")),
				ValueItem(_t, d, u) => {
					ValueItem(common_type_all(pairs.iter().map(|&(_, ref r)| r.get_type())).expect("Right sides are not of common type"),
						d.propagate(|d| ctx.down_op(eval::ChooseOp(d, pairs.clone()))),
						u.propagate(|u| ctx.up_op(u, |cell| eval::ChooseOp(cell,
							pairs.iter().map(|&(ref l, ref r)| (r.clone(), l.clone())).collect()
						)))
					)
				}
				_ => fail!("Invalid type in choice expr")
			}

			// TODO: non-constant arms, check types for case coverage
		}

		ast::ConcatExpr(ref v) =>  {
			let mut len = 0;
			let mut consts = Vec::new();

			let mut down_parts = Vec::new();
			let mut down_poison = None;

			let mut up_parts = Vec::new();
			let mut up_poison = None;

			for e in v.iter() {
				match resolve_expr(ctx, scope, e) {
					ConstantItem(v) => {
						consts.push(v);
					}
					ValueItem(_t, d, u) => {
						if down_poison.is_none() {
							if consts.len() != 0 { down_parts.push(eval::ConstSlice(consts.clone())); }
							match d {
								Dynamic(id) => down_parts.push(eval::DynElem(id)),
								Ignored => { down_poison = Some(Poison("Some elements are ignored in down evaluation")) }
								Poison(..) => { down_poison = Some(d) }
							}
						}

						if up_poison.is_none() {
							if consts.len() != 0 { up_parts.push(eval::ConstSlice(consts.clone())); }
							match u {
								Dynamic(id) => up_parts.push(eval::DynElem(id)),
								Ignored => (),
								Poison(..) => { up_poison = Some(u) }
							}
						}

						len += consts.len() + 1;
						consts.clear();
					}
					_ => fail!("Concatinating values that are not vectors")
				}
			}

			if len == 0 { // Length is only incremented on non-constant elements
				ConstantItem(VectorValue(consts))
			} else {
				let d = match down_poison {
					Some(p) => p,
					None => {
						if consts.len() != 0 { down_parts.push(eval::ConstSlice(consts.clone())); }
						ctx.down_op(eval::ConcatOp(down_parts))
					}
				};

				let u = match up_poison {
					Some(p) => p,
					None => {
						if consts.len() != 0 { up_parts.push(eval::ConstSlice(consts.clone())); }
						if up_parts.len() != 0 {
							let up_ref = ctx.make_register();
							let mut pos = 0;
							for elem in up_parts.into_iter() {
								match elem {
									eval::ConstSlice(v) => {
										let slice = ctx.make_register();
										ctx.add_up_op(slice, eval::ElemOp(up_ref, pos));
										pos += v.len();
										ctx.add_up_op(0, eval::CheckOp(slice, VectorValue(v)));
									}
									eval::DynElem(id) => {
										ctx.add_up_op(id, eval::ElemOp(up_ref, pos));
										pos += 1;
									}
									eval::DynSlice(id, len) => {
										ctx.add_up_op(id, eval::SliceOp(up_ref, pos, len));
										pos += len;
									}
								}
							}
							Dynamic(up_ref)
						} else { Ignored }
					}
				};

				ValueItem(VectorType(len), d, u)
			}
		}

		ast::BinExpr(box ref a, op, box ref b) => {
			fn one_const<'s>(ctx: &mut Context<'s>, op: eval::BinOp, _a_type: Type, a_down: ValueRef, a_up: ValueRef, b: f64) -> Item<'s> {
				// TODO: check type
				ValueItem(NumberType,
					a_down.propagate(|a| ctx.down_op(eval::BinaryConstOp(a, op, b))),
					a_up.propagate(|a| ctx.up_op(a, |i| eval::BinaryConstOp(i, op.invert(), b)))
				)
			}

			match (resolve_expr(ctx, scope, a), resolve_expr(ctx, scope, b)) {
				(ConstantItem(NumberValue(a)), ConstantItem(NumberValue(b))) => {
					ConstantItem(NumberValue(op.eval(a, b)))
				}
				(ValueItem(a_type, a_down, a_up), ConstantItem(NumberValue(b))) => {
					one_const(ctx, op, a_type, a_down, a_up, b)
				}
				(ConstantItem(NumberValue(a)), ValueItem(b_type, b_down, b_up)) => {
					one_const(ctx, op.swap(), b_type, b_down, b_up, a)
				}
				(ValueItem(_a_type, a_down, _), ValueItem(_b_type, b_down, _)) => {
					// TODO: check type
					ValueItem(NumberType,
						propagate_pair(a_down, b_down, |a, b| ctx.down_op(eval::BinaryOp(a, op, b))),
						Poison("At least one side of an up-evaluated binary operator must be constant")
					)
				}
				_ => fail!("Invalid types in binary {}", op)
			}
		}

		ast::VarExpr(ref name) => {
			scope.get(name.as_slice()).expect("Undefined variable")
		}

		ast::TupExpr(ref items) => {
			TupleItem(items.iter().map(|i| resolve_expr(ctx, scope, i)).collect())
		}

		ast::DotExpr(box ref _lexpr, ref _name) => unimplemented!(),
	}
}

pub fn resolve_pattern<'s>(ctx: &mut Context<'s>, scope: &mut Scope<'s>, l: &ast::Expr, r: Item<'s>) {
	match *l {
		ast::IgnoreExpr => (),
		ast::ValueExpr(ref val) => {
			match r {
				ConstantItem(ref v) => {
					if v != val { fail!("Match always fails"); }
				}
				ValueItem(_t, d, u) => {
					// TODO: type check
					d.propagate(|d| ctx.down_op(eval::CheckOp(d, val.clone())));
					u.propagate(|u| ctx.up_op(u, |_| eval::ConstOp(val.clone())));
				}
				_ => fail!("Type error")
			}
		},
		ast::RangeExpr(box ref _min_expr, box ref _max_expr) => fail!("patterns cannot be refutable"),
		ast::FlipExpr(box ref down, box ref up) => {
				match r {
					ConstantItem(..) => unimplemented!(),
					ValueItem(t, d, u) => {
						resolve_pattern(ctx, scope, down, ValueItem(t, d, Ignored));
						resolve_pattern(ctx, scope, up,   ValueItem(t, Ignored, u));
					}
					_ => fail!("Type error")
				}
		}
		ast::ChooseExpr(box ref _e, ref _c) => unimplemented!(),
		ast::ConcatExpr(ref _v) =>  unimplemented!(),
		ast::BinExpr(box ref _a, _op, box ref _b) => unimplemented!(),

		ast::VarExpr(ref name) => {
			debug!("defined {} = {}", name, r);
			scope.bind(name.as_slice(), r);
		}

		ast::TupExpr(ref exprs) => {
			match r {
				TupleItem(v) => {
					if exprs.len() != v.len() {
						fail!("can't bind a tuple with a different length");
					}
					for (expr, item) in exprs.iter().zip(v.into_iter()) {
						resolve_pattern(ctx, scope, expr, item);
					}
				}
				_ => fail!("can't bind a tuple with a non-tuple")
			}
		}

		ast::DotExpr(box ref _lexpr, ref _name) => fail!("Cannot declare a property"),
	}
}

#[cfg(test)]
mod test {
	use super::resolve_expr;
	use session::Session;
	use resolve::context::{Context, ValueID};
	use resolve::types::{Type, TopType, NumberType, SymbolType};
	use ast::{
		Value,
			NumberValue,
			IntegerValue,
			VectorValue,
			SymbolValue,
	};
	use resolve::scope::{
		Scope,
		Item,
			ConstantItem,
			ValueItem,
		ValueRef,
			Dynamic,
			Ignored,
	};
	use grammar;

	static XD: ValueID = 100;
	static XU: ValueID = 101;
	static YD: ValueID = 102;
	static YU: ValueID = 103;

	fn check(s: &str, test: proc(Item)) {
		let ses = Session::new();
		let mut ctx = Context::new(&ses);
		let mut scope = Scope::new();
		scope.bind("x", ValueItem(TopType, Dynamic(XD), Dynamic(XU)));
		scope.bind("y", ValueItem(TopType, Dynamic(YD), Dynamic(YU)));
		let e = grammar::valexpr(s).unwrap();
		let r = resolve_expr(&mut ctx, &scope, &e);
		test(r)
	}

	fn check_const(s: &str, v: Value) {
		check(s, proc(r) assert_eq!(r, ConstantItem(v)));
	}

	fn check_dyn(s: &str, t: Type, d: ValueRef, u: ValueRef) {
		check(s, proc(r) {
			assert_eq!(r, ValueItem(t, d, u))
		})
	}

	#[test] fn literal_number() { check_const("55",   NumberValue(55f64)); }
	#[test] fn literal_symbol() { check_const("#foo", SymbolValue("foo".to_string())); }
	#[test] fn literal_int()    { check_const("#10",  IntegerValue(10)); }

	#[test] fn const_add()      { check_const("2 + 3", NumberValue(5f64)); }
	#[test] fn const_switch()   { check_const("(#bar)[#foo=#a, #bar=#b, #baz=#c]", SymbolValue("b".to_string())); }
	#[test] fn const_concat()   { check_const("[#1, #2]", VectorValue(vec![IntegerValue(1), IntegerValue(2)])); }

	#[test] fn flip() {
		check_dyn("x!y", TopType, Dynamic(XD), Dynamic(YU));
		check_dyn("<:x", TopType, Dynamic(XD), Ignored);
		check_dyn(":>x", TopType, Ignored, Dynamic(XU));
	}

	#[test] fn ignore_propagate() {
		check_dyn("2+ignore", NumberType, Ignored, Ignored);
		check_dyn("ignore[#foo=#a]", SymbolType, Ignored, Ignored);
	}

	#[test]
	#[should_fail]
	fn test_add_wrongtype() {
		check_const("2 + #test", NumberValue(2.)); // TODO: make sure it fails for the right reason
	}
}
<|endoftext|>


<commit_before>use std::error::Error;

use conduit::{Request, Response, Handler};
use conduit_static::Static;
use conduit_middleware::AroundMiddleware;

use util::RequestProxy;

pub struct Middleware {
    handler: Option<Box<Handler>>,
    dist: Static,
}

impl Middleware {
    pub fn new() -> Middleware {
        Middleware {
            handler: None,
            dist: Static::new("dist"),
        }
    }
}

impl AroundMiddleware for Middleware {
    fn with_handler(&mut self, handler: Box<Handler>) {
        self.handler = Some(handler);
    }
}

impl Handler for Middleware {
    fn call(&self, req: &mut Request) -> Result<Response, Box<Error+Send>> {
        // First, attempt to serve a static file. If we're missing a static
        // file, then keep going.
        match self.dist.call(req) {
            Ok(ref resp) if resp.status.0 == 404 => {}
            ret => return ret,
        }

        // Second, if we're requesting html, then we've only got one page so
        // serve up that page. Otherwise proxy on to the rest of the app.
        let wants_html = req.headers().find("Accept").map(|accept| {
            accept.iter().any(|s| s.contains("html"))
        }).unwrap_or(true); // If no Accept header is specified, serve up html.
        if wants_html {
            self.dist.call(&mut RequestProxy {
                other: req,
                path: Some("/index.html"),
                method: None,
            })
        } else {
            self.handler.as_ref().unwrap().call(req)
        }
    }
}
<commit_msg>Revert "Assume html if no Accept header is presented"<commit_after>use std::error::Error;

use conduit::{Request, Response, Handler};
use conduit_static::Static;
use conduit_middleware::AroundMiddleware;

use util::RequestProxy;

pub struct Middleware {
    handler: Option<Box<Handler>>,
    dist: Static,
}

impl Middleware {
    pub fn new() -> Middleware {
        Middleware {
            handler: None,
            dist: Static::new("dist"),
        }
    }
}

impl AroundMiddleware for Middleware {
    fn with_handler(&mut self, handler: Box<Handler>) {
        self.handler = Some(handler);
    }
}

impl Handler for Middleware {
    fn call(&self, req: &mut Request) -> Result<Response, Box<Error+Send>> {
        // First, attempt to serve a static file. If we're missing a static
        // file, then keep going.
        match self.dist.call(req) {
            Ok(ref resp) if resp.status.0 == 404 => {}
            ret => return ret,
        }

        // Second, if we're requesting html, then we've only got one page so
        // serve up that page. Otherwise proxy on to the rest of the app.
        let wants_html = req.headers().find("Accept").map(|accept| {
            accept.iter().any(|s| s.contains("html"))
        }).unwrap_or(false);
        if wants_html {
            self.dist.call(&mut RequestProxy {
                other: req,
                path: Some("/index.html"),
                method: None,
            })
        } else {
            self.handler.as_ref().unwrap().call(req)
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2019 mysql_async contributors
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use futures_core::stream::Stream;
use futures_util::stream::futures_unordered::FuturesUnordered;
use tokio::sync::mpsc;

use std::future::Future;
use std::pin::Pin;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::task::{Context, Poll};

use super::{IdlingConn, Inner};
use crate::{BoxFuture, Conn, PoolOptions};
use tokio::sync::mpsc::UnboundedReceiver;

pub struct Recycler {
    inner: Arc<Inner>,
    discard: FuturesUnordered<BoxFuture<()>>,
    discarded: usize,
    cleaning: FuturesUnordered<BoxFuture<Conn>>,

    // Option<Conn> so that we have a way to send a "I didn't make a Conn after all" signal
    dropped: mpsc::UnboundedReceiver<Option<Conn>>,
    /// Pool options.
    pool_opts: PoolOptions,
    eof: bool,
}

impl Recycler {
    pub fn new(
        pool_opts: PoolOptions,
        inner: Arc<Inner>,
        dropped: UnboundedReceiver<Option<Conn>>,
    ) -> Self {
        Self {
            inner,
            discard: FuturesUnordered::new(),
            discarded: 0,
            cleaning: FuturesUnordered::new(),
            dropped,
            pool_opts,
            eof: false,
        }
    }
}

impl Future for Recycler {
    type Output = ();

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let mut close = self.inner.close.load(Ordering::Acquire);

        macro_rules! conn_decision {
            ($self:ident, $conn:ident) => {
                if $conn.inner.stream.is_none() || $conn.inner.disconnected {
                    // drop unestablished connection
                    $self.discard.push(Box::pin(::futures_util::future::ok(())));
                } else if $conn.inner.in_transaction || $conn.inner.has_result.is_some() {
                    $self.cleaning.push(Box::pin($conn.cleanup()));
                } else if $conn.expired() || close {
                    $self.discard.push(Box::pin($conn.close()));
                } else {
                    let mut exchange = $self.inner.exchange.lock().unwrap();
                    if exchange.available.len() >= $self.pool_opts.active_bound() {
                        drop(exchange);
                        $self.discard.push(Box::pin($conn.close()));
                    } else {
                        exchange.available.push_back($conn.into());
                        if let Some(w) = exchange.waiting.pop_front() {
                            w.wake();
                        }
                    }
                }
            };
        }

        while !self.eof {
            // see if there are more connections for us to recycle
            match Pin::new(&mut self.dropped).poll_next(cx) {
                Poll::Ready(Some(Some(conn))) => {
                    assert!(conn.inner.pool.is_none());
                    conn_decision!(self, conn);
                }
                Poll::Ready(Some(None)) => {
                    // someone signaled us that it's exit time
                    close = self.inner.close.load(Ordering::Acquire);
                    assert!(close);
                    continue;
                }
                Poll::Ready(None) => {
                    // no more connections are coming -- time to exit!
                    self.inner.close.store(true, Ordering::Release);
                    self.eof = true;
                    close = true;
                }
                Poll::Pending => {
                    // nope -- but let's still make progress on the ones we have
                    break;
                }
            }
        }

        // if we've been asked to close, reclaim any idle connections
        if close {
            while let Some(IdlingConn { conn, .. }) =
                self.inner.exchange.lock().unwrap().available.pop_front()
            {
                assert!(conn.inner.pool.is_none());
                conn_decision!(self, conn);
            }
        }

        // are any dirty connections ready for us to reclaim?
        loop {
            match Pin::new(&mut self.cleaning).poll_next(cx) {
                Poll::Pending | Poll::Ready(None) => break,
                Poll::Ready(Some(Ok(conn))) => conn_decision!(self, conn),
                Poll::Ready(Some(Err(e))) => {
                    // an error occurred while cleaning a connection.
                    // what do we do? replace it with a new connection?
                    // for a conn to end up in cleaning, it must have come through .dropped.
                    // anything that comes through .dropped we know has .pool.is_none().
                    // therefore, dropping the conn won't decrement .exist, so we need to do that.
                    self.discarded += 1;
                    // NOTE: we're discarding the error here
                    let _ = e;
                }
            }
        }

        // are there any torn-down connections for us to deal with?
        loop {
            match Pin::new(&mut self.discard).poll_next(cx) {
                Poll::Pending | Poll::Ready(None) => break,
                Poll::Ready(Some(Ok(()))) => {
                    // yes! count it.
                    // note that we must decrement .exist since the connection does not have a
                    // .pool, and therefore won't do anything useful when it is dropped.
                    self.discarded += 1
                }
                Poll::Ready(Some(Err(e))) => {
                    // an error occurred while closing a connection.
                    // what do we do? we still replace it with a new connection..
                    self.discarded += 1;
                    // NOTE: we're discarding the error here
                    let _ = e;
                }
            }
        }

        if self.discarded != 0 {
            // we need to open up slots for new connctions to be established!
            let mut exchange = self.inner.exchange.lock().unwrap();
            exchange.exist -= self.discarded;
            for _ in 0..self.discarded {
                if let Some(w) = exchange.waiting.pop_front() {
                    w.wake();
                }
            }
            drop(exchange);
            self.discarded = 0;
        }

        // NOTE: we are asserting here that no more connections will ever be returned to
        // us. see the explanation in Pool::poll_new_conn for why this is okay, even during
        // races on .exist
        let effectively_eof = close && self.inner.exchange.lock().unwrap().exist == 0;

        if (self.eof || effectively_eof) && self.cleaning.is_empty() && self.discard.is_empty() {
            // we know that all Pool handles have been dropped (self.dropped.poll returned None).

            // if this assertion fails, where are the remaining connections?
            assert_eq!(self.inner.exchange.lock().unwrap().available.len(), 0);

            // NOTE: it is _necessary_ that we set this _before_ we call .wake
            // otherwise, the following may happen to the DisconnectPool future:
            //
            //  - We wake all in .wake
            //  - DisconnectPool::poll adds to .wake
            //  - DisconnectPool::poll reads .closed == false
            //  - We set .closed = true
            //
            // At this point, DisconnectPool::poll will never be notified again.
            self.inner.closed.store(true, Ordering::Release);
        }

        if self.inner.closed.load(Ordering::Acquire) {
            // `DisconnectPool` might still wait to be woken up.
            let mut exchange = self.inner.exchange.lock().unwrap();
            while let Some(w) = exchange.waiting.pop_front() {
                w.wake();
            }
            // we're about to exit, so there better be no outstanding connections
            assert_eq!(exchange.exist, 0);
            assert_eq!(exchange.available.len(), 0);
            drop(exchange);

            Poll::Ready(())
        } else {
            Poll::Pending
        }
    }
}
<commit_msg>Make sure to drop available conns before exit<commit_after>// Copyright (c) 2019 mysql_async contributors
//
// 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. All files in the project carrying such notice may not be copied,
// modified, or distributed except according to those terms.

use futures_core::stream::Stream;
use futures_util::stream::futures_unordered::FuturesUnordered;
use tokio::sync::mpsc;

use std::future::Future;
use std::pin::Pin;
use std::sync::atomic::Ordering;
use std::sync::Arc;
use std::task::{Context, Poll};

use super::{IdlingConn, Inner};
use crate::{BoxFuture, Conn, PoolOptions};
use tokio::sync::mpsc::UnboundedReceiver;

pub struct Recycler {
    inner: Arc<Inner>,
    discard: FuturesUnordered<BoxFuture<()>>,
    discarded: usize,
    cleaning: FuturesUnordered<BoxFuture<Conn>>,

    // Option<Conn> so that we have a way to send a "I didn't make a Conn after all" signal
    dropped: mpsc::UnboundedReceiver<Option<Conn>>,
    /// Pool options.
    pool_opts: PoolOptions,
    eof: bool,
}

impl Recycler {
    pub fn new(
        pool_opts: PoolOptions,
        inner: Arc<Inner>,
        dropped: UnboundedReceiver<Option<Conn>>,
    ) -> Self {
        Self {
            inner,
            discard: FuturesUnordered::new(),
            discarded: 0,
            cleaning: FuturesUnordered::new(),
            dropped,
            pool_opts,
            eof: false,
        }
    }
}

impl Future for Recycler {
    type Output = ();

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        let mut close = self.inner.close.load(Ordering::Acquire);

        macro_rules! conn_decision {
            ($self:ident, $conn:ident) => {
                if $conn.inner.stream.is_none() || $conn.inner.disconnected {
                    // drop unestablished connection
                    $self.discard.push(Box::pin(::futures_util::future::ok(())));
                } else if $conn.inner.in_transaction || $conn.inner.has_result.is_some() {
                    $self.cleaning.push(Box::pin($conn.cleanup()));
                } else if $conn.expired() || close {
                    $self.discard.push(Box::pin($conn.close()));
                } else {
                    let mut exchange = $self.inner.exchange.lock().unwrap();
                    if exchange.available.len() >= $self.pool_opts.active_bound() {
                        drop(exchange);
                        $self.discard.push(Box::pin($conn.close()));
                    } else {
                        exchange.available.push_back($conn.into());
                        if let Some(w) = exchange.waiting.pop_front() {
                            w.wake();
                        }
                    }
                }
            };
        }

        while !self.eof {
            // see if there are more connections for us to recycle
            match Pin::new(&mut self.dropped).poll_next(cx) {
                Poll::Ready(Some(Some(conn))) => {
                    assert!(conn.inner.pool.is_none());
                    conn_decision!(self, conn);
                }
                Poll::Ready(Some(None)) => {
                    // someone signaled us that it's exit time
                    close = self.inner.close.load(Ordering::Acquire);
                    assert!(close);
                    continue;
                }
                Poll::Ready(None) => {
                    // no more connections are coming -- time to exit!
                    self.inner.close.store(true, Ordering::Release);
                    self.eof = true;
                    close = true;
                }
                Poll::Pending => {
                    // nope -- but let's still make progress on the ones we have
                    break;
                }
            }
        }

        // if we've been asked to close, reclaim any idle connections
        if close || self.eof {
            while let Some(IdlingConn { conn, .. }) =
                self.inner.exchange.lock().unwrap().available.pop_front()
            {
                assert!(conn.inner.pool.is_none());
                conn_decision!(self, conn);
            }
        }

        // are any dirty connections ready for us to reclaim?
        loop {
            match Pin::new(&mut self.cleaning).poll_next(cx) {
                Poll::Pending | Poll::Ready(None) => break,
                Poll::Ready(Some(Ok(conn))) => conn_decision!(self, conn),
                Poll::Ready(Some(Err(e))) => {
                    // an error occurred while cleaning a connection.
                    // what do we do? replace it with a new connection?
                    // for a conn to end up in cleaning, it must have come through .dropped.
                    // anything that comes through .dropped we know has .pool.is_none().
                    // therefore, dropping the conn won't decrement .exist, so we need to do that.
                    self.discarded += 1;
                    // NOTE: we're discarding the error here
                    let _ = e;
                }
            }
        }

        // are there any torn-down connections for us to deal with?
        loop {
            match Pin::new(&mut self.discard).poll_next(cx) {
                Poll::Pending | Poll::Ready(None) => break,
                Poll::Ready(Some(Ok(()))) => {
                    // yes! count it.
                    // note that we must decrement .exist since the connection does not have a
                    // .pool, and therefore won't do anything useful when it is dropped.
                    self.discarded += 1
                }
                Poll::Ready(Some(Err(e))) => {
                    // an error occurred while closing a connection.
                    // what do we do? we still replace it with a new connection..
                    self.discarded += 1;
                    // NOTE: we're discarding the error here
                    let _ = e;
                }
            }
        }

        if self.discarded != 0 {
            // we need to open up slots for new connctions to be established!
            let mut exchange = self.inner.exchange.lock().unwrap();
            exchange.exist -= self.discarded;
            for _ in 0..self.discarded {
                if let Some(w) = exchange.waiting.pop_front() {
                    w.wake();
                }
            }
            drop(exchange);
            self.discarded = 0;
        }

        // NOTE: we are asserting here that no more connections will ever be returned to
        // us. see the explanation in Pool::poll_new_conn for why this is okay, even during
        // races on .exist
        let effectively_eof = close && self.inner.exchange.lock().unwrap().exist == 0;

        if (self.eof || effectively_eof) && self.cleaning.is_empty() && self.discard.is_empty() {
            // we know that all Pool handles have been dropped (self.dropped.poll returned None).

            // if this assertion fails, where are the remaining connections?
            assert_eq!(self.inner.exchange.lock().unwrap().available.len(), 0);

            // NOTE: it is _necessary_ that we set this _before_ we call .wake
            // otherwise, the following may happen to the DisconnectPool future:
            //
            //  - We wake all in .wake
            //  - DisconnectPool::poll adds to .wake
            //  - DisconnectPool::poll reads .closed == false
            //  - We set .closed = true
            //
            // At this point, DisconnectPool::poll will never be notified again.
            self.inner.closed.store(true, Ordering::Release);
        }

        if self.inner.closed.load(Ordering::Acquire) {
            // `DisconnectPool` might still wait to be woken up.
            let mut exchange = self.inner.exchange.lock().unwrap();
            while let Some(w) = exchange.waiting.pop_front() {
                w.wake();
            }
            // we're about to exit, so there better be no outstanding connections
            assert_eq!(exchange.exist, 0);
            assert_eq!(exchange.available.len(), 0);
            drop(exchange);

            Poll::Ready(())
        } else {
            Poll::Pending
        }
    }
}
<|endoftext|>


<commit_before>use async_std::path::PathBuf as AsyncPathBuf;
use moka::future::Cache;
use std::path::{Path, PathBuf};
use std::time::Duration;
use std::{ffi::OsStr, io};
use tide::http::mime::Mime;
use tide::{Body, Endpoint, Request, Response, Result, StatusCode};

pub struct ServeStaticFiles {
    prefix: String,
    dir: PathBuf,
    skip_compress_mime: Option<Vec<String>>,
    cache: Option<Cache<String, (Vec<u8>, Mime)>>,
}

impl ServeStaticFiles {
    pub fn new(prefix: String, dir: PathBuf, skip_compress_mime: Option<Vec<String>>) -> Self {
        Self {
            prefix,
            dir,
            skip_compress_mime,
            cache: Some(
                Cache::builder()
                    // TTL: 5 minutes
                    .time_to_live(Duration::from_secs(5 * 60))
                    // TTI: 1 minute
                    .time_to_idle(Duration::from_secs(60))
                    .build(),
            ),
        }
    }

    pub fn get_body_from_cache(&self, url: &str) -> Option<(Vec<u8>, Mime)> {
        match &self.cache {
            Some(cache) => cache.get(&url.to_string()),
            None => None,
        }
    }

    pub async fn insert_body_to_cache(&self, url: String, body_as_bytes: Vec<u8>, mime: Mime) {
        match &self.cache {
            Some(cache) => {
                cache
                    .insert(url.clone(), (body_as_bytes.clone(), mime))
                    .await
            }
            None => (),
        }
    }

    pub fn get_ok_response_from_body(&self, body_as_bytes: Vec<u8>, mime: Mime) -> Response {
        let mut body = Body::from_bytes(body_as_bytes);
        body.set_mime(mime.clone());
        let skip_compression: bool = match &self.skip_compress_mime {
            Some(skip_compress_mime) => skip_compress_mime.contains(&mime.essence().to_string()),
            None => false,
        };
        if skip_compression {
            Response::builder(StatusCode::Ok)
                .body(body)
                .header("Cache-Control", "no-transform")
                .build()
        } else {
            Response::builder(StatusCode::Ok).body(body).build()
        }
    }

    pub fn get_path_with_extension(path: &AsyncPathBuf, extension: &str) -> AsyncPathBuf {
        let mut path_with_extension = path.clone();
        path_with_extension.set_extension(extension);
        return path_with_extension;
    }
}

#[async_trait::async_trait]
impl<State> Endpoint<State> for ServeStaticFiles
where
    State: Clone + Send + Sync + 'static,
{
    async fn call(&self, req: Request<State>) -> Result {
        let url = &req.url().to_string();
        let cached_body = self.get_body_from_cache(&url);
        return if cached_body.is_some() {
            // The body for the URL was found from the cache, return it without any file IO
            log::debug!("Cache hit: {}", &url);
            let cached_body = cached_body.unwrap();
            Ok(self.get_ok_response_from_body(cached_body.0, cached_body.1))
        } else {
            // Read the file from the file system
            log::debug!("Cache miss: {}", &url);
            let path = req.url().path();
            let path = path
                .strip_prefix(&self.prefix.trim_end_matches('*'))
                .unwrap();
            let path = path.trim_start_matches('/');
            let mut file_path = self.dir.clone();
            for p in Path::new(path) {
                if p == OsStr::new(".") {
                    continue;
                } else if p == OsStr::new("..") {
                    file_path.pop();
                } else {
                    file_path.push(&p);
                }
            }
            let file_path = AsyncPathBuf::from(file_path);

            let mut file_path_to_search = file_path;
            if file_path_to_search.extension().is_none() {
                // When a call comes without an extension, search for .html suffix and/or directory with
                // index.html
                if file_path_to_search.is_dir().await {
                    let file_path_with_extension =
                        ServeStaticFiles::get_path_with_extension(&file_path_to_search, "html");
                    if file_path_with_extension.exists().await {
                        file_path_to_search = file_path_with_extension;
                    } else {
                        file_path_to_search.push("index.html");
                    }
                } else if !file_path_to_search.exists().await {
                    let file_path_with_extension =
                        ServeStaticFiles::get_path_with_extension(&file_path_to_search, "html");
                    file_path_to_search = file_path_with_extension;
                }
            }
            if !file_path_to_search.starts_with(&self.dir) {
                log::warn!("Unauthorized attempt to read: {:?}", file_path_to_search);
                Ok(Response::new(StatusCode::Forbidden))
            } else {
                match Body::from_file(&file_path_to_search).await {
                    Ok(body) => {
                        let mime = body.mime().clone();
                        let body_as_bytes = body.into_bytes().await.unwrap();
                        self.insert_body_to_cache(url.clone(), body_as_bytes.clone(), mime.clone())
                            .await;
                        Ok(self.get_ok_response_from_body(body_as_bytes, mime))
                    }
                    Err(e) if e.kind() == io::ErrorKind::NotFound => {
                        log::warn!("File not found: {:?}", &file_path_to_search);
                        Ok(Response::new(StatusCode::NotFound))
                    }
                    Err(e) => Err(e.into()),
                }
            }
        };
    }
}
<commit_msg>Block Google Topics tracking<commit_after>use async_std::path::PathBuf as AsyncPathBuf;
use moka::future::Cache;
use std::path::{Path, PathBuf};
use std::time::Duration;
use std::{ffi::OsStr, io};
use tide::http::mime::Mime;
use tide::{Body, Endpoint, Request, Response, Result, StatusCode};

pub struct ServeStaticFiles {
    prefix: String,
    dir: PathBuf,
    skip_compress_mime: Option<Vec<String>>,
    cache: Option<Cache<String, (Vec<u8>, Mime)>>,
}

impl ServeStaticFiles {
    pub fn new(prefix: String, dir: PathBuf, skip_compress_mime: Option<Vec<String>>) -> Self {
        Self {
            prefix,
            dir,
            skip_compress_mime,
            cache: Some(
                Cache::builder()
                    // TTL: 5 minutes
                    .time_to_live(Duration::from_secs(5 * 60))
                    // TTI: 1 minute
                    .time_to_idle(Duration::from_secs(60))
                    .build(),
            ),
        }
    }

    pub fn get_body_from_cache(&self, url: &str) -> Option<(Vec<u8>, Mime)> {
        match &self.cache {
            Some(cache) => cache.get(&url.to_string()),
            None => None,
        }
    }

    pub async fn insert_body_to_cache(&self, url: String, body_as_bytes: Vec<u8>, mime: Mime) {
        match &self.cache {
            Some(cache) => {
                cache
                    .insert(url.clone(), (body_as_bytes.clone(), mime))
                    .await
            }
            None => (),
        }
    }

    pub fn get_ok_response_from_body(&self, body_as_bytes: Vec<u8>, mime: Mime) -> Response {
        let mut body = Body::from_bytes(body_as_bytes);
        body.set_mime(mime.clone());
        let skip_compression: bool = match &self.skip_compress_mime {
            Some(skip_compress_mime) => skip_compress_mime.contains(&mime.essence().to_string()),
            None => false,
        };
        let response = Response::builder(StatusCode::Ok)
            .body(body)
            .header("Permissions-Policy", "browsing-topics=()");
        if skip_compression {
            response.header("Cache-Control", "no-transform").build()
        } else {
            response.build()
        }
    }

    pub fn get_path_with_extension(path: &AsyncPathBuf, extension: &str) -> AsyncPathBuf {
        let mut path_with_extension = path.clone();
        path_with_extension.set_extension(extension);
        return path_with_extension;
    }
}

#[async_trait::async_trait]
impl<State> Endpoint<State> for ServeStaticFiles
where
    State: Clone + Send + Sync + 'static,
{
    async fn call(&self, req: Request<State>) -> Result {
        let url = &req.url().to_string();
        let cached_body = self.get_body_from_cache(&url);
        return if cached_body.is_some() {
            // The body for the URL was found from the cache, return it without any file IO
            log::debug!("Cache hit: {}", &url);
            let cached_body = cached_body.unwrap();
            Ok(self.get_ok_response_from_body(cached_body.0, cached_body.1))
        } else {
            // Read the file from the file system
            log::debug!("Cache miss: {}", &url);
            let path = req.url().path();
            let path = path
                .strip_prefix(&self.prefix.trim_end_matches('*'))
                .unwrap();
            let path = path.trim_start_matches('/');
            let mut file_path = self.dir.clone();
            for p in Path::new(path) {
                if p == OsStr::new(".") {
                    continue;
                } else if p == OsStr::new("..") {
                    file_path.pop();
                } else {
                    file_path.push(&p);
                }
            }
            let file_path = AsyncPathBuf::from(file_path);

            let mut file_path_to_search = file_path;
            if file_path_to_search.extension().is_none() {
                // When a call comes without an extension, search for .html suffix and/or directory with
                // index.html
                if file_path_to_search.is_dir().await {
                    let file_path_with_extension =
                        ServeStaticFiles::get_path_with_extension(&file_path_to_search, "html");
                    if file_path_with_extension.exists().await {
                        file_path_to_search = file_path_with_extension;
                    } else {
                        file_path_to_search.push("index.html");
                    }
                } else if !file_path_to_search.exists().await {
                    let file_path_with_extension =
                        ServeStaticFiles::get_path_with_extension(&file_path_to_search, "html");
                    file_path_to_search = file_path_with_extension;
                }
            }
            if !file_path_to_search.starts_with(&self.dir) {
                log::warn!("Unauthorized attempt to read: {:?}", file_path_to_search);
                Ok(Response::new(StatusCode::Forbidden))
            } else {
                match Body::from_file(&file_path_to_search).await {
                    Ok(body) => {
                        let mime = body.mime().clone();
                        let body_as_bytes = body.into_bytes().await.unwrap();
                        self.insert_body_to_cache(url.clone(), body_as_bytes.clone(), mime.clone())
                            .await;
                        Ok(self.get_ok_response_from_body(body_as_bytes, mime))
                    }
                    Err(e) if e.kind() == io::ErrorKind::NotFound => {
                        log::warn!("File not found: {:?}", &file_path_to_search);
                        Ok(Response::new(StatusCode::NotFound))
                    }
                    Err(e) => Err(e.into()),
                }
            }
        };
    }
}
<|endoftext|>


<commit_before>/// TextStyle holds the displayed attributes flags.
#[derive(Debug, Default, Hash, Clone, Copy, Eq, PartialEq)]
pub struct TextStyle {
    /// The character should blink.
    pub is_blinking: bool,
    /// The character is a part of a selection.
    pub is_selected: bool,
    /// The fg/bg attributes are reversed (used to simulate cursors/marks).
    pub is_inverse: bool,
    /// The character should be displayed as bold.
    pub is_bold: bool,
    /// The character should be displayed in italic.
    pub is_italic: bool,
    /// rbg tuple for foreground color
    pub color: (u8, u8, u8), // RGB
    /// rbg tuple for background color
    pub bg_color: (u8, u8, u8), // RGB
}

impl TextStyle {
    pub fn new() -> Self {
        TextStyle {
            is_blinking: false,
            is_selected: false,
            is_inverse: false,
            is_bold: false,
            is_italic: false,
            color: Self::default_color(),
            bg_color: Self::default_bg_color(),
        }
    }

    pub fn default_color() -> (u8, u8, u8) {
        // (192, 192, 192) // White
        // (128, 128, 128)    // Gray
        //(177, 177, 177)
        (160, 160, 160)
    }

    pub fn default_bg_color() -> (u8, u8, u8) {
        // (30, 34, 39)
        //(45, 55, 67)
        //(40, 44, 49)
        (39, 40, 54)
    }

    pub fn default_selected_bg_color() -> (u8, u8, u8) {
        let sbg = Self::default_bg_color();
        let add = 25;
        (sbg.0 + add, sbg.1 + add, sbg.2 + add)
    }

    pub fn default_mark_line_bg_color() -> (u8, u8, u8) {
        let sbg = Self::default_bg_color();
        let add = 5;
        (sbg.0 + add, sbg.1 + add, sbg.2 + add)
    }
}

/// A CodepointInfo contains displayed character attributes.

/// The displayed screen is composed of LineCell(s), that contain CodepointInfo(s).
#[derive(Hash, Default, Debug, Clone, Copy, Eq, PartialEq)]
pub struct CodepointInfo {
    pub used: bool,

    pub metadata: bool, // offset cannot be used, TODO(ceg): use enum to tag Eof, Normal

    // pub is_eof ?
    pub cp: char,            // the real codepoint
    pub displayed_cp: char,  // the displayed codepoint
    pub offset: Option<u64>, // TODO(ceg): Option<(u64, usize)>, back end size (codec)
    pub size: usize,         // TODO(ceg): Option<(u64, usize)>, back end size (codec)

    pub skip_render: bool,

    // TODO(ceg): add n/m fragments ie tabs ?
    // TODO(ceg): add real_size ? in bytes
    pub style: TextStyle,
}

impl CodepointInfo {
    pub fn new() -> Self {
        CodepointInfo {
            used: false,
            metadata: true,
            cp: ' ',
            displayed_cp: ' ',
            offset: None,
            size: 0,
            skip_render: false,
            //
            style: TextStyle::new(),
        }
    }
}

/*
Logical Color	Terminal Color	RGB Value Used by SGD
Black	0 0 0
Light_red	255 0 0
Light_green	0 255 0
Yellow	255 255 0
Light_blue	0 0 255
Light_magenta	255 0 255
Light_cyan	    0 255 255
High_white	    255 255 255
Gray	    128 128 128
Red	    128 0 0
Green	0 128 0
Brown	128 128 0
Blue	0 0 128
Magenta	128 0 128
Cyan	0 128 128
White	192 192 192
*/
<commit_msg>update CodepointInfo doc<commit_after>/// TextStyle holds the displayed attributes flags.
#[derive(Debug, Default, Hash, Clone, Copy, Eq, PartialEq)]
pub struct TextStyle {
    /// The character should blink.
    pub is_blinking: bool,
    /// The character is a part of a selection.
    pub is_selected: bool,
    /// The fg/bg attributes are reversed (used to simulate cursors/marks).
    pub is_inverse: bool,
    /// The character should be displayed as bold.
    pub is_bold: bool,
    /// The character should be displayed in italic.
    pub is_italic: bool,
    /// rbg tuple for foreground color
    pub color: (u8, u8, u8), // RGB
    /// rbg tuple for background color
    pub bg_color: (u8, u8, u8), // RGB
}

impl TextStyle {
    pub fn new() -> Self {
        TextStyle {
            is_blinking: false,
            is_selected: false,
            is_inverse: false,
            is_bold: false,
            is_italic: false,
            color: Self::default_color(),
            bg_color: Self::default_bg_color(),
        }
    }

    pub fn default_color() -> (u8, u8, u8) {
        // (192, 192, 192) // White
        // (128, 128, 128)    // Gray
        //(177, 177, 177)
        (160, 160, 160)
    }

    pub fn default_bg_color() -> (u8, u8, u8) {
        // (30, 34, 39)
        //(45, 55, 67)
        //(40, 44, 49)
        (39, 40, 54)
    }

    pub fn default_selected_bg_color() -> (u8, u8, u8) {
        let sbg = Self::default_bg_color();
        let add = 25;
        (sbg.0 + add, sbg.1 + add, sbg.2 + add)
    }

    pub fn default_mark_line_bg_color() -> (u8, u8, u8) {
        let sbg = Self::default_bg_color();
        let add = 5;
        (sbg.0 + add, sbg.1 + add, sbg.2 + add)
    }
}

/// A CodepointInfo contains displayed character attributes.

/// The displayed screen is composed of LineCell(s), that contain CodepointInfo(s).
#[derive(Hash, Default, Debug, Clone, Copy, Eq, PartialEq)]
pub struct CodepointInfo {
    /// Ignore this CodepointInfo if set to false.
    pub used: bool, // rename into ignore ?
    /// The CodepointInfo is some part metadata.

    /// When set to true offset must be set to None
    pub metadata: bool, // TODO(ceg): prefer enum use enum { Normal, Eof, ... }
    /// The real codepoint found on storage
    pub cp: char,
    /// The codepoint to display
    pub displayed_cp: char,
    /// Storage offset
    pub offset: Option<u64>,
    /// Storage size in bytes
    pub size: usize,
    /// Hints for render
    pub skip_render: bool,
    /// Style to apply when rendering
    pub style: TextStyle,
}

impl CodepointInfo {
    pub fn new() -> Self {
        CodepointInfo {
            used: false,
            metadata: true,
            cp: ' ',
            displayed_cp: ' ',
            offset: None,
            size: 0,
            skip_render: false,
            //
            style: TextStyle::new(),
        }
    }
}

/*
Logical Color	Terminal Color	RGB Value Used by SGD
Black	0 0 0
Light_red	255 0 0
Light_green	0 255 0
Yellow	255 255 0
Light_blue	0 0 255
Light_magenta	255 0 255
Light_cyan	    0 255 255
High_white	    255 255 255
Gray	    128 128 128
Red	    128 0 0
Green	0 128 0
Brown	128 128 0
Blue	0 0 128
Magenta	128 0 128
Cyan	0 128 128
White	192 192 192
*/
<|endoftext|>


<commit_before>use diesel::backend::Backend;
use diesel::expression::Expression;
use diesel::types::{FromSql, IsNull, Text, ToSql};
use std::error::Error;
use std::io::Write;
use std::fmt;
use std::str::FromStr;
use super::entities::Mbid;

#[derive(Debug)]
struct MbidFromSqlError {}

impl fmt::Display for MbidFromSqlError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        write!(f, "{}", self.description())
    }
}

impl Error for MbidFromSqlError {
    fn description(&self) -> &str
    {
        "Failed reading `Mbid` from SQL."
    }
}

impl<DB: Backend<RawValue = String>> FromSql<Text, DB> for Mbid {
    fn from_sql(value: Option<&String>) -> Result<Self, Box<Error + Send + Sync>>
    {
        let str_value = value.ok_or(MbidFromSqlError {})?.as_ref();
        Ok(Mbid::from_str(str_value)?)
    }
}

impl<DB: Backend<RawValue = String>> ToSql<Text, DB> for Mbid {
    fn to_sql<W: Write>(&self, out: &mut W) -> Result<IsNull, Box<Error + Send + Sync>>
    {
        write!(out, "{}", self)?;
        Ok(IsNull::No)
    }
}

impl Expression for Mbid {
    type SqlType = Text;
}
<commit_msg>diesel_integration: update trait implementations<commit_after>use diesel::backend::Backend;
use diesel::expression::bound::Bound;
use diesel::expression::AsExpression;
use diesel::types::{FromSql, IsNull, Nullable, Text, ToSql};
use std::error::Error;
use std::io::Write;
use std::fmt;
use std::str::FromStr;
use super::entities::Mbid;

#[derive(Debug)]
struct MbidFromSqlError {}

impl fmt::Display for MbidFromSqlError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
    {
        write!(f, "{}", self.description())
    }
}

impl Error for MbidFromSqlError {
    fn description(&self) -> &str
    {
        "Failed reading `Mbid` from SQL."
    }
}

impl<DB: Backend<RawValue = String>> FromSql<Text, DB> for Mbid {
    fn from_sql(value: Option<&String>) -> Result<Self, Box<Error + Send + Sync>>
    {
        let str_value = value.ok_or(MbidFromSqlError {})?.as_ref();
        Ok(Mbid::from_str(str_value)?)
    }
}

impl<DB: Backend<RawValue = String>> ToSql<Nullable<Text>, DB> for Mbid {
    fn to_sql<W: Write>(&self, out: &mut W) -> Result<IsNull, Box<Error + Send + Sync>>
    {
        write!(out, "{}", self)?;
        Ok(IsNull::No)
    }
}

impl AsExpression<Text> for Mbid {
    type Expression = Bound<Text, Self>;

    fn as_expression(self) -> Self::Expression
    {
        Bound::new(self)
    }
}

impl<'expr> AsExpression<Text> for &'expr Mbid {
    type Expression = Bound<Text, Self>;

    fn as_expression(self) -> Self::Expression
    {
        Bound::new(self)
    }
}

impl AsExpression<Nullable<Text>> for Mbid {
    type Expression = Bound<Nullable<Text>, Self>;

    fn as_expression(self) -> Self::Expression
    {
        Bound::new(self)
    }
}

impl<'expr> AsExpression<Nullable<Text>> for &'expr Mbid {
    type Expression = Bound<Nullable<Text>, Self>;

    fn as_expression(self) -> Self::Expression
    {
        Bound::new(self)
    }
}
<|endoftext|>