<commit_before>use std::{fmt, mem};
use std::ops::{Index, IndexMut, Range, RangeTo, RangeFrom, RangeFull};
use std::ascii::AsciiExt;

use AsciiCast;
use ascii::Ascii;
use ascii_string::AsciiString;

/// A borrowed ascii string, like a slice into an `AsciiString`.
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AsciiStr {
    slice: [Ascii],
}

impl AsciiStr {
    /// Coerces into an `AsciiStr` slice.
    pub fn new<S: AsRef<AsciiStr> + ?Sized>(s: &S) -> &AsciiStr {
        s.as_ref()
    }

    /// Converts `&self` to a `&str` slice.
    pub fn as_str(&self) -> &str {
        unsafe { mem::transmute(&self.slice) }
    }

    /// Converts `&self` into a byte slice.
    pub fn as_bytes(&self) -> &[u8] {
        unsafe { mem::transmute(&self.slice) }
    }

    pub fn as_slice(&self) -> &[Ascii] {
        &self.slice
    }

    /// Copies the content of this `AsciiStr` into an owned `AsciiString`.
    pub fn to_ascii_string(&self) -> AsciiString {
        AsciiString::from(self.slice.to_vec())
    }

    /// Converts anything that can represent a byte slice into an `AsciiStr`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ascii::AsciiStr;
    /// let foo = AsciiStr::from_bytes("foo");
    /// let err = AsciiStr::from_bytes("Ŋ");
    /// assert_eq!(foo.unwrap().as_str(), "foo");
    /// assert_eq!(err, Err(()));
    /// ```
    pub fn from_bytes<'a, B: ?Sized>(bytes: &'a B) -> Result<&'a AsciiStr, ()>
        where B: AsRef<[u8]>
    {
        unsafe {
            if bytes.as_ref().is_ascii() {
                Ok( mem::transmute(bytes.as_ref()) )
            } else {
                Err(())
            }
        }
    }

    /// Converts a borrowed string to a borrows ascii string.
    pub fn from_str<'a>(s: &'a str) -> Result<&'a AsciiStr, ()> {
        AsciiStr::from_bytes(s.as_bytes())
    }

    /// Returns the number of bytes in this ascii string.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ascii::AsciiStr;
    /// let s = AsciiStr::from_bytes("foo").unwrap();
    /// assert_eq!(s.len(), 3);
    /// ```
    pub fn len(&self) -> usize {
        self.slice.len()
    }

    /// Returns true if the ascii string contains no bytes.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ascii::AsciiStr;
    /// let mut empty = AsciiStr::from_bytes("").unwrap();
    /// let mut full = AsciiStr::from_bytes("foo").unwrap();
    /// assert!(empty.is_empty());
    /// assert!(!full.is_empty());
    /// ```
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns an ascii string slice with leading and trailing whitespace removed.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ascii::AsciiStr;
    /// let example = AsciiStr::from_str("  \twhite \tspace  \t").unwrap();
    /// assert_eq!("white \tspace", example.trim());
    /// ```
    pub fn trim(&self) -> &Self {
        unsafe { mem::transmute(self.as_str().trim()) }
    }

    /// Returns a string slice with leading whitespace removed.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ascii::AsciiStr;
    /// let example = AsciiStr::from_str("  \twhite \tspace  \t").unwrap();
    /// assert_eq!("white \tspace  \t", example.trim_left());
    /// ```
    pub fn trim_left(&self) -> &Self {
        unsafe { mem::transmute(self.as_str().trim_left()) }
    }

    /// Returns a string slice with trainling whitespace removed.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ascii::AsciiStr;
    /// let example = AsciiStr::from_str("  \twhite \tspace  \t").unwrap();
    /// assert_eq!("  \twhite \tspace", example.trim_right());
    /// ```
    pub fn trim_right(&self) -> &Self {
        unsafe { mem::transmute(self.as_str().trim_right()) }
    }
}

impl PartialEq<str> for AsciiStr {
    fn eq(&self, other: &str) -> bool {
        self.as_str() == other
    }
}

impl PartialEq<AsciiStr> for str {
    fn eq(&self, other: &AsciiStr) -> bool {
        other.as_str() == self
    }
}

/*
impl PartialOrd<AsciiString> for AsciiStr {
    #[inline]
    fn partial_cmp(&self, other: &AsciiString) -> Option<Ordering> {
        self.as_bytes().partial_cmp(other.as_bytes())
    }
}
*/

impl ToOwned for AsciiStr {
    type Owned = AsciiString;

    fn to_owned(&self) -> AsciiString {
        self.to_ascii_string()
    }
}

impl AsRef<[u8]> for AsciiStr {
    fn as_ref(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl AsRef<str> for AsciiStr {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl fmt::Display for AsciiStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self.as_str(), f)
    }
}

impl fmt::Debug for AsciiStr {
   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
       fmt::Debug::fmt(self.as_str(), f)
   }
}

macro_rules! impl_index {
    ($lhs:ty, $idx:ty, $rhs:ty) => {
        impl Index<$idx> for $lhs {
            type Output = $rhs;

            #[inline]
            fn index(&self, index: $idx) -> &$rhs {
                unsafe { mem::transmute(&self.slice[index]) }
            }
        }

        impl IndexMut<$idx> for $lhs {
            #[inline]
            fn index_mut(&mut self, index: $idx) -> &mut $rhs {
                unsafe { mem::transmute(&mut self.slice[index]) }
            }
        }
    }
}

impl_index! { AsciiStr, usize, Ascii }
impl_index! { AsciiStr, Range<usize>, AsciiStr }
impl_index! { AsciiStr, RangeTo<usize>, AsciiStr }
impl_index! { AsciiStr, RangeFrom<usize>, AsciiStr }
impl_index! { AsciiStr, RangeFull, AsciiStr }

#[cfg(feature = "unstable")]
impl AsciiExt for AsciiStr {
    type Owned = AsciiString;

    #[inline]
    fn is_ascii(&self) -> bool {
        true
    }

    fn to_ascii_uppercase(&self) -> AsciiString {
        let mut ascii_string = self.to_ascii_string();
        ascii_string.make_ascii_uppercase();
        ascii_string
    }

    fn to_ascii_lowercase(&self) -> AsciiString {
        let mut ascii_string = self.to_ascii_string();
        ascii_string.make_ascii_uppercase();
        ascii_string
    }

    fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
        self.len() == other.len() &&
        self.slice.iter().zip(other.slice.iter()).all(|(a, b)| a.eq_ignore_ascii_case(b))
    }

    fn make_ascii_uppercase(&mut self) {
        for ascii in &mut self.slice {
            ascii.make_ascii_uppercase();
        }
    }

    fn make_ascii_lowercase(&mut self) {
        for ascii in &mut self.slice {
            ascii.make_ascii_lowercase();
        }
    }
}

impl<'a> AsciiCast<'a> for [u8] {
    type Target = &'a AsciiStr;

    #[inline]
    unsafe fn to_ascii_nocheck(&'a self) -> &'a AsciiStr {
        mem::transmute(self)
    }
}

impl<'a> AsciiCast<'a> for str {
    type Target = &'a AsciiStr;

    #[inline]
    unsafe fn to_ascii_nocheck(&'a self) -> &'a AsciiStr {
        mem::transmute(self)
    }
}

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

    #[test]
    fn as_str() {
        let b = &[40_u8, 32, 59];
        let v = AsciiStr::from_bytes(b).unwrap();
        assert_eq!(v.as_str(), "( ;");
        assert_eq!(AsRef::<str>::as_ref(v), "( ;");
    }

    #[test]
    fn as_bytes() {
        let b = &[40_u8, 32, 59];
        let v = AsciiStr::from_bytes(b).unwrap();
        assert_eq!(v.as_bytes(), b"( ;");
        assert_eq!(AsRef::<[u8]>::as_ref(v), b"( ;");
    }

    #[test]
    fn fmt_display_ascii_str() {
        let s = "abc".to_ascii().unwrap();
        assert_eq!(format!("{}", s), "abc".to_string());
    }

    #[test]
    fn fmt_debug_ascii_str() {
        let s = "abc".to_ascii().unwrap();
        assert_eq!(format!("{:?}", s), "\"abc\"".to_string());
    }
}
<commit_msg>Add more simple conversions<commit_after>use std::{fmt, mem};
use std::ops::{Index, IndexMut, Range, RangeTo, RangeFrom, RangeFull};
use std::ascii::AsciiExt;

use AsciiCast;
use ascii::Ascii;
use ascii_string::AsciiString;

/// A borrowed ascii string, like a slice into an `AsciiString`.
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct AsciiStr {
    slice: [Ascii],
}

impl AsciiStr {
    /// Coerces into an `AsciiStr` slice.
    pub fn new<S: AsRef<AsciiStr> + ?Sized>(s: &S) -> &AsciiStr {
        s.as_ref()
    }

    /// Converts `&self` to a `&str` slice.
    pub fn as_str(&self) -> &str {
        unsafe { mem::transmute(&self.slice) }
    }

    /// Converts `&self` into a byte slice.
    pub fn as_bytes(&self) -> &[u8] {
        unsafe { mem::transmute(&self.slice) }
    }

    /// Returns the entire string as slice of `Ascii` characters.
    pub fn as_slice(&self) -> &[Ascii] {
        &self.slice
    }

    /// Returns the entire string as mutable slice of `Ascii` characters.
    pub fn as_mut_slice(&mut self) -> &mut [Ascii] {
        &mut self.slice
    }

    /// Returns a raw pointer to the `AsciiStr`'s buffer.
    ///
    /// The caller must ensure that the slice outlives the pointer this function returns, or else it
    /// will end up pointing to garbage. Modifying the `AsciiStr` may cause it's buffer to be
    /// reallocated, which would also make any pointers to it invalid.
    pub fn as_ptr(&self) -> *const Ascii {
        self.as_slice().as_ptr()
    }

    /// Returns an unsafe mutable pointer to the `AsciiStr`'s buffer.
    ///
    /// The caller must ensure that the slice outlives the pointer this function returns, or else it
    /// will end up pointing to garbage. Modifying the `AsciiStr` may cause it's buffer to be
    /// reallocated, which would also make any pointers to it invalid.
    pub fn as_mut_ptr(&mut self) -> *mut Ascii {
        self.as_mut_slice().as_mut_ptr()
    }

    /// Copies the content of this `AsciiStr` into an owned `AsciiString`.
    pub fn to_ascii_string(&self) -> AsciiString {
        AsciiString::from(self.slice.to_vec())
    }

    /// Converts anything that can represent a byte slice into an `AsciiStr`.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ascii::AsciiStr;
    /// let foo = AsciiStr::from_bytes("foo");
    /// let err = AsciiStr::from_bytes("Ŋ");
    /// assert_eq!(foo.unwrap().as_str(), "foo");
    /// assert_eq!(err, Err(()));
    /// ```
    pub fn from_bytes<'a, B: ?Sized>(bytes: &'a B) -> Result<&'a AsciiStr, ()>
        where B: AsRef<[u8]>
    {
        unsafe {
            if bytes.as_ref().is_ascii() {
                Ok( mem::transmute(bytes.as_ref()) )
            } else {
                Err(())
            }
        }
    }

    /// Converts a borrowed string to a borrows ascii string.
    pub fn from_str<'a>(s: &'a str) -> Result<&'a AsciiStr, ()> {
        AsciiStr::from_bytes(s.as_bytes())
    }

    /// Returns the number of bytes in this ascii string.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ascii::AsciiStr;
    /// let s = AsciiStr::from_bytes("foo").unwrap();
    /// assert_eq!(s.len(), 3);
    /// ```
    pub fn len(&self) -> usize {
        self.slice.len()
    }

    /// Returns true if the ascii string contains no bytes.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ascii::AsciiStr;
    /// let mut empty = AsciiStr::from_bytes("").unwrap();
    /// let mut full = AsciiStr::from_bytes("foo").unwrap();
    /// assert!(empty.is_empty());
    /// assert!(!full.is_empty());
    /// ```
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns an ascii string slice with leading and trailing whitespace removed.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ascii::AsciiStr;
    /// let example = AsciiStr::from_str("  \twhite \tspace  \t").unwrap();
    /// assert_eq!("white \tspace", example.trim());
    /// ```
    pub fn trim(&self) -> &Self {
        unsafe { mem::transmute(self.as_str().trim()) }
    }

    /// Returns a string slice with leading whitespace removed.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ascii::AsciiStr;
    /// let example = AsciiStr::from_str("  \twhite \tspace  \t").unwrap();
    /// assert_eq!("white \tspace  \t", example.trim_left());
    /// ```
    pub fn trim_left(&self) -> &Self {
        unsafe { mem::transmute(self.as_str().trim_left()) }
    }

    /// Returns a string slice with trainling whitespace removed.
    ///
    /// # Examples
    ///
    /// ```
    /// # use ascii::AsciiStr;
    /// let example = AsciiStr::from_str("  \twhite \tspace  \t").unwrap();
    /// assert_eq!("  \twhite \tspace", example.trim_right());
    /// ```
    pub fn trim_right(&self) -> &Self {
        unsafe { mem::transmute(self.as_str().trim_right()) }
    }
}

impl PartialEq<str> for AsciiStr {
    fn eq(&self, other: &str) -> bool {
        self.as_str() == other
    }
}

impl PartialEq<AsciiStr> for str {
    fn eq(&self, other: &AsciiStr) -> bool {
        other.as_str() == self
    }
}

/*
impl PartialOrd<AsciiString> for AsciiStr {
    #[inline]
    fn partial_cmp(&self, other: &AsciiString) -> Option<Ordering> {
        self.as_bytes().partial_cmp(other.as_bytes())
    }
}
*/

impl ToOwned for AsciiStr {
    type Owned = AsciiString;

    fn to_owned(&self) -> AsciiString {
        self.to_ascii_string()
    }
}

impl AsRef<[u8]> for AsciiStr {
    fn as_ref(&self) -> &[u8] {
        self.as_bytes()
    }
}

impl AsRef<str> for AsciiStr {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl fmt::Display for AsciiStr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(self.as_str(), f)
    }
}

impl fmt::Debug for AsciiStr {
   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
       fmt::Debug::fmt(self.as_str(), f)
   }
}

macro_rules! impl_index {
    ($lhs:ty, $idx:ty, $rhs:ty) => {
        impl Index<$idx> for $lhs {
            type Output = $rhs;

            #[inline]
            fn index(&self, index: $idx) -> &$rhs {
                unsafe { mem::transmute(&self.slice[index]) }
            }
        }

        impl IndexMut<$idx> for $lhs {
            #[inline]
            fn index_mut(&mut self, index: $idx) -> &mut $rhs {
                unsafe { mem::transmute(&mut self.slice[index]) }
            }
        }
    }
}

impl_index! { AsciiStr, usize, Ascii }
impl_index! { AsciiStr, Range<usize>, AsciiStr }
impl_index! { AsciiStr, RangeTo<usize>, AsciiStr }
impl_index! { AsciiStr, RangeFrom<usize>, AsciiStr }
impl_index! { AsciiStr, RangeFull, AsciiStr }

#[cfg(feature = "unstable")]
impl AsciiExt for AsciiStr {
    type Owned = AsciiString;

    #[inline]
    fn is_ascii(&self) -> bool {
        true
    }

    fn to_ascii_uppercase(&self) -> AsciiString {
        let mut ascii_string = self.to_ascii_string();
        ascii_string.make_ascii_uppercase();
        ascii_string
    }

    fn to_ascii_lowercase(&self) -> AsciiString {
        let mut ascii_string = self.to_ascii_string();
        ascii_string.make_ascii_uppercase();
        ascii_string
    }

    fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
        self.len() == other.len() &&
        self.slice.iter().zip(other.slice.iter()).all(|(a, b)| a.eq_ignore_ascii_case(b))
    }

    fn make_ascii_uppercase(&mut self) {
        for ascii in &mut self.slice {
            ascii.make_ascii_uppercase();
        }
    }

    fn make_ascii_lowercase(&mut self) {
        for ascii in &mut self.slice {
            ascii.make_ascii_lowercase();
        }
    }
}

impl<'a> AsciiCast<'a> for [u8] {
    type Target = &'a AsciiStr;

    #[inline]
    unsafe fn to_ascii_nocheck(&'a self) -> &'a AsciiStr {
        mem::transmute(self)
    }
}

impl<'a> AsciiCast<'a> for str {
    type Target = &'a AsciiStr;

    #[inline]
    unsafe fn to_ascii_nocheck(&'a self) -> &'a AsciiStr {
        mem::transmute(self)
    }
}

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

    #[test]
    fn as_str() {
        let b = &[40_u8, 32, 59];
        let v = AsciiStr::from_bytes(b).unwrap();
        assert_eq!(v.as_str(), "( ;");
        assert_eq!(AsRef::<str>::as_ref(v), "( ;");
    }

    #[test]
    fn as_bytes() {
        let b = &[40_u8, 32, 59];
        let v = AsciiStr::from_bytes(b).unwrap();
        assert_eq!(v.as_bytes(), b"( ;");
        assert_eq!(AsRef::<[u8]>::as_ref(v), b"( ;");
    }

    #[test]
    fn fmt_display_ascii_str() {
        let s = "abc".to_ascii().unwrap();
        assert_eq!(format!("{}", s), "abc".to_string());
    }

    #[test]
    fn fmt_debug_ascii_str() {
        let s = "abc".to_ascii().unwrap();
        assert_eq!(format!("{:?}", s), "\"abc\"".to_string());
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2018, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#[macro_use]
extern crate criterion;

use ring::rand::*;

use criterion::Criterion;

fn handshake(c: &mut Criterion) {
    let mut buf = [0; 65535];

    let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
    config
        .load_cert_chain_from_pem_file("examples/cert.crt")
        .unwrap();
    config
        .load_priv_key_from_pem_file("examples/cert.key")
        .unwrap();
    config
        .set_application_protos(b"\x06proto1\x06proto2")
        .unwrap();
    config.set_initial_max_data(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_bidi_local(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_bidi_remote(2u64.pow(62) - 1);
    config.set_initial_max_streams_bidi(3);
    config.set_initial_max_streams_uni(3);
    config.verify_peer(false);

    c.bench_function("handshake", move |b| {
        b.iter(|| {
            let mut pipe =
                quiche::testing::Pipe::with_config(&mut config).unwrap();
            pipe.handshake(&mut buf).unwrap();
        })
    });
}

fn stream(c: &mut Criterion) {
    let mut buf = [0; 65535];

    let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
    config
        .load_cert_chain_from_pem_file("examples/cert.crt")
        .unwrap();
    config
        .load_priv_key_from_pem_file("examples/cert.key")
        .unwrap();
    config
        .set_application_protos(b"\x06proto1\x06proto2")
        .unwrap();
    config.set_max_packet_size(1350);
    config.set_initial_max_data(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_bidi_local(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_bidi_remote(2u64.pow(62) - 1);
    config.set_initial_max_streams_bidi(3);
    config.set_initial_max_streams_uni(3);
    config.verify_peer(false);

    let mut pipe = quiche::testing::Pipe::with_config(&mut config).unwrap();
    pipe.handshake(&mut buf).unwrap();

    let mut send_buf = vec![0; 5_000_000];
    SystemRandom::new().fill(&mut send_buf[..]).unwrap();

    let mut recv_buf = vec![0; send_buf.len()];

    c.bench_function_over_inputs(
        "stream",
        move |b, &&size| {
            b.iter(|| {
                pipe.client
                    .stream_send(4, &send_buf[..size], false)
                    .unwrap();

                let mut recv_len = 0;

                while recv_len < size {
                    loop {
                        let len = match pipe.client.send(&mut buf) {
                            Ok(write) => write,

                            Err(quiche::Error::Done) => break,

                            Err(e) => panic!("client send failed {}", e),
                        };

                        match pipe.server.recv(&mut buf[..len]) {
                            Ok(_) => (),

                            Err(quiche::Error::Done) => (),

                            Err(e) => panic!("server recv failed {}", e),
                        }
                    }

                    let (len, _) = pipe
                        .server
                        .stream_recv(4, &mut recv_buf[recv_len..])
                        .unwrap();
                    recv_len += len;

                    loop {
                        let len = match pipe.server.send(&mut buf) {
                            Ok(write) => write,

                            Err(quiche::Error::Done) => break,

                            Err(e) => panic!("server send failed {}", e),
                        };

                        match pipe.client.recv(&mut buf[..len]) {
                            Ok(_) => (),

                            Err(quiche::Error::Done) => (),

                            Err(e) => panic!("client recv failed {}", e),
                        }
                    }
                }

                assert_eq!(&recv_buf[..size], &send_buf[..size]);
            })
        },
        &[128_000, 5_000_000],
    );
}

criterion_group!(benches, handshake, stream);

criterion_main!(benches);
<commit_msg>benches: add HTTP/3 request/response benchmark<commit_after>// Copyright (C) 2018, Cloudflare, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#[macro_use]
extern crate criterion;

use ring::rand::*;

use criterion::Criterion;

fn handshake(c: &mut Criterion) {
    let mut buf = [0; 65535];

    let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
    config
        .load_cert_chain_from_pem_file("examples/cert.crt")
        .unwrap();
    config
        .load_priv_key_from_pem_file("examples/cert.key")
        .unwrap();
    config
        .set_application_protos(b"\x06proto1\x06proto2")
        .unwrap();
    config.set_initial_max_data(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_bidi_local(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_bidi_remote(2u64.pow(62) - 1);
    config.set_initial_max_streams_bidi(3);
    config.set_initial_max_streams_uni(3);
    config.verify_peer(false);

    c.bench_function("handshake", move |b| {
        b.iter(|| {
            let mut pipe =
                quiche::testing::Pipe::with_config(&mut config).unwrap();
            pipe.handshake(&mut buf).unwrap();
        })
    });
}

fn stream(c: &mut Criterion) {
    let mut buf = [0; 65535];

    let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
    config
        .load_cert_chain_from_pem_file("examples/cert.crt")
        .unwrap();
    config
        .load_priv_key_from_pem_file("examples/cert.key")
        .unwrap();
    config
        .set_application_protos(b"\x06proto1\x06proto2")
        .unwrap();
    config.set_max_packet_size(1350);
    config.set_initial_max_data(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_bidi_local(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_bidi_remote(2u64.pow(62) - 1);
    config.set_initial_max_streams_bidi(3);
    config.set_initial_max_streams_uni(3);
    config.verify_peer(false);

    let mut pipe = quiche::testing::Pipe::with_config(&mut config).unwrap();
    pipe.handshake(&mut buf).unwrap();

    let mut send_buf = vec![0; 5_000_000];
    SystemRandom::new().fill(&mut send_buf[..]).unwrap();

    let mut recv_buf = vec![0; send_buf.len()];

    c.bench_function_over_inputs(
        "stream",
        move |b, &&size| {
            b.iter(|| {
                pipe.client
                    .stream_send(4, &send_buf[..size], false)
                    .unwrap();

                let mut recv_len = 0;

                while recv_len < size {
                    loop {
                        let len = match pipe.client.send(&mut buf) {
                            Ok(write) => write,

                            Err(quiche::Error::Done) => break,

                            Err(e) => panic!("client send failed {}", e),
                        };

                        match pipe.server.recv(&mut buf[..len]) {
                            Ok(_) => (),

                            Err(quiche::Error::Done) => (),

                            Err(e) => panic!("server recv failed {}", e),
                        }
                    }

                    let (len, _) = pipe
                        .server
                        .stream_recv(4, &mut recv_buf[recv_len..])
                        .unwrap();
                    recv_len += len;

                    loop {
                        let len = match pipe.server.send(&mut buf) {
                            Ok(write) => write,

                            Err(quiche::Error::Done) => break,

                            Err(e) => panic!("server send failed {}", e),
                        };

                        match pipe.client.recv(&mut buf[..len]) {
                            Ok(_) => (),

                            Err(quiche::Error::Done) => (),

                            Err(e) => panic!("client recv failed {}", e),
                        }
                    }
                }

                assert_eq!(recv_len, size);
                assert_eq!(&recv_buf[..size], &send_buf[..size]);
            })
        },
        &[128_000, 5_000_000],
    );
}

fn http3(c: &mut Criterion) {
    let mut buf = [0; 65535];

    let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION).unwrap();
    config
        .load_cert_chain_from_pem_file("examples/cert.crt")
        .unwrap();
    config
        .load_priv_key_from_pem_file("examples/cert.key")
        .unwrap();
    config
        .set_application_protos(quiche::h3::APPLICATION_PROTOCOL)
        .unwrap();
    config.set_max_packet_size(1350);
    config.set_initial_max_data(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_bidi_local(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_bidi_remote(2u64.pow(62) - 1);
    config.set_initial_max_stream_data_uni(150);
    config.set_initial_max_streams_bidi(2u64.pow(60) - 1);
    config.set_initial_max_streams_uni(5);
    config.verify_peer(false);

    let mut h3_config = quiche::h3::Config::new(0, 1024, 0, 0).unwrap();

    let mut s =
        quiche::h3::testing::Session::with_configs(&mut config, &mut h3_config)
            .unwrap();
    s.handshake().unwrap();

    let mut send_buf = vec![0; 5_000_000];
    SystemRandom::new().fill(&mut send_buf[..]).unwrap();

    let mut recv_buf = vec![0; send_buf.len()];

    let req = [
        quiche::h3::Header::new(":method", "GET"),
        quiche::h3::Header::new(":scheme", "https"),
        quiche::h3::Header::new(":authority", "quic.tech"),
        quiche::h3::Header::new(":path", "/test"),
        quiche::h3::Header::new("user-agent", "quiche-test"),
    ];

    let resp = [
        quiche::h3::Header::new(":status", "200"),
        quiche::h3::Header::new("server", "quiche-test"),
    ];

    c.bench_function_over_inputs(
        "http3",
        move |b, &&size| {
            b.iter(|| {
                s.client
                    .send_request(&mut s.pipe.client, &req, true)
                    .unwrap();

                let mut recv_len = 0;

                while recv_len < size {
                    loop {
                        let len = match s.pipe.client.send(&mut buf) {
                            Ok(write) => write,

                            Err(quiche::Error::Done) => break,

                            Err(e) => panic!("client send failed {}", e),
                        };

                        match s.pipe.server.recv(&mut buf[..len]) {
                            Ok(_) => (),

                            Err(quiche::Error::Done) => (),

                            Err(e) => panic!("server recv failed {}", e),
                        }
                    }

                    match s.server.poll(&mut s.pipe.server) {
                        Ok((stream, quiche::h3::Event::Headers(_))) => {
                            s.server
                                .send_response(
                                    &mut s.pipe.server,
                                    stream,
                                    &resp,
                                    false,
                                )
                                .unwrap();

                            s.server
                                .send_body(
                                    &mut s.pipe.server,
                                    stream,
                                    &send_buf[..size],
                                    true,
                                )
                                .unwrap();
                        },

                        _ => (),
                    }

                    loop {
                        let len = match s.pipe.server.send(&mut buf) {
                            Ok(write) => write,

                            Err(quiche::Error::Done) => break,

                            Err(e) => panic!("server send failed {}", e),
                        };

                        match s.pipe.client.recv(&mut buf[..len]) {
                            Ok(_) => (),

                            Err(quiche::Error::Done) => (),

                            Err(e) => panic!("client recv failed {}", e),
                        }
                    }

                    while let Ok(ev) = s.client.poll(&mut s.pipe.client) {
                        match ev {
                            (_, quiche::h3::Event::Data(data)) => {
                                &mut recv_buf[recv_len..recv_len + data.len()]
                                    .copy_from_slice(&data);
                                recv_len += data.len();
                            },

                            _ => (),
                        };
                    }
                }

                assert_eq!(recv_len, size);
                assert_eq!(&recv_buf[..size], &send_buf[..size]);
            })
        },
        &[0, 128_000, 5_000_000],
    );
}

criterion_group!(benches, handshake, stream, http3);

criterion_main!(benches);
<|endoftext|>


<commit_before>extern crate arg_parser;
extern crate extra;

use std::env;
use std::io::{stdout, stderr, Write};
use std::process::exit;
use arg_parser::ArgParser;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{clear} */ r#"
NAME
    clear - clear the terminal screen

SYNOPSIS
    clear [ -h | --help]

DESCRIPTION
    Clear the screen, if possible

OPTIONS
    -h
    --help
        display this help and exit
"#; /* @MANEND */

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(1)
        .add_flag(&["h", "help"]);
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write_all(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    }

    let _ = stdout.write(b"\x1B[2J");
}
<commit_msg>clear.rs: Cursor to home position<commit_after>extern crate arg_parser;
extern crate extra;

use std::env;
use std::io::{stdout, stderr, Write};
use std::process::exit;
use arg_parser::ArgParser;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{clear} */ r#"
NAME
    clear - clear the terminal screen

SYNOPSIS
    clear [ -h | --help]

DESCRIPTION
    Clear the screen, if possible

OPTIONS
    -h
    --help
        display this help and exit
"#; /* @MANEND */

fn main() {
    let stdout = stdout();
    let mut stdout = stdout.lock();
    let mut stderr = stderr();
    let mut parser = ArgParser::new(1)
        .add_flag(&["h", "help"]);
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write_all(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    }

    let _ = stdout.write(b"\x1b[H\x1B[2J");
}
<|endoftext|>


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

use byteorder::{BigEndian, WriteBytesExt};

use util::codec::bytes;
use raftserver::{Result, other};

pub const MIN_KEY: &'static [u8] = &[];
pub const MAX_KEY: &'static [u8] = &[0xFF];

// local is in (0x01, 0x02);
pub const LOCAL_PREFIX: u8 = 0x01;
pub const LOCAL_MIN_KEY: &'static [u8] = &[LOCAL_PREFIX];
pub const LOCAL_MAX_KEY: &'static [u8] = &[LOCAL_PREFIX + 1];
pub const META1_PREFIX: u8 = 0x02;
pub const META2_PREFIX: u8 = 0x03;
pub const META1_PREFIX_KEY: &'static [u8] = &[META1_PREFIX];
pub const META2_PREFIX_KEY: &'static [u8] = &[META2_PREFIX];
pub const META_MIN_KEY: &'static [u8] = &[META1_PREFIX];
pub const META_MAX_KEY: &'static [u8] = &[META2_PREFIX + 1];
pub const META1_MAX_KEY: &'static [u8] = &[META1_PREFIX, MAX_KEY[0]];
pub const META2_MAX_KEY: &'static [u8] = &[META2_PREFIX, MAX_KEY[0]];

pub const DATA_PREFIX: u8 = b'z';
pub const DATA_PREFIX_KEY: &'static [u8] = &[DATA_PREFIX];

// Following keys are all local keys, so the first byte must be 0x01.
pub const STORE_IDENT_KEY: &'static [u8] = &[LOCAL_PREFIX, 0x01];
pub const REGION_ID_PREFIX: u8 = 0x02;
pub const REGION_ID_PREFIX_KEY: &'static [u8] = &[LOCAL_PREFIX, REGION_ID_PREFIX];
pub const REGION_META_PREFIX: u8 = 0x03;
pub const REGION_META_PREFIX_KEY: &'static [u8] = &[LOCAL_PREFIX, REGION_META_PREFIX];
pub const REGION_META_MIN_KEY: &'static [u8] = &[LOCAL_PREFIX, REGION_META_PREFIX];
pub const REGION_META_MAX_KEY: &'static [u8] = &[LOCAL_PREFIX, REGION_META_PREFIX + 1];

// Following are the suffix after the local prefix.
// For region id
pub const RAFT_LOG_SUFFIX: u8 = 0x01;
pub const RAFT_HARD_STATE_SUFFIX: u8 = 0x02;
pub const RAFT_APPLIED_INDEX_SUFFIX: u8 = 0x03;
pub const RAFT_LAST_INDEX_SUFFIX: u8 = 0x04;
pub const RAFT_TRUNCATED_STATE_SUFFIX: u8 = 0x05;

// For region meta
pub const REGION_INFO_SUFFIX: u8 = 0x01;

pub fn store_ident_key() -> Vec<u8> {
    STORE_IDENT_KEY.to_vec()
}

fn make_region_id_key(region_id: u64, suffix: u8, extra_cap: usize) -> Vec<u8> {
    let mut key = Vec::with_capacity(REGION_ID_PREFIX_KEY.len() + 8 + 1 + extra_cap);
    key.extend_from_slice(REGION_ID_PREFIX_KEY);
    // no need check error here, can't panic;
    key.write_u64::<BigEndian>(region_id).unwrap();
    key.push(suffix);
    key
}

pub fn region_id_prefix(region_id: u64) -> Vec<u8> {
    let mut key = Vec::with_capacity(REGION_ID_PREFIX_KEY.len() + 8);
    key.extend_from_slice(REGION_ID_PREFIX_KEY);
    // no need check error here, can't panic;
    key.write_u64::<BigEndian>(region_id).unwrap();
    key
}

pub fn raft_log_key(region_id: u64, log_index: u64) -> Vec<u8> {
    let mut key = make_region_id_key(region_id, RAFT_LOG_SUFFIX, 8);
    // no need check error here, can't panic;
    key.write_u64::<BigEndian>(log_index).unwrap();
    key
}

pub fn raft_log_prefix(region_id: u64) -> Vec<u8> {
    make_region_id_key(region_id, RAFT_LOG_SUFFIX, 0)
}

pub fn raft_hard_state_key(region_id: u64) -> Vec<u8> {
    make_region_id_key(region_id, RAFT_HARD_STATE_SUFFIX, 0)
}

pub fn raft_applied_index_key(region_id: u64) -> Vec<u8> {
    make_region_id_key(region_id, RAFT_APPLIED_INDEX_SUFFIX, 0)
}

pub fn raft_last_index_key(region_id: u64) -> Vec<u8> {
    make_region_id_key(region_id, RAFT_LAST_INDEX_SUFFIX, 0)
}

pub fn raft_truncated_state_key(region_id: u64) -> Vec<u8> {
    make_region_id_key(region_id, RAFT_TRUNCATED_STATE_SUFFIX, 0)
}

fn make_region_meta_key(region_key: &[u8], suffix: u8) -> Vec<u8> {
    let mut key = Vec::with_capacity(REGION_META_PREFIX_KEY.len() + 1 +
                                     bytes::max_encoded_bytes_size(region_key.len()));
    key.extend_from_slice(REGION_META_PREFIX_KEY);
    key.extend(bytes::encode_bytes(region_key));
    key.push(suffix);
    key
}

// Decode encoded region meta key, return the region key and meta suffix type.
pub fn decode_region_meta_key(key: &[u8]) -> Result<(Vec<u8>, u8)> {
    if !key.starts_with(REGION_META_PREFIX_KEY) {
        return Err(other(format!("invalid region meta prefix for key {:?}", key)));
    }

    let (region_key, cnt) = try!(bytes::decode_bytes(&key[REGION_META_PREFIX_KEY.len()..]));
    // The last character must be the suffix type, 1 byte.
    if REGION_META_PREFIX_KEY.len() + cnt + 1 != key.len() {
        return Err(other(format!("invalid region meta suffix for key {:?}", key)));
    }

    Ok((region_key, key[key.len() - 1]))
}

pub fn region_meta_prefix(region_key: &[u8]) -> Vec<u8> {
    let mut key = Vec::with_capacity(REGION_META_PREFIX_KEY.len() +
                                     bytes::max_encoded_bytes_size(region_key.len()));
    key.extend_from_slice(REGION_META_PREFIX_KEY);
    key.extend(bytes::encode_bytes(region_key));
    key
}

pub fn region_info_key(region_key: &[u8]) -> Vec<u8> {
    make_region_meta_key(region_key, REGION_INFO_SUFFIX)
}

// Returns a region route meta (meta1, meta2) indexing key for the
// given key.
// For data key, it returns a meta2 key, e.g, "zabc" -> \0x03"zabc"
// For meta2 key, it returns a meta1 key, e.g, \0x03\"zabc" -> \0x02"zabc"
// For meta1 key, it returns a MIN_KEY, e.g, \x02\"zabc" -> ""
pub fn region_route_meta_key(key: &[u8]) -> Vec<u8> {
    if key.len() == 0 {
        return MIN_KEY.to_vec();
    }

    match key[0] {
        META1_PREFIX => MIN_KEY.to_vec(),
        META2_PREFIX => vec![META1_PREFIX_KEY, &key[1..]].concat(),
        _ => vec![META2_PREFIX_KEY, key].concat(),
    }
}

pub fn validate_region_route_meta_key(key: &[u8]) -> Result<()> {
    if key == MIN_KEY {
        return Ok(());
    }

    // TODO: Maybe no necessary to check this, remove later?
    if key.len() < META1_PREFIX_KEY.len() {
        return Err(other(format!("{:?} is too short", key)));
    }

    let prefix = key[0];
    if prefix != META2_PREFIX && prefix != META1_PREFIX {
        return Err(other(format!("{:?} is not a meta key", key)));
    }

    // TODO: check data prefix later?
    if MAX_KEY < &key[META1_PREFIX_KEY.len()..] {
        return Err(other(format!("{:?} is > {:?}", key, MAX_KEY)));
    }

    Ok(())
}

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

    #[test]
    fn test_region_id_key() {
        let tbls = vec![0, 1, 1024, !0];
        for region_id in tbls {
            let prefix = region_id_prefix(region_id);

            assert!(raft_log_prefix(region_id).starts_with(&prefix));
            assert!(raft_log_key(region_id, 1).starts_with(&prefix));
            assert!(raft_hard_state_key(region_id).starts_with(&prefix));
            assert!(raft_applied_index_key(region_id).starts_with(&prefix));
            assert!(raft_last_index_key(region_id).starts_with(&prefix));
            assert!(raft_truncated_state_key(region_id).starts_with(&prefix));
        }

        // test sort.
        let tbls = vec![(1, 0, Ordering::Greater), (1, 1, Ordering::Equal), (1, 2, Ordering::Less)];
        for tbl in tbls {
            let lhs = region_id_prefix(tbl.0);
            let rhs = region_id_prefix(tbl.1);
            assert_eq!(lhs.partial_cmp(&rhs), Some(tbl.2));
        }
    }

    #[test]
    fn test_raft_log_sort() {
        let tbls = vec![(1, 1, 1, 2, Ordering::Less),
                        (2, 1, 1, 2, Ordering::Greater),
                        (1, 1, 1, 1, Ordering::Equal)];

        for tbl in tbls {
            let lhs = raft_log_key(tbl.0, tbl.1);
            let rhs = raft_log_key(tbl.2, tbl.3);
            assert_eq!(lhs.partial_cmp(&rhs), Some(tbl.4));
        }
    }

    #[test]
    fn test_region_meta_key() {
        let tbls: Vec<&[u8]> = vec![b"123", b"abc", b"hello_world"];
        for key in tbls {
            let prefix = region_meta_prefix(key);
            let info_key = region_info_key(key);
            assert!(info_key.starts_with(&prefix));

            assert_eq!(decode_region_meta_key(&info_key).unwrap(),
                       (key.to_vec(), REGION_INFO_SUFFIX));
        }

        // test sort.
        let tbls: Vec<(&[u8], &[u8], Ordering)> = vec![
        (b"1", b"2", Ordering::Less),
        (b"1", b"1", Ordering::Equal),
        (b"2", b"1", Ordering::Greater),
        (b"2", b"123", Ordering::Greater),
        ];

        for tbl in tbls {
            let lhs = region_info_key(tbl.0);
            let rhs = region_info_key(tbl.1);
            assert_eq!(lhs.partial_cmp(&rhs), Some(tbl.2));
        }
    }

    fn route_key(prefix: u8, key: &[u8]) -> Vec<u8> {
        let mut v = vec![];
        v.push(prefix);
        v.extend_from_slice(key);
        v
    }

    fn meta1_key(key: &[u8]) -> Vec<u8> {
        route_key(META1_PREFIX, key)
    }

    fn meta2_key(key: &[u8]) -> Vec<u8> {
        route_key(META2_PREFIX, key)
    }

    fn data_key(key: &[u8]) -> Vec<u8> {
        route_key(DATA_PREFIX, key)
    }

    #[test]
    fn test_region_route_meta_key() {
        let dkey = data_key(b"abc");
        let tbls = vec![
            (vec![], vec![]),
            (meta1_key(&dkey), vec![]),
            (meta2_key(&dkey), meta1_key(&dkey)),
            (dkey.clone(), meta2_key(&dkey)),
        ];

        for tbl in tbls {
            assert_eq!(region_route_meta_key(&tbl.0), tbl.1);
        }

        let tbls = vec![
            (vec![], true),
            (vec![0xFF], false),
            (vec![DATA_PREFIX, 1], false),
            (vec![META1_PREFIX - 1, 1], false),
            (vec![META2_PREFIX + 1, 1], false),
            (vec![META1_PREFIX, 1], true),
            (vec![META2_PREFIX, 1], true),
            (vec![META1_PREFIX, 0xFF, 1], false),
            (vec![META2_PREFIX, 0xFF, 1], false),
        ];

        for tbl in tbls {
            match validate_region_route_meta_key(&tbl.0) {
                Ok(_) => assert!(tbl.1),
                Err(_) => assert!(!tbl.1),
            }
        }
    }
}
<commit_msg>raftserver: Address comment.<commit_after>use std::vec::Vec;

use byteorder::{BigEndian, WriteBytesExt};

use util::codec::bytes;
use raftserver::{Result, other};

pub const MIN_KEY: &'static [u8] = &[];
pub const MAX_KEY: &'static [u8] = &[0xFF];

// local is in (0x01, 0x02);
pub const LOCAL_PREFIX: u8 = 0x01;
pub const LOCAL_MIN_KEY: &'static [u8] = &[LOCAL_PREFIX];
pub const LOCAL_MAX_KEY: &'static [u8] = &[LOCAL_PREFIX + 1];
pub const META1_PREFIX: u8 = 0x02;
pub const META2_PREFIX: u8 = 0x03;
pub const META1_PREFIX_KEY: &'static [u8] = &[META1_PREFIX];
pub const META2_PREFIX_KEY: &'static [u8] = &[META2_PREFIX];
pub const META_MIN_KEY: &'static [u8] = &[META1_PREFIX];
pub const META_MAX_KEY: &'static [u8] = &[META2_PREFIX + 1];
pub const META1_MAX_KEY: &'static [u8] = &[META1_PREFIX, MAX_KEY[0]];
pub const META2_MAX_KEY: &'static [u8] = &[META2_PREFIX, MAX_KEY[0]];

pub const DATA_PREFIX: u8 = b'z';
pub const DATA_PREFIX_KEY: &'static [u8] = &[DATA_PREFIX];

// Following keys are all local keys, so the first byte must be 0x01.
pub const STORE_IDENT_KEY: &'static [u8] = &[LOCAL_PREFIX, 0x01];
pub const REGION_ID_PREFIX: u8 = 0x02;
pub const REGION_ID_PREFIX_KEY: &'static [u8] = &[LOCAL_PREFIX, REGION_ID_PREFIX];
pub const REGION_META_PREFIX: u8 = 0x03;
pub const REGION_META_PREFIX_KEY: &'static [u8] = &[LOCAL_PREFIX, REGION_META_PREFIX];
pub const REGION_META_MIN_KEY: &'static [u8] = &[LOCAL_PREFIX, REGION_META_PREFIX];
pub const REGION_META_MAX_KEY: &'static [u8] = &[LOCAL_PREFIX, REGION_META_PREFIX + 1];

// Following are the suffix after the local prefix.
// For region id
pub const RAFT_LOG_SUFFIX: u8 = 0x01;
pub const RAFT_HARD_STATE_SUFFIX: u8 = 0x02;
pub const RAFT_APPLIED_INDEX_SUFFIX: u8 = 0x03;
pub const RAFT_LAST_INDEX_SUFFIX: u8 = 0x04;
pub const RAFT_TRUNCATED_STATE_SUFFIX: u8 = 0x05;

// For region meta
pub const REGION_INFO_SUFFIX: u8 = 0x01;

pub fn store_ident_key() -> Vec<u8> {
    STORE_IDENT_KEY.to_vec()
}

fn make_region_id_key(region_id: u64, suffix: u8, extra_cap: usize) -> Vec<u8> {
    let mut key = Vec::with_capacity(REGION_ID_PREFIX_KEY.len() + 8 + 1 + extra_cap);
    key.extend_from_slice(REGION_ID_PREFIX_KEY);
    // no need check error here, can't panic;
    key.write_u64::<BigEndian>(region_id).unwrap();
    key.push(suffix);
    key
}

pub fn region_id_prefix(region_id: u64) -> Vec<u8> {
    let mut key = Vec::with_capacity(REGION_ID_PREFIX_KEY.len() + 8);
    key.extend_from_slice(REGION_ID_PREFIX_KEY);
    // no need check error here, can't panic;
    key.write_u64::<BigEndian>(region_id).unwrap();
    key
}

pub fn raft_log_key(region_id: u64, log_index: u64) -> Vec<u8> {
    let mut key = make_region_id_key(region_id, RAFT_LOG_SUFFIX, 8);
    // no need check error here, can't panic;
    key.write_u64::<BigEndian>(log_index).unwrap();
    key
}

pub fn raft_log_prefix(region_id: u64) -> Vec<u8> {
    make_region_id_key(region_id, RAFT_LOG_SUFFIX, 0)
}

pub fn raft_hard_state_key(region_id: u64) -> Vec<u8> {
    make_region_id_key(region_id, RAFT_HARD_STATE_SUFFIX, 0)
}

pub fn raft_applied_index_key(region_id: u64) -> Vec<u8> {
    make_region_id_key(region_id, RAFT_APPLIED_INDEX_SUFFIX, 0)
}

pub fn raft_last_index_key(region_id: u64) -> Vec<u8> {
    make_region_id_key(region_id, RAFT_LAST_INDEX_SUFFIX, 0)
}

pub fn raft_truncated_state_key(region_id: u64) -> Vec<u8> {
    make_region_id_key(region_id, RAFT_TRUNCATED_STATE_SUFFIX, 0)
}

fn make_region_meta_key(region_key: &[u8], suffix: u8) -> Vec<u8> {
    let mut key = Vec::with_capacity(REGION_META_PREFIX_KEY.len() + 1 +
                                     bytes::max_encoded_bytes_size(region_key.len()));
    key.extend_from_slice(REGION_META_PREFIX_KEY);
    key.extend(bytes::encode_bytes(region_key));
    key.push(suffix);
    key
}

// Decode encoded region meta key, return the region key and meta suffix type.
pub fn decode_region_meta_key(key: &[u8]) -> Result<(Vec<u8>, u8)> {
    if !key.starts_with(REGION_META_PREFIX_KEY) {
        return Err(other(format!("invalid region meta prefix for key {:?}", key)));
    }

    let (region_key, cnt) = try!(bytes::decode_bytes(&key[REGION_META_PREFIX_KEY.len()..]));
    // The last character must be the suffix type, 1 byte.
    if REGION_META_PREFIX_KEY.len() + cnt + 1 != key.len() {
        return Err(other(format!("invalid region meta suffix for key {:?}", key)));
    }

    Ok((region_key, key[key.len() - 1]))
}

pub fn region_meta_prefix(region_key: &[u8]) -> Vec<u8> {
    let mut key = Vec::with_capacity(REGION_META_PREFIX_KEY.len() +
                                     bytes::max_encoded_bytes_size(region_key.len()));
    key.extend_from_slice(REGION_META_PREFIX_KEY);
    key.extend(bytes::encode_bytes(region_key));
    key
}

pub fn region_info_key(region_key: &[u8]) -> Vec<u8> {
    make_region_meta_key(region_key, REGION_INFO_SUFFIX)
}

// Returns a region route meta (meta1, meta2) indexing key for the
// given key.
// For data key, it returns a meta2 key, e.g, "zabc" -> \0x03"zabc"
// For meta2 key, it returns a meta1 key, e.g, \0x03\"zabc" -> \0x02"zabc"
// For meta1 key, it returns a MIN_KEY, e.g, \x02\"zabc" -> ""
pub fn region_route_meta_key(key: &[u8]) -> Vec<u8> {
    if key.len() == 0 {
        return MIN_KEY.to_vec();
    }

    match key[0] {
        META1_PREFIX => MIN_KEY.to_vec(),
        META2_PREFIX => vec![META1_PREFIX_KEY, &key[1..]].concat(),
        _ => vec![META2_PREFIX_KEY, key].concat(),
    }
}

pub fn validate_region_route_meta_key(key: &[u8]) -> Result<()> {
    if key == MIN_KEY {
        return Ok(());
    }

    // TODO: Maybe no necessary to check this, remove later?
    if key.len() < META1_PREFIX_KEY.len() {
        return Err(other(format!("{:?} is too short", key)));
    }

    let prefix = key[0];
    if prefix != META2_PREFIX && prefix != META1_PREFIX {
        return Err(other(format!("{:?} is not a meta key", key)));
    }

    // TODO: check data prefix later?
    if MAX_KEY < &key[META1_PREFIX_KEY.len()..] {
        return Err(other(format!("{:?} is > {:?}", key, MAX_KEY)));
    }

    Ok(())
}

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

    #[test]
    fn test_region_id_key() {
        let region_ids = vec![0, 1, 1024, !0];
        for region_id in region_ids {
            let prefix = region_id_prefix(region_id);

            assert!(raft_log_prefix(region_id).starts_with(&prefix));
            assert!(raft_log_key(region_id, 1).starts_with(&prefix));
            assert!(raft_hard_state_key(region_id).starts_with(&prefix));
            assert!(raft_applied_index_key(region_id).starts_with(&prefix));
            assert!(raft_last_index_key(region_id).starts_with(&prefix));
            assert!(raft_truncated_state_key(region_id).starts_with(&prefix));
        }

        // test sort.
        let tbls = vec![(1, 0, Ordering::Greater), (1, 1, Ordering::Equal), (1, 2, Ordering::Less)];
        for (lid, rid, order) in tbls {
            let lhs = region_id_prefix(lid);
            let rhs = region_id_prefix(rid);
            assert_eq!(lhs.partial_cmp(&rhs), Some(order));
        }
    }

    #[test]
    fn test_raft_log_sort() {
        let tbls = vec![(1, 1, 1, 2, Ordering::Less),
                        (2, 1, 1, 2, Ordering::Greater),
                        (1, 1, 1, 1, Ordering::Equal)];

        for (lid, l_log_id, rid, r_log_id, order) in tbls {
            let lhs = raft_log_key(lid, l_log_id);
            let rhs = raft_log_key(rid, r_log_id);
            assert_eq!(lhs.partial_cmp(&rhs), Some(order));
        }
    }

    #[test]
    fn test_region_meta_key() {
        let keys: Vec<&[u8]> = vec![b"123", b"abc", b"hello_world"];
        for key in keys {
            let prefix = region_meta_prefix(key);
            let info_key = region_info_key(key);
            assert!(info_key.starts_with(&prefix));

            assert_eq!(decode_region_meta_key(&info_key).unwrap(),
                       (key.to_vec(), REGION_INFO_SUFFIX));
        }

        // test sort.
        let tbls: Vec<(&[u8], &[u8], Ordering)> = vec![
        (b"1", b"2", Ordering::Less),
        (b"1", b"1", Ordering::Equal),
        (b"2", b"1", Ordering::Greater),
        (b"2", b"123", Ordering::Greater),
        ];

        for (lkey, rkey, order) in tbls {
            let lhs = region_info_key(lkey);
            let rhs = region_info_key(rkey);
            assert_eq!(lhs.partial_cmp(&rhs), Some(order));
        }
    }

    fn route_key(prefix: u8, key: &[u8]) -> Vec<u8> {
        let mut v = vec![];
        v.push(prefix);
        v.extend_from_slice(key);
        v
    }

    fn meta1_key(key: &[u8]) -> Vec<u8> {
        route_key(META1_PREFIX, key)
    }

    fn meta2_key(key: &[u8]) -> Vec<u8> {
        route_key(META2_PREFIX, key)
    }

    fn data_key(key: &[u8]) -> Vec<u8> {
        route_key(DATA_PREFIX, key)
    }

    #[test]
    fn test_region_route_meta_key() {
        let dkey = data_key(b"abc");
        let tbls = vec![
            (vec![], vec![]),
            (meta1_key(&dkey), vec![]),
            (meta2_key(&dkey), meta1_key(&dkey)),
            (dkey.clone(), meta2_key(&dkey)),
        ];

        for (lkey, rkey) in tbls {
            assert_eq!(region_route_meta_key(&lkey), rkey);
        }

        let tbls = vec![
            (vec![], true),
            (vec![0xFF], false),
            (vec![DATA_PREFIX, 1], false),
            (vec![META1_PREFIX - 1, 1], false),
            (vec![META2_PREFIX + 1, 1], false),
            (vec![META1_PREFIX, 1], true),
            (vec![META2_PREFIX, 1], true),
            (vec![META1_PREFIX, 0xFF, 1], false),
            (vec![META2_PREFIX, 0xFF, 1], false),
        ];

        for (key, ok) in tbls {
            match validate_region_route_meta_key(&key) {
                Ok(_) => assert!(ok),
                Err(_) => assert!(!ok),
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate clap;
extern crate env_logger;
#[macro_use]
extern crate log;
extern crate protobuf;
extern crate record_query;

use std::io;
use std::path;

use record_query as rq;

const ABOUT: &'static str = r#"
A tool for manipulating data records.  Similar in spirit to awk(1),
but on steroids.  Inspired by jq(1), but supports more record formats
and operations.

Records are read from stdin, processed, and written to stdout.  The
tool accepts a query in the custom rq query language as its main
command-line arguments.

Flags can be used to control the input and output formats of the tool.
By default, the input and output format is JSON.

See 'man rq' for in-depth documentation."#;

const AUTHOR: &'static str = "David Flemström <david.flemstrom@gmail.com>";

const INPUT_FORMAT_GROUP: &'static str = "input-format";
const OUTPUT_FORMAT_GROUP: &'static str = "output-format";

const PROTOBUF_CMD: &'static str = "protobuf";
const PROTOBUF_ADD_CMD: &'static str = "add";
const PROTOBUF_ADD_INPUT_ARG: &'static str = "protobuf-add-input";

const INPUT_JSON_ARG: &'static str = "input-json";
const OUTPUT_JSON_ARG: &'static str = "output-json";
const INPUT_PROTOBUF_ARG: &'static str = "input-protobuf";
const OUTPUT_PROTOBUF_ARG: &'static str = "output-protobuf";

const QUERY_ARG: &'static str = "query";

fn main() {
    use std::io::Read;

    env_logger::init().unwrap();

    let paths = rq::config::Paths::new().unwrap();
    let matches = match_args();

    if let Some(matches) = matches.subcommand_matches(PROTOBUF_CMD) {
        if let Some(matches) = matches.subcommand_matches(PROTOBUF_ADD_CMD) {
            let input = matches.value_of(PROTOBUF_ADD_INPUT_ARG).unwrap();
            rq::proto_index::add_file(&paths, path::Path::new(input)).unwrap();
        }
    } else {

        let query = rq::query::Query::parse(matches.value_of(QUERY_ARG).unwrap());

        let stdin = io::stdin();
        let mut input = stdin.lock();

        if matches.is_present(INPUT_PROTOBUF_ARG) {
            let name = matches.value_of(INPUT_PROTOBUF_ARG).unwrap();
            debug!("Input is protobuf with argument {}", name);

            let descriptors_proto = rq::proto_index::compile_descriptor_set(&paths).unwrap();
            let descriptors =
                rq::value::protobuf::descriptor::Descriptors::from_proto(&descriptors_proto);
            let stream = protobuf::CodedInputStream::new(&mut input);
            let values = rq::value::protobuf::ProtobufValues::new(descriptors,
                                                                  name.to_owned(),
                                                                  stream);
            run(values, query);
        } else {
            run(rq::value::json::JsonValues::new(input.bytes()), query);
        }
    }
}

#[cfg_attr(rustfmt, rustfmt_skip)]
fn match_args<'a>() -> clap::ArgMatches<'a> {
    use clap::AppSettings;
    use clap::Arg;
    use clap::ArgGroup;
    use clap::SubCommand;

    clap::App::new("rq - Record query")
        .version(env!("CARGO_PKG_VERSION"))
        .author(AUTHOR)
        .about(ABOUT)
        .setting(AppSettings::SubcommandsNegateReqs)
        .group(ArgGroup::with_name(INPUT_FORMAT_GROUP))
        .group(ArgGroup::with_name(OUTPUT_FORMAT_GROUP))
        .arg(Arg::with_name(INPUT_JSON_ARG)
             .group(INPUT_FORMAT_GROUP)
             .short("j")
             .long("input-json")
             .help("Input is white-space separated JSON values."))
        .arg(Arg::with_name(OUTPUT_JSON_ARG)
             .group(OUTPUT_FORMAT_GROUP)
             .short("J")
             .long("output-json")
             .help("Output should be formatted as JSON values."))
        .arg(Arg::with_name(INPUT_PROTOBUF_ARG)
             .group(INPUT_FORMAT_GROUP)
             .short("p")
             .long("input-protobuf")
             .takes_value(true)
             .value_name(".package.MessageType")
             .next_line_help(true)
             .help("Input is a single protocol buffer object.  The argument refers to the fully \
                    qualified name of the message type (including the leading '.')"))
        .arg(Arg::with_name(OUTPUT_PROTOBUF_ARG)
             .group(OUTPUT_FORMAT_GROUP)
             .short("P")
             .long("output-protobuf")
             .takes_value(true)
             .value_name(".package.MessageType")
             .next_line_help(true)
             .help("Output should be formatted as protocol buffer objects.  The argument refers \
                    to the fully qualified name of the message type (including the leading '.'), \
                    but if it is omitted and -p was used, the input schema is used instead."))
        .arg(Arg::with_name(QUERY_ARG)
             .required(true)
             .help("The query to apply."))
        .subcommand(SubCommand::with_name(PROTOBUF_CMD)
                    .about("Control protobuf configuration and data")
                    .author(AUTHOR)
                    .subcommand(SubCommand::with_name(PROTOBUF_ADD_CMD)
                                .about("Add a schema file to the rq registry")
                                .author(AUTHOR)
                                .arg(Arg::with_name(PROTOBUF_ADD_INPUT_ARG)
                                     .required(true)
                                     .value_name("schema")
                                     .help("The path to a .proto file to add to the rq registry"))))
        .get_matches()
}

fn run<Iter>(input: Iter, query: rq::query::Query)
    where Iter: Iterator<Item = rq::error::Result<rq::value::Value>>
{
    use std::io::Write;
    let mut stdout = io::stdout();
    let context = rq::query::Context::new();

    debug!("Starting input consumption");

    for value in input {
        debug!("Consuming an input value");
        query.evaluate(&context, value.unwrap()).to_json(&mut stdout).unwrap();
        stdout.write(&[10]).unwrap();
        stdout.flush().unwrap();
    }
}
<commit_msg>Customize log output format<commit_after>extern crate clap;
extern crate env_logger;
#[macro_use]
extern crate log;
extern crate protobuf;
extern crate record_query;

use std::env;
use std::io;
use std::path;

use record_query as rq;

const ABOUT: &'static str = r#"
A tool for manipulating data records.  Similar in spirit to awk(1),
but on steroids.  Inspired by jq(1), but supports more record formats
and operations.

Records are read from stdin, processed, and written to stdout.  The
tool accepts a query in the custom rq query language as its main
command-line arguments.

Flags can be used to control the input and output formats of the tool.
By default, the input and output format is JSON.

See 'man rq' for in-depth documentation."#;

const AUTHOR: &'static str = "David Flemström <david.flemstrom@gmail.com>";

const INPUT_FORMAT_GROUP: &'static str = "input-format";
const OUTPUT_FORMAT_GROUP: &'static str = "output-format";

const PROTOBUF_CMD: &'static str = "protobuf";
const PROTOBUF_ADD_CMD: &'static str = "add";
const PROTOBUF_ADD_INPUT_ARG: &'static str = "protobuf-add-input";

const INPUT_JSON_ARG: &'static str = "input-json";
const OUTPUT_JSON_ARG: &'static str = "output-json";
const INPUT_PROTOBUF_ARG: &'static str = "input-protobuf";
const OUTPUT_PROTOBUF_ARG: &'static str = "output-protobuf";

const QUERY_ARG: &'static str = "query";

fn main() {
    use std::io::Read;

    setup_log();

    let paths = rq::config::Paths::new().unwrap();
    let matches = match_args();

    if let Some(matches) = matches.subcommand_matches(PROTOBUF_CMD) {
        if let Some(matches) = matches.subcommand_matches(PROTOBUF_ADD_CMD) {
            let input = matches.value_of(PROTOBUF_ADD_INPUT_ARG).unwrap();
            rq::proto_index::add_file(&paths, path::Path::new(input)).unwrap();
        }
    } else {

        let query = rq::query::Query::parse(matches.value_of(QUERY_ARG).unwrap());

        let stdin = io::stdin();
        let mut input = stdin.lock();

        if matches.is_present(INPUT_PROTOBUF_ARG) {
            let name = matches.value_of(INPUT_PROTOBUF_ARG).unwrap();
            debug!("Input is protobuf with argument {}", name);

            let descriptors_proto = rq::proto_index::compile_descriptor_set(&paths).unwrap();
            let descriptors =
                rq::value::protobuf::descriptor::Descriptors::from_proto(&descriptors_proto);
            let stream = protobuf::CodedInputStream::new(&mut input);
            let values = rq::value::protobuf::ProtobufValues::new(descriptors,
                                                                  name.to_owned(),
                                                                  stream);
            run(values, query);
        } else {
            run(rq::value::json::JsonValues::new(input.bytes()), query);
        }
    }
}

fn setup_log() {
    let format = |record: &log::LogRecord| {
        format!("{} {}", record.level(), record.args())
    };

    let mut builder = env_logger::LogBuilder::new();

    builder.format(format).filter(None, log::LogLevelFilter::Info);

    if let Ok(spec) = env::var("RUST_LOG") {
        builder.parse(&spec);
    }

    builder.init().unwrap();
}

#[cfg_attr(rustfmt, rustfmt_skip)]
fn match_args<'a>() -> clap::ArgMatches<'a> {
    use clap::AppSettings;
    use clap::Arg;
    use clap::ArgGroup;
    use clap::SubCommand;

    clap::App::new("rq - Record query")
        .version(env!("CARGO_PKG_VERSION"))
        .author(AUTHOR)
        .about(ABOUT)
        .setting(AppSettings::SubcommandsNegateReqs)
        .group(ArgGroup::with_name(INPUT_FORMAT_GROUP))
        .group(ArgGroup::with_name(OUTPUT_FORMAT_GROUP))
        .arg(Arg::with_name(INPUT_JSON_ARG)
             .group(INPUT_FORMAT_GROUP)
             .short("j")
             .long("input-json")
             .help("Input is white-space separated JSON values."))
        .arg(Arg::with_name(OUTPUT_JSON_ARG)
             .group(OUTPUT_FORMAT_GROUP)
             .short("J")
             .long("output-json")
             .help("Output should be formatted as JSON values."))
        .arg(Arg::with_name(INPUT_PROTOBUF_ARG)
             .group(INPUT_FORMAT_GROUP)
             .short("p")
             .long("input-protobuf")
             .takes_value(true)
             .value_name(".package.MessageType")
             .next_line_help(true)
             .help("Input is a single protocol buffer object.  The argument refers to the fully \
                    qualified name of the message type (including the leading '.')"))
        .arg(Arg::with_name(OUTPUT_PROTOBUF_ARG)
             .group(OUTPUT_FORMAT_GROUP)
             .short("P")
             .long("output-protobuf")
             .takes_value(true)
             .value_name(".package.MessageType")
             .next_line_help(true)
             .help("Output should be formatted as protocol buffer objects.  The argument refers \
                    to the fully qualified name of the message type (including the leading '.'), \
                    but if it is omitted and -p was used, the input schema is used instead."))
        .arg(Arg::with_name(QUERY_ARG)
             .required(true)
             .help("The query to apply."))
        .subcommand(SubCommand::with_name(PROTOBUF_CMD)
                    .about("Control protobuf configuration and data")
                    .author(AUTHOR)
                    .subcommand(SubCommand::with_name(PROTOBUF_ADD_CMD)
                                .about("Add a schema file to the rq registry")
                                .author(AUTHOR)
                                .arg(Arg::with_name(PROTOBUF_ADD_INPUT_ARG)
                                     .required(true)
                                     .value_name("schema")
                                     .help("The path to a .proto file to add to the rq registry"))))
        .get_matches()
}

fn run<Iter>(input: Iter, query: rq::query::Query)
    where Iter: Iterator<Item = rq::error::Result<rq::value::Value>>
{
    use std::io::Write;
    let mut stdout = io::stdout();
    let context = rq::query::Context::new();

    debug!("Starting input consumption");

    for value in input {
        debug!("Consuming an input value");
        query.evaluate(&context, value.unwrap()).to_json(&mut stdout).unwrap();
        stdout.write(&[10]).unwrap();
        stdout.flush().unwrap();
    }
}
<|endoftext|>


<commit_before>use std::rc::{Rc};
use std::cell::{RefCell};
use std::collections::HashMap;

//is same identity
fn is_same<T>(lhs: &T, rhs: &T) -> bool {
    lhs as *const T == rhs as *const T
}

//the code below is horrible
//borrow doesn't return T, it returns Ref<T>
//we need to dereference it to get to the T inside
//is_same takes borrow so reapply the ampersand
fn is_same_subscriber<T: Subscriber>(lhs: Rc<RefCell<T>>, rhs: Rc<RefCell<T>>) -> bool {
    let lhs = lhs.clone();
    let rhs = rhs.clone();
    let res = is_same(&*lhs.borrow(), &*rhs.borrow()); //needed to live long enough
    res
}

pub trait Subscriber {
    fn new_message(&mut self, bytes: &[u8]);
}

pub struct Broker<T: Subscriber> {
    tree: Node<T>,
    use_cache: bool,
    cache: HashMap<String, Vec<Rc<RefCell<T>>>>,
}

struct Node<T: Subscriber> {
    children: HashMap<String, Node<T>>,
    leaves: Vec<Subscription<T>>,
}

struct Subscription<T: Subscriber> {
    subscriber: Rc<RefCell<T>>,
    topic: String,
}

impl<T: Subscriber> Subscription<T> {
    fn new(subscriber: Rc<RefCell<T>>, topic: &str) -> Self {
        Subscription { subscriber: subscriber.clone(), topic: topic.to_string() }
    }
}

impl<T: Subscriber> Node<T> {
    fn new() -> Self {
        Node { children: HashMap::new(), leaves: vec![] }
    }

    fn add_subscription(&mut self, subscription: Subscription<T>) {
        self.leaves.push(subscription);
    }
}

impl<T: Subscriber> Broker<T> {
    pub fn new() -> Self {
        Broker { tree: Node::new(), use_cache: false, cache: HashMap::new() }
    }

    pub fn subscribe(&mut self, subscriber: Rc<RefCell<T>>, topic: &str) {
        self.invalidate_cache();
        let sub_parts : Vec<&str> = topic.split("/").collect();
        Self::ensure_node_exists(&sub_parts, &mut self.tree);
        Self::add_subscription_to_node(&mut self.tree, subscriber.clone(), &sub_parts, topic);
    }

    pub fn unsubscribe_all(&mut self, subscriber: Rc<RefCell<T>>) {
        self.invalidate_cache();
        Self::unsubscribe_impl(&mut self.tree, subscriber.clone(), &[], false);
    }

    pub fn unsubscribe(&mut self, subscriber: Rc<RefCell<T>>, topics: &[&str]) {
        self.invalidate_cache();
        Self::unsubscribe_impl(&mut self.tree, subscriber.clone(), topics, true);
    }

    pub fn publish(&self, topic: &str, payload: &[u8]) {
        if self.use_cache {
            if let Some(subscribers) = self.cache.get(topic) {
                for subscriber in subscribers {
                    subscriber.borrow_mut().new_message(payload);
                }
                return;
            }
        }

        let pub_parts : Vec<&str> = topic.split("/").collect();
        Self::publish_impl(&self.tree, &pub_parts, &payload);
    }

    fn ensure_node_exists(sub_parts: &[&str], node: &mut Node<T>) {
        if sub_parts.len() == 0 {
            return;
        }

        let part = &sub_parts[0][..];
        if !node.children.contains_key(part) {
            node.children.insert(sub_parts[0].to_string(), Node::new());
        }

        Self::ensure_node_exists(&sub_parts[1..], node.children.get_mut(part)
                                 .expect(&format!("Could not get node at {}", &part)));
    }

    fn add_subscription_to_node(tree: &mut Node<T>, subscriber: Rc<RefCell<T>>, sub_parts: &[&str], topic: &str) {
        if sub_parts.len() < 1 {
            panic!("oops");
        }

        let part = &sub_parts[0][..];
        let node = tree.children.get_mut(part)
            .expect(&format!("Could not get node at {}", &part));
        let sub_parts = &sub_parts[1..];

        if sub_parts.len() == 0 {
            node.add_subscription(Subscription::new(subscriber.clone(), topic));
        } else {
            Self::add_subscription_to_node(node, subscriber, sub_parts, topic);
        }
    }

    fn publish_impl(tree: &Node<T>, pub_parts: &[&str], payload: &[u8]) {
        if pub_parts.len() < 1 {
            return;
        }

        let part = &pub_parts[0][..];
        let pub_parts = &pub_parts[1..];

        for part in vec![part, "#", "+"] {

            let node = tree.children.get(part);

            match node {
                None => {
                    continue; //didn't find a subscriber
                },
                Some(node) => {
                    //so that "finance/#" matches "finance"
                    if pub_parts.len() == 0 && node.children.contains_key("#") {
                        Self::publish_node(node.children.get("#")
                                           .expect(&format!("Could not get node at {}", &part)), payload);
                    }

                    if pub_parts.len() == 0 || part == "#" {
                        Self::publish_node(&node, payload);
                    }

                    Self::publish_impl(&node, pub_parts, payload);
                }
            }
        }
    }

    fn publish_node(node: &Node<T>, payload: &[u8]) {
        for subscription in &node.leaves {
            let subscriber = subscription.subscriber.clone();
            subscriber.borrow_mut().new_message(payload);
        }
    }

    fn unsubscribe_impl(tree: &mut Node<T>, subscriber: Rc<RefCell<T>>, topics: &[&str], check_topics: bool) {
        tree.leaves.retain(|s| {
            let is_same_subscriber = is_same_subscriber(s.subscriber.clone(), subscriber.clone());
            //I have no idea why t below is &&&str, I added a tripe deref cos the compiler told me to
            let is_same_topic = !check_topics || topics.into_iter().find(|t| ***t == s.topic).is_some();
            !is_same_subscriber || !is_same_topic
        });

        if tree.children.len() == 0 {
            return;
        }

        for (_, node) in tree.children.iter_mut() {
            Self::unsubscribe_impl(node, subscriber.clone(), topics, check_topics);
        }
    }

    fn invalidate_cache(&mut self) {
        if self.use_cache {
            self.cache = HashMap::new();
        }
    }
}

#[cfg(test)]
struct TestSubscriber {
    msgs: Vec<Vec<u8>>,
}

#[cfg(test)]
impl TestSubscriber {
    fn new() -> Self {
        TestSubscriber{msgs: vec![]}
    }
}

#[cfg(test)]
impl Subscriber for TestSubscriber {
    fn new_message(&mut self, bytes: &[u8]) {
        self.msgs.push(bytes.to_vec());
    }
}

#[test]
fn test_subscribe() {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();
    broker.publish("topics/foo", &[0, 1, 2]);
    assert_eq!(subscriber.borrow().msgs.len(), 0);

    broker.subscribe(subscriber.clone(), "topics/foo");
    broker.publish("topics/foo", &[0, 1, 9]); //should get this
    broker.publish("topics/bar", &[2, 4, 6]); //shouldn't get this
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);

    broker.subscribe(subscriber.clone(), "topics/bar");
    broker.publish("topics/foo", &[1, 3, 5, 7]);
    broker.publish("topics/bar", &[2, 4]);
    assert_eq!(subscriber.borrow().msgs.len(), 3);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
    assert_eq!(subscriber.borrow().msgs[1], &[1, 3, 5, 7]);
    assert_eq!(subscriber.borrow().msgs[2], &[2, 4]);
}

#[test]
fn test_unsubscribe_all() {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();

    broker.subscribe(subscriber.clone(), "topics/foo");
    broker.publish("topics/foo", &[0, 1, 9]); //should get this
    broker.publish("topics/bar", &[2, 4, 6]); //shouldn't get this
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);

    broker.unsubscribe_all(subscriber.clone());
    broker.publish("topics/foo", &[0, 1, 9]);
    broker.publish("topics/bar", &[2, 4]);
    broker.publish("topics/baz", &[2, 4, 7, 11]);

    //shouldn't have changed
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
}

#[test]
fn test_unsubscribe_one() {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();

    broker.subscribe(subscriber.clone(), "topics/foo");
    broker.subscribe(subscriber.clone(), "topics/bar");
    broker.publish("topics/foo", &[0, 1, 9]); //should get this
    broker.publish("topics/bar", &[2, 4]); //should get this
    broker.publish("topics/baz", &[2, 4, 7, 11]); //shouldn't get this
    assert_eq!(subscriber.borrow().msgs.len(), 2);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
    assert_eq!(subscriber.borrow().msgs[1], &[2, 4]);

    broker.unsubscribe(subscriber.clone(), &["topics/foo"]);
    broker.publish("topics/foo", &[0, 1, 9]); //shouldn't get this
    broker.publish("topics/bar", &[2, 4]); //should get this
    broker.publish("topics/baz", &[2, 4, 7, 11]); //shouldn't get this

    assert_eq!(subscriber.borrow().msgs.len(), 3);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
    assert_eq!(subscriber.borrow().msgs[1], &[2, 4]);
    assert_eq!(subscriber.borrow().msgs[2], &[2, 4]);
}

#[cfg(test)]
fn test_matches(pub_topic: &str, sub_topic: &str) -> bool {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();

    broker.subscribe(subscriber.clone(), sub_topic);
    broker.publish(pub_topic, &[0, 1, 2]);
    let subscriber = subscriber.borrow();
    subscriber.msgs.len() == 1
}

#[test]
fn test_wildcards() {
    assert_eq!(test_matches("foo/bar/baz", "foo/bar/baz"), true);
    assert_eq!(test_matches("foo/bar", "foo/+"), true);
    assert_eq!(test_matches("foo/baz", "foo/+"), true);
    assert_eq!(test_matches("foo/bar/baz", "foo/+"), false);
    assert_eq!(test_matches("foo/bar", "foo/#"), true);
    assert_eq!(test_matches("foo/bar/baz", "foo/#"), true);
    assert_eq!(test_matches("foo/bar/baz/boo", "foo/#"), true);
    assert_eq!(test_matches("foo/bla/bar/baz/boo/bogadog", "foo/+/bar/baz/#"), true);
    assert_eq!(test_matches("finance", "finance/#"), true);
    assert_eq!(test_matches("finance", "finance#"), false);
    assert_eq!(test_matches("finance", "#"), true);
    assert_eq!(test_matches("finance/stock", "#"), true);
    assert_eq!(test_matches("finance/stock", "finance/stock/ibm"), false);
    assert_eq!(test_matches("topics/foo/bar", "topics/foo/#"), true);
    assert_eq!(test_matches("topics/bar/baz/boo", "topics/foo/#"), false);
}

#[test]
fn test_subscribe_wildcards() {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc1 = Rc::new(RefCell::new(TestSubscriber::new()));
    let sub_rc2 = Rc::new(RefCell::new(TestSubscriber::new()));
    let sub_rc3 = Rc::new(RefCell::new(TestSubscriber::new()));
    let sub_rc4 = Rc::new(RefCell::new(TestSubscriber::new()));

    let subscriber1 = sub_rc1.clone();
    let subscriber2 = sub_rc2.clone();
    let subscriber3 = sub_rc3.clone();
    let subscriber4 = sub_rc4.clone();

    broker.subscribe(subscriber1.clone(), "topics/foo/+");
    broker.publish("topics/foo/bar", &[3]);
    broker.publish("topics/bar/baz/boo", &[4]); //shouldn't get this one
    assert_eq!(subscriber1.borrow().msgs, vec![&[3]]);

    broker.subscribe(subscriber2.clone(), "topics/foo/#");
    broker.publish("topics/foo/bar", &[3]);
    broker.publish("topics/bar/baz/boo", &[4]); //shouldn't get this one
    assert_eq!(subscriber1.borrow().msgs, vec![&[3], &[3]]);
    assert_eq!(subscriber2.borrow().msgs, vec![&[3]]);

    broker.subscribe(subscriber3.clone(), "topics/+/bar");
    broker.subscribe(subscriber4.clone(), "topics/#");

    broker.publish("topics/foo/bar", &[3]);
    broker.publish("topics/bar/baz/boo", &[4]);
    broker.publish("topics/boo/bar/zoo", &[5]);
    broker.publish("topics/foo/bar/zoo", &[6]);
    broker.publish("topics/bbobobobo/bar", &[7]);

    assert_eq!(subscriber1.borrow().msgs, vec![&[3], &[3], &[3]]);
    assert_eq!(subscriber2.borrow().msgs, vec![&[3], &[3], &[6]]);
    assert_eq!(subscriber3.borrow().msgs, vec![&[3], &[7]]);
    assert_eq!(subscriber4.borrow().msgs, vec![&[3], &[4], &[5], &[6], &[7]]);
}
<commit_msg>Got it to compile<commit_after>use std::rc::{Rc};
use std::cell::{RefCell};
use std::collections::HashMap;

//is same identity
fn is_same<T>(lhs: &T, rhs: &T) -> bool {
    lhs as *const T == rhs as *const T
}

//the code below is horrible
//borrow doesn't return T, it returns Ref<T>
//we need to dereference it to get to the T inside
//is_same takes borrow so reapply the ampersand
fn is_same_subscriber<T: Subscriber>(lhs: Rc<RefCell<T>>, rhs: Rc<RefCell<T>>) -> bool {
    let lhs = lhs.clone();
    let rhs = rhs.clone();
    let res = is_same(&*lhs.borrow(), &*rhs.borrow()); //needed to live long enough
    res
}

pub trait Subscriber {
    fn new_message(&mut self, bytes: &[u8]);
}

pub struct Broker<T: Subscriber> {
    tree: Node<T>,
    use_cache: bool,
    cache: HashMap<String, Vec<Rc<RefCell<T>>>>,
}

struct Node<T: Subscriber> {
    children: HashMap<String, Node<T>>,
    leaves: Vec<Subscription<T>>,
}

struct Subscription<T: Subscriber> {
    subscriber: Rc<RefCell<T>>,
    topic: String,
}

impl<T: Subscriber> Subscription<T> {
    fn new(subscriber: Rc<RefCell<T>>, topic: &str) -> Self {
        Subscription { subscriber: subscriber.clone(), topic: topic.to_string() }
    }
}

impl<T: Subscriber> Node<T> {
    fn new() -> Self {
        Node { children: HashMap::new(), leaves: vec![] }
    }

    fn add_subscription(&mut self, subscription: Subscription<T>) {
        self.leaves.push(subscription);
    }
}

impl<T: Subscriber> Broker<T> {
    pub fn new() -> Self {
        Broker { tree: Node::new(), use_cache: false, cache: HashMap::new() }
    }

    pub fn subscribe(&mut self, subscriber: Rc<RefCell<T>>, topic: &str) {
        self.invalidate_cache();
        let sub_parts : Vec<&str> = topic.split("/").collect();
        Self::ensure_node_exists(&sub_parts, &mut self.tree);
        Self::add_subscription_to_node(&mut self.tree, subscriber.clone(), &sub_parts, topic);
    }

    pub fn unsubscribe_all(&mut self, subscriber: Rc<RefCell<T>>) {
        self.invalidate_cache();
        Self::unsubscribe_impl(&mut self.tree, subscriber.clone(), &[], false);
    }

    pub fn unsubscribe(&mut self, subscriber: Rc<RefCell<T>>, topics: &[&str]) {
        self.invalidate_cache();
        Self::unsubscribe_impl(&mut self.tree, subscriber.clone(), topics, true);
    }

    pub fn publish(&mut self, topic: &str, payload: &[u8]) {
        if self.use_cache {
            if let Some(subscribers) = self.cache.get(topic) {
                for subscriber in subscribers {
                    subscriber.borrow_mut().new_message(payload);
                }
                return;
            }
        }

        let pub_parts : Vec<&str> = topic.split("/").collect();
        Self::publish_impl(&self.tree, &pub_parts, &payload, topic, self.use_cache, &mut self.cache);
    }

    fn ensure_node_exists(sub_parts: &[&str], node: &mut Node<T>) {
        if sub_parts.len() == 0 {
            return;
        }

        let part = &sub_parts[0][..];
        if !node.children.contains_key(part) {
            node.children.insert(sub_parts[0].to_string(), Node::new());
        }

        Self::ensure_node_exists(&sub_parts[1..], node.children.get_mut(part)
                                 .expect(&format!("Could not get node at {}", &part)));
    }

    fn add_subscription_to_node(tree: &mut Node<T>, subscriber: Rc<RefCell<T>>, sub_parts: &[&str], topic: &str) {
        if sub_parts.len() < 1 {
            panic!("oops");
        }

        let part = &sub_parts[0][..];
        let node = tree.children.get_mut(part)
            .expect(&format!("Could not get node at {}", &part));
        let sub_parts = &sub_parts[1..];

        if sub_parts.len() == 0 {
            node.add_subscription(Subscription::new(subscriber.clone(), topic));
        } else {
            Self::add_subscription_to_node(node, subscriber, sub_parts, topic);
        }
    }

    fn publish_impl(tree: &Node<T>, pub_parts: &[&str], payload: &[u8], topic: &str, use_cache: bool, cache: &mut HashMap<String, Vec<Rc<RefCell<T>>>>) {
        if pub_parts.len() < 1 {
            return;
        }

        let part = &pub_parts[0][..];
        let pub_parts = &pub_parts[1..];

        for part in vec![part, "#", "+"] {

            let node = tree.children.get(part);

            match node {
                None => {
                    continue; //didn't find a subscriber
                },
                Some(node) => {
                    //so that "finance/#" matches "finance"
                    if pub_parts.len() == 0 && node.children.contains_key("#") {
                        Self::publish_node(node.children.get("#")
                                           .expect(&format!("Could not get node at {}", &part)),
                                           payload, topic, use_cache, cache);
                    }

                    if pub_parts.len() == 0 || part == "#" {
                        Self::publish_node(&node, payload, topic, use_cache, cache);
                    }

                    Self::publish_impl(&node, pub_parts, payload, topic, use_cache, cache);
                }
            }
        }
    }

    fn publish_node(node: &Node<T>, payload: &[u8], topic: &str, use_cache: bool, cache: &mut HashMap<String, Vec<Rc<RefCell<T>>>>) {
        for subscription in &node.leaves {
            let subscriber = subscription.subscriber.clone();
            subscriber.borrow_mut().new_message(payload);
            if use_cache {
                if !cache.contains_key(topic) {
                    cache.insert(topic.to_string(), vec![]);
                }
                match cache.get_mut(topic) {
                    None => {
                        panic!("Impossible to not have key")
                    }
                    Some(subscribers) => {
                        subscribers.push(subscriber.clone());
                    }
                }
            }
        }
    }

    fn unsubscribe_impl(tree: &mut Node<T>, subscriber: Rc<RefCell<T>>, topics: &[&str], check_topics: bool) {
        tree.leaves.retain(|s| {
            let is_same_subscriber = is_same_subscriber(s.subscriber.clone(), subscriber.clone());
            //I have no idea why t below is &&&str, I added a tripe deref cos the compiler told me to
            let is_same_topic = !check_topics || topics.into_iter().find(|t| ***t == s.topic).is_some();
            !is_same_subscriber || !is_same_topic
        });

        if tree.children.len() == 0 {
            return;
        }

        for (_, node) in tree.children.iter_mut() {
            Self::unsubscribe_impl(node, subscriber.clone(), topics, check_topics);
        }
    }

    fn invalidate_cache(&mut self) {
        if self.use_cache {
            self.cache = HashMap::new();
        }
    }
}

#[cfg(test)]
struct TestSubscriber {
    msgs: Vec<Vec<u8>>,
}

#[cfg(test)]
impl TestSubscriber {
    fn new() -> Self {
        TestSubscriber{msgs: vec![]}
    }
}

#[cfg(test)]
impl Subscriber for TestSubscriber {
    fn new_message(&mut self, bytes: &[u8]) {
        self.msgs.push(bytes.to_vec());
    }
}

#[test]
fn test_subscribe() {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();
    broker.publish("topics/foo", &[0, 1, 2]);
    assert_eq!(subscriber.borrow().msgs.len(), 0);

    broker.subscribe(subscriber.clone(), "topics/foo");
    broker.publish("topics/foo", &[0, 1, 9]); //should get this
    broker.publish("topics/bar", &[2, 4, 6]); //shouldn't get this
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);

    broker.subscribe(subscriber.clone(), "topics/bar");
    broker.publish("topics/foo", &[1, 3, 5, 7]);
    broker.publish("topics/bar", &[2, 4]);
    assert_eq!(subscriber.borrow().msgs.len(), 3);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
    assert_eq!(subscriber.borrow().msgs[1], &[1, 3, 5, 7]);
    assert_eq!(subscriber.borrow().msgs[2], &[2, 4]);
}

#[test]
fn test_unsubscribe_all() {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();

    broker.subscribe(subscriber.clone(), "topics/foo");
    broker.publish("topics/foo", &[0, 1, 9]); //should get this
    broker.publish("topics/bar", &[2, 4, 6]); //shouldn't get this
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);

    broker.unsubscribe_all(subscriber.clone());
    broker.publish("topics/foo", &[0, 1, 9]);
    broker.publish("topics/bar", &[2, 4]);
    broker.publish("topics/baz", &[2, 4, 7, 11]);

    //shouldn't have changed
    assert_eq!(subscriber.borrow().msgs.len(), 1);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
}

#[test]
fn test_unsubscribe_one() {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();

    broker.subscribe(subscriber.clone(), "topics/foo");
    broker.subscribe(subscriber.clone(), "topics/bar");
    broker.publish("topics/foo", &[0, 1, 9]); //should get this
    broker.publish("topics/bar", &[2, 4]); //should get this
    broker.publish("topics/baz", &[2, 4, 7, 11]); //shouldn't get this
    assert_eq!(subscriber.borrow().msgs.len(), 2);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
    assert_eq!(subscriber.borrow().msgs[1], &[2, 4]);

    broker.unsubscribe(subscriber.clone(), &["topics/foo"]);
    broker.publish("topics/foo", &[0, 1, 9]); //shouldn't get this
    broker.publish("topics/bar", &[2, 4]); //should get this
    broker.publish("topics/baz", &[2, 4, 7, 11]); //shouldn't get this

    assert_eq!(subscriber.borrow().msgs.len(), 3);
    assert_eq!(subscriber.borrow().msgs[0], &[0, 1, 9]);
    assert_eq!(subscriber.borrow().msgs[1], &[2, 4]);
    assert_eq!(subscriber.borrow().msgs[2], &[2, 4]);
}

#[cfg(test)]
fn test_matches(pub_topic: &str, sub_topic: &str) -> bool {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc = Rc::new(RefCell::new(TestSubscriber::new()));
    let subscriber = sub_rc.clone();

    broker.subscribe(subscriber.clone(), sub_topic);
    broker.publish(pub_topic, &[0, 1, 2]);
    let subscriber = subscriber.borrow();
    subscriber.msgs.len() == 1
}

#[test]
fn test_wildcards() {
    assert_eq!(test_matches("foo/bar/baz", "foo/bar/baz"), true);
    assert_eq!(test_matches("foo/bar", "foo/+"), true);
    assert_eq!(test_matches("foo/baz", "foo/+"), true);
    assert_eq!(test_matches("foo/bar/baz", "foo/+"), false);
    assert_eq!(test_matches("foo/bar", "foo/#"), true);
    assert_eq!(test_matches("foo/bar/baz", "foo/#"), true);
    assert_eq!(test_matches("foo/bar/baz/boo", "foo/#"), true);
    assert_eq!(test_matches("foo/bla/bar/baz/boo/bogadog", "foo/+/bar/baz/#"), true);
    assert_eq!(test_matches("finance", "finance/#"), true);
    assert_eq!(test_matches("finance", "finance#"), false);
    assert_eq!(test_matches("finance", "#"), true);
    assert_eq!(test_matches("finance/stock", "#"), true);
    assert_eq!(test_matches("finance/stock", "finance/stock/ibm"), false);
    assert_eq!(test_matches("topics/foo/bar", "topics/foo/#"), true);
    assert_eq!(test_matches("topics/bar/baz/boo", "topics/foo/#"), false);
}

#[test]
fn test_subscribe_wildcards() {
    let mut broker = Broker::<TestSubscriber>::new();
    let sub_rc1 = Rc::new(RefCell::new(TestSubscriber::new()));
    let sub_rc2 = Rc::new(RefCell::new(TestSubscriber::new()));
    let sub_rc3 = Rc::new(RefCell::new(TestSubscriber::new()));
    let sub_rc4 = Rc::new(RefCell::new(TestSubscriber::new()));

    let subscriber1 = sub_rc1.clone();
    let subscriber2 = sub_rc2.clone();
    let subscriber3 = sub_rc3.clone();
    let subscriber4 = sub_rc4.clone();

    broker.subscribe(subscriber1.clone(), "topics/foo/+");
    broker.publish("topics/foo/bar", &[3]);
    broker.publish("topics/bar/baz/boo", &[4]); //shouldn't get this one
    assert_eq!(subscriber1.borrow().msgs, vec![&[3]]);

    broker.subscribe(subscriber2.clone(), "topics/foo/#");
    broker.publish("topics/foo/bar", &[3]);
    broker.publish("topics/bar/baz/boo", &[4]); //shouldn't get this one
    assert_eq!(subscriber1.borrow().msgs, vec![&[3], &[3]]);
    assert_eq!(subscriber2.borrow().msgs, vec![&[3]]);

    broker.subscribe(subscriber3.clone(), "topics/+/bar");
    broker.subscribe(subscriber4.clone(), "topics/#");

    broker.publish("topics/foo/bar", &[3]);
    broker.publish("topics/bar/baz/boo", &[4]);
    broker.publish("topics/boo/bar/zoo", &[5]);
    broker.publish("topics/foo/bar/zoo", &[6]);
    broker.publish("topics/bbobobobo/bar", &[7]);

    assert_eq!(subscriber1.borrow().msgs, vec![&[3], &[3], &[3]]);
    assert_eq!(subscriber2.borrow().msgs, vec![&[3], &[3], &[6]]);
    assert_eq!(subscriber3.borrow().msgs, vec![&[3], &[7]]);
    assert_eq!(subscriber4.borrow().msgs, vec![&[3], &[4], &[5], &[6], &[7]]);
}
<|endoftext|>


<commit_before>//! Selection sort algorithm.
//!
//! The `selection` module contains the simple sorting algorithm "Selection Sort".
//!
//! Source: https://en.wikipedia.org/wiki/Selection_sort

use std::fmt::Debug;

/// Simple sort: selection sort.
///
/// # Details
///
/// Selection sort is one of the simplest sorting algorithm. The list to sort is split into two
/// sections; the first with the sorted element (starting empty) and the second with the remaining
/// element (starting full). At every iteration, the smallest element in the remaining list is
/// found and placed at the end of the sorted list.
///
/// This function takes an immutable reference vector of any type and returns a vector of `usize`
/// of the same length containing the indices of the initial vector sorted.
///
/// # Scaling
///
/// Selection sort in scale as O(N^2) since for all elements to sort, the algorithm will compare it
/// with every (remaining) elements.
///
/// Insertion sort is still useful as it is quite simple.
///
/// # Optimizations
///
/// None
///
/// # Notes
///
/// The type T of the vector elements to sort _must_ implement the `PartialOrd` trait so the
/// compiler knows how to compare the elements and sort them.
///
/// # Examples
///
/// ```
/// let mut data: Vec<i32> = vec![4, 2, 3, 1, 5];
/// sorting::simplesorts::selection::sort(&mut data);
/// assert_eq!(vec![1, 2, 3, 4, 5], data);
/// ```
///
pub fn sort<T: Ord + Debug>(array: &mut Vec<T>) {
    println!("input array:  {:?}", array);

    if !array.is_empty() {
        // Let's loop over the input array, skipping last value (important as we want to get a
        // slice of the following values).
        let n = array.len();
        for i in 0..n-1 {
            println!("    i: {:?}", i);

            // Find index of the minimum value in the slice of values following the i^th element.
            let j = {
                let int_slice = &array[i+1..];
                println!("        array:        {:?}", array);
                println!("        int_slice:    {:?}", int_slice);
                // k now holds the index (of "array") of the minimum element of "int_slice", or the
                // value "i" of the current element of "array" (which should be the less than
                // all elements of "int_slice").
                let k = int_slice.iter().enumerate().fold(i, |j, pair| {
                    if array[i] > *pair.1 { i + 1 + pair.0 } else { j }
                });

                k
            };
            println!("            k: {:?}   array[i]={:?}   array[j]={:?}", j, array[i], array[j]);

            array.swap(i, j);
            println!("   new array: {:?}", array);
        }
    }

    println!("output array: {:?}", array);

    // panic!("Ok");
}
<commit_msg>Bug fix: The previous sorting was taking the last element of "int_slice" smaller than "array[i]".<commit_after>//! Selection sort algorithm.
//!
//! The `selection` module contains the simple sorting algorithm "Selection Sort".
//!
//! Source: https://en.wikipedia.org/wiki/Selection_sort

use std::fmt::Debug;

/// Simple sort: selection sort.
///
/// # Details
///
/// Selection sort is one of the simplest sorting algorithm. The list to sort is split into two
/// sections; the first with the sorted element (starting empty) and the second with the remaining
/// element (starting full). At every iteration, the smallest element in the remaining list is
/// found and placed at the end of the sorted list.
///
/// This function takes an immutable reference vector of any type and returns a vector of `usize`
/// of the same length containing the indices of the initial vector sorted.
///
/// # Scaling
///
/// Selection sort in scale as O(N^2) since for all elements to sort, the algorithm will compare it
/// with every (remaining) elements.
///
/// Insertion sort is still useful as it is quite simple.
///
/// # Optimizations
///
/// None
///
/// # Notes
///
/// The type T of the vector elements to sort _must_ implement the `PartialOrd` trait so the
/// compiler knows how to compare the elements and sort them.
///
/// # Examples
///
/// ```
/// let mut data: Vec<i32> = vec![4, 2, 3, 1, 5];
/// sorting::simplesorts::selection::sort(&mut data);
/// assert_eq!(vec![1, 2, 3, 4, 5], data);
/// ```
///
pub fn sort<T: Ord + Debug>(array: &mut Vec<T>) {
    println!("input array:  {:?}", array);

    if !array.is_empty() {
        // Let's loop over the input array, skipping last value (important as we want to get a
        // slice of the following values).
        let n = array.len();
        for i in 0..n-1 {
            println!("    i: {:?}", i);

            // Find index of the minimum value in the slice of values following the i^th element.
            let j = {
                let int_slice = &array[i+1..];
                println!("        array:        {:?}", array);
                println!("        int_slice:    {:?}", int_slice);
                // k now holds the index (of "array") of the minimum element of "int_slice", or the
                // value "i" of the current element of "array" (which should be the less than
                // all elements of "int_slice").
                // "k" is a tuple containing the smallest element of "int_slice" and its index.
                //     k.0: Index of "int_slice" of its smallest value.
                //     k.1: Smallest value of "int_slice".
                let k = int_slice.iter().enumerate().fold(
                    (0, int_slice.first().unwrap()), |acc, item| {
                        if acc.1 > item.1 { item } else { acc }
                });

                // Return from the block the smallest element between the one at index "i" of
                // the "array" and the smallest one from the "int_slice" array.
                // NOTE: Since "k" worked on the subarray "int_slice", it's first element is the
                //       i^th element of "array". If "k" is actually smaller than "array[i]", we
                //       need to adapt the index as stored in "k.0".
                if k.1 < &array[i] { i + k.0 + 1 } else { i }
            };
            println!("            k: {:?}   array[i]={:?}   array[j]={:?}", j, array[i], array[j]);

            array.swap(i, j);
            println!("   new array: {:?}", array);
        }
    }

    println!("output array: {:?}", array);

    // panic!("Ok");
}
<|endoftext|>


<commit_before>// Menu for a text-based adventure game.
// (Also learn how to import/use code from another file!)

struct MenuOption {
  selector: char,
  description: String,
}

pub fn display_menu() {
  let option_new_game  : MenuOption = MenuOption { selector: 'n', description: "New Game".to_string(), };
  let option_load_game : MenuOption = MenuOption { selector: 'l', description: "Load Game".to_string(), };
  let option_quit      : MenuOption = MenuOption { selector: 'q', description: "Quit".to_string(), };

  println!("Welcome to The Great Rust Adventure!");
  println!("=-----------------------------------=\n");
  println!("  Menu  ");
  println!("--------");

  display_menu_option(option_new_game);
  display_menu_option(option_load_game);
  display_menu_option(option_quit);

}

fn display_menu_option(opt:MenuOption) {
  println!(" {sel} - {desc} ", sel=opt.selector, desc=opt.description)
}
<commit_msg>Make instead array of menu options!<commit_after>// Menu for a text-based adventure game.
// (Also learn how to import/use code from another file!)

#[derive(Clone)]
struct MenuOption {
  selector: char,
  description: String,
}

pub fn display_menu() {
  let options : [MenuOption; 3] = [MenuOption { selector: 'n', description: "New Game".to_string(), },
                                   MenuOption { selector: 'l', description: "Load Game".to_string(), },
                                   MenuOption { selector: 'q', description: "Quit".to_string(), }];

  println!("Welcome to The Great Rust Adventure!");
  println!("=-----------------------------------=\n");
  println!("  Menu  ");
  println!("--------");

  for i in 0..options.len() {
    display_menu_option(options[i].clone());
  }

}

fn display_menu_option(opt:MenuOption) {
  println!(" {sel} - {desc} ", sel=opt.selector, desc=opt.description)
}
<|endoftext|>