<commit_before>use std::collections::HashMap;
use std::fs;
use std::path::Path;
#[macro_use]
extern crate scan_fmt;

#[derive(Clone, PartialEq, Eq, Hash)]
struct Player {
    position: u64,
    score: u64,
}

impl Player {
    fn new(position: u64) -> Self {
        Self { position, score: 0 }
    }
    fn move_spaces(&mut self, spaces: u64) {
        self.position += spaces % 10;
        if self.position > 10 {
            self.position -= 10;
        }
        self.score += self.position;
    }
}

fn part1(pos1: u64, pos2: u64) -> u64 {
    let mut player1 = Player::new(pos1);
    let mut player2 = Player::new(pos2);
    let mut die = 0;
    let mut num_rolls = 0;
    while player1.score < 1000 && player2.score < 1000 {
        num_rolls += 3;
        let mut step = 0;
        for _ in 0..3 {
            die += 1;
            if die > 100 {
                die -= 100;
            }
            step += die;
        }
        player1.move_spaces(step);
        std::mem::swap(&mut player1, &mut player2);
    }
    num_rolls * player1.score.min(player2.score)
}

fn part2(pos1: u64, pos2: u64) -> u64 {
    fn go(
        players: (Player, Player),
        cache: &mut HashMap<(Player, Player), (u64, u64)>,
    ) -> (u64, u64) {
        if players.0.score >= 21 {
            (1, 0)
        } else if players.1.score >= 21 {
            (0, 1)
        } else if let Some(&score) = cache.get(&players) {
            score
        } else {
            let (p1, p2) = players;
            let (mut s1, mut s2) = (0, 0);
            for i in 1..4 {
                for j in 1..4 {
                    for k in 1..4 {
                        let mut p1_fut = p1.clone();
                        p1_fut.move_spaces(i + j + k);
                        let (s2_fut, s1_fut) = go((p2.clone(), p1_fut), cache);
                        s1 += s1_fut;
                        s2 += s2_fut;
                    }
                }
            }
            cache.insert((p1, p2), (s1, s2));
            (s1, s2)
        }
    }
    let (s1, s2) = go((Player::new(pos1), Player::new(pos2)), &mut HashMap::new());
    s1.max(s2)
}

fn main() {
    let input = fs::read_to_string(&Path::new("input.txt")).expect("Can't read file!");
    let (pos1, pos2) = scan_fmt!(
        &input,
        "Player 1 starting position: {d}\nPlayer 2 starting position: {d}",
        u64,
        u64
    )
    .expect("Can't parse positions!");
    println!("Part 1: {}", part1(pos1, pos2));
    println!("Part 2: {}", part2(pos1, pos2));
}
<commit_msg>no need to swap<commit_after>use std::collections::HashMap;
use std::fs;
use std::path::Path;
#[macro_use]
extern crate scan_fmt;

#[derive(Clone, PartialEq, Eq, Hash)]
struct Player {
    position: u64,
    score: u64,
}

impl Player {
    fn new(position: u64) -> Self {
        Self { position, score: 0 }
    }
    fn move_spaces(&mut self, spaces: u64) {
        self.position += spaces % 10;
        if self.position > 10 {
            self.position -= 10;
        }
        self.score += self.position;
    }
}

fn part1(pos1: u64, pos2: u64) -> u64 {
    let mut player1 = Player::new(pos1);
    let mut player2 = Player::new(pos2);
    let mut ones_turn = true;
    let mut die = 0;
    let mut num_rolls = 0;
    while player1.score < 1000 && player2.score < 1000 {
        num_rolls += 3;
        let mut step = 0;
        for _ in 0..3 {
            die += 1;
            if die > 100 {
                die -= 100;
            }
            step += die;
        }
        if ones_turn {
            player1.move_spaces(step);
        } else {
            player2.move_spaces(step);
        }
        ones_turn = !ones_turn
    }
    num_rolls * player1.score.min(player2.score)
}

fn part2(pos1: u64, pos2: u64) -> u64 {
    fn go(
        players: (Player, Player),
        cache: &mut HashMap<(Player, Player), (u64, u64)>,
    ) -> (u64, u64) {
        if players.0.score >= 21 {
            (1, 0)
        } else if players.1.score >= 21 {
            (0, 1)
        } else if let Some(&score) = cache.get(&players) {
            score
        } else {
            let (p1, p2) = players;
            let (mut s1, mut s2) = (0, 0);
            for i in 1..4 {
                for j in 1..4 {
                    for k in 1..4 {
                        let mut p1_fut = p1.clone();
                        p1_fut.move_spaces(i + j + k);
                        let (s2_fut, s1_fut) = go((p2.clone(), p1_fut), cache);
                        s1 += s1_fut;
                        s2 += s2_fut;
                    }
                }
            }
            cache.insert((p1, p2), (s1, s2));
            (s1, s2)
        }
    }
    let (s1, s2) = go((Player::new(pos1), Player::new(pos2)), &mut HashMap::new());
    s1.max(s2)
}

fn main() {
    let input = fs::read_to_string(&Path::new("input.txt")).expect("Can't read file!");
    let (pos1, pos2) = scan_fmt!(
        &input,
        "Player 1 starting position: {d}\nPlayer 2 starting position: {d}",
        u64,
        u64
    )
    .expect("Can't parse positions!");
    println!("Part 1: {}", part1(pos1, pos2));
    println!("Part 2: {}", part2(pos1, pos2));
}
<|endoftext|>


<commit_before>extern crate schannel;

use std::io;
use std::fmt;
use std::error;
use self::schannel::cert_store::PfxImportOptions;
use self::schannel::cert_context::CertContext;
use self::schannel::schannel_cred::{Direction, SchannelCred};
use self::schannel::tls_stream;

pub struct Error(io::Error);

impl error::Error for Error {
    fn description(&self) -> &str {
        error::Error::description(&self.0)
    }

    fn cause(&self) -> Option<&error::Error> {
        error::Error::cause(&self.0)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, fmt)
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl From<io::Error> for Error {
    fn from(error: io::Error) -> Error {
        Error(error)
    }
}

pub struct Pkcs12 {
    cert: CertContext,
}

impl Pkcs12 {
    pub fn from_der(buf: &[u8], pass: &str) -> Result<Pkcs12, Error> {
        let mut store = try!(PfxImportOptions::new()
            .password(pass)
            .import(buf));
        let mut identity = None;

        for cert in store.certs() {
            if cert.private_key().silent(true).compare_key(true).acquire().is_ok() {
                identity = Some(cert);
            }
        }

        let identity = match identity {
            Some(identity) => identity,
            None => {
                return Err(io::Error::new(io::ErrorKind::InvalidInput,
                                          "No identity found in PKCS #12 archive").into());
            },
        };

        Ok(Pkcs12 {
            cert: identity,
        })
    }
}

pub struct MidHandshakeTlsStream<S>(tls_stream::MidHandshakeTlsStream<S>);

impl<S> fmt::Debug for MidHandshakeTlsStream<S>
    where S: fmt::Debug {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S> MidHandshakeTlsStream<S>
    where S: io::Read + io::Write
{
    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }

    pub fn handshake(self) -> Result<TlsStream<S>, HandshakeError<S>> {
        match self.0.handshake() {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub enum HandshakeError<S> {
    Failure(Error),
    Interrupted(MidHandshakeTlsStream<S>),
}

impl<S> From<tls_stream::HandshakeError<S>> for HandshakeError<S> {
    fn from(e: tls_stream::HandshakeError<S>) -> HandshakeError<S> {
        match e {
            tls_stream::HandshakeError::Failure(e) => HandshakeError::Failure(e.into()),
            tls_stream::HandshakeError::Interrupted(s) => {
                HandshakeError::Interrupted(MidHandshakeTlsStream(s))
            }
        }
    }
}

impl<S> From<io::Error> for HandshakeError<S> {
    fn from(e: io::Error) -> HandshakeError<S> {
        HandshakeError::Failure(e.into())
    }
}

pub struct ClientBuilder {
    cert: Option<CertContext>,
}

impl ClientBuilder {
	pub fn new() -> Result<ClientBuilder, Error> {
        Ok(ClientBuilder {
            cert: None,
        })
	}

    pub fn identity(&mut self, pkcs12: Pkcs12) -> Result<(), Error> {
        self.cert = Some(pkcs12.cert);
        Ok(())
    }

    pub fn handshake<S>(&self,
                        domain: &str,
                        stream: S)
                        -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let mut builder = SchannelCred::builder();
        if let Some(cert) = self.cert.as_ref() {
            builder.cert(cert.clone());
        }
        let cred = try!(builder.acquire(Direction::Outbound));
        match tls_stream::Builder::new().domain(domain).connect(cred, stream) {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub struct ServerBuilder {
    cert: CertContext,
}

impl ServerBuilder {
    pub fn new(pkcs12: Pkcs12) -> Result<ServerBuilder, Error> {
        Ok(ServerBuilder {
            cert: pkcs12.cert,
        })
    }

    pub fn handshake<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let mut builder = SchannelCred::builder();
        builder.cert(self.cert.clone());
        // FIXME we're probably missing the certificate chain?
        let cred = try!(builder.acquire(Direction::Inbound));
        match tls_stream::Builder::new().accept(cred, stream) {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub struct TlsStream<S>(tls_stream::TlsStream<S>);

impl<S: fmt::Debug> fmt::Debug for TlsStream<S> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S: io::Read + io::Write> TlsStream<S> {
    pub fn buffered_read_size(&self) -> Result<usize, Error> {
        Ok(self.0.get_buf().len())
    }

    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S: io::Read + io::Write> io::Read for TlsStream<S> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl<S: io::Read + io::Write> io::Write for TlsStream<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

/// SChannel-specific extensions to `TlsStream`.
pub trait TlsStreamExt<S> {
    /// Returns a shared reference to the SChannel `TlsStream`.
    fn raw_stream(&self) -> &tls_stream::TlsStream<S>;

    /// Returns a mutable reference to the SChannel `TlsStream`.
    fn raw_stream_mut(&mut self) -> &mut tls_stream::TlsStream<S>;
}

impl<S> TlsStreamExt<S> for ::TlsStream<S> {
    fn raw_stream(&self) -> &tls_stream::TlsStream<S> {
        &(self.0).0
    }

    fn raw_stream_mut(&mut self) -> &mut tls_stream::TlsStream<S> {
        &mut (self.0).0
    }
}
<commit_msg>Only enable TLS protocols for schannel<commit_after>extern crate schannel;

use std::io;
use std::fmt;
use std::error;
use self::schannel::cert_store::PfxImportOptions;
use self::schannel::cert_context::CertContext;
use self::schannel::schannel_cred::{Direction, SchannelCred, Protocol};
use self::schannel::tls_stream;

pub struct Error(io::Error);

impl error::Error for Error {
    fn description(&self) -> &str {
        error::Error::description(&self.0)
    }

    fn cause(&self) -> Option<&error::Error> {
        error::Error::cause(&self.0)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, fmt)
    }
}

impl fmt::Debug for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl From<io::Error> for Error {
    fn from(error: io::Error) -> Error {
        Error(error)
    }
}

pub struct Pkcs12 {
    cert: CertContext,
}

impl Pkcs12 {
    pub fn from_der(buf: &[u8], pass: &str) -> Result<Pkcs12, Error> {
        let mut store = try!(PfxImportOptions::new()
            .password(pass)
            .import(buf));
        let mut identity = None;

        for cert in store.certs() {
            if cert.private_key().silent(true).compare_key(true).acquire().is_ok() {
                identity = Some(cert);
            }
        }

        let identity = match identity {
            Some(identity) => identity,
            None => {
                return Err(io::Error::new(io::ErrorKind::InvalidInput,
                                          "No identity found in PKCS #12 archive").into());
            },
        };

        Ok(Pkcs12 {
            cert: identity,
        })
    }
}

pub struct MidHandshakeTlsStream<S>(tls_stream::MidHandshakeTlsStream<S>);

impl<S> fmt::Debug for MidHandshakeTlsStream<S>
    where S: fmt::Debug {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S> MidHandshakeTlsStream<S>
    where S: io::Read + io::Write
{
    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }

    pub fn handshake(self) -> Result<TlsStream<S>, HandshakeError<S>> {
        match self.0.handshake() {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub enum HandshakeError<S> {
    Failure(Error),
    Interrupted(MidHandshakeTlsStream<S>),
}

impl<S> From<tls_stream::HandshakeError<S>> for HandshakeError<S> {
    fn from(e: tls_stream::HandshakeError<S>) -> HandshakeError<S> {
        match e {
            tls_stream::HandshakeError::Failure(e) => HandshakeError::Failure(e.into()),
            tls_stream::HandshakeError::Interrupted(s) => {
                HandshakeError::Interrupted(MidHandshakeTlsStream(s))
            }
        }
    }
}

impl<S> From<io::Error> for HandshakeError<S> {
    fn from(e: io::Error) -> HandshakeError<S> {
        HandshakeError::Failure(e.into())
    }
}

pub struct ClientBuilder {
    cert: Option<CertContext>,
}

impl ClientBuilder {
	pub fn new() -> Result<ClientBuilder, Error> {
        Ok(ClientBuilder {
            cert: None,
        })
	}

    pub fn identity(&mut self, pkcs12: Pkcs12) -> Result<(), Error> {
        self.cert = Some(pkcs12.cert);
        Ok(())
    }

    pub fn handshake<S>(&self,
                        domain: &str,
                        stream: S)
                        -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let mut builder = SchannelCred::builder();
        let protocols = [
            Protocol::Tls10,
            Protocol::Tls11,
            Protocol::Tls12,
        ];
        builder.enabled_protocols(&protocols);
        if let Some(cert) = self.cert.as_ref() {
            builder.cert(cert.clone());
        }
        let cred = try!(builder.acquire(Direction::Outbound));
        match tls_stream::Builder::new().domain(domain).connect(cred, stream) {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub struct ServerBuilder {
    cert: CertContext,
}

impl ServerBuilder {
    pub fn new(pkcs12: Pkcs12) -> Result<ServerBuilder, Error> {
        Ok(ServerBuilder {
            cert: pkcs12.cert,
        })
    }

    pub fn handshake<S>(&self, stream: S) -> Result<TlsStream<S>, HandshakeError<S>>
        where S: io::Read + io::Write
    {
        let mut builder = SchannelCred::builder();
        builder.cert(self.cert.clone());
        // FIXME we're probably missing the certificate chain?
        let cred = try!(builder.acquire(Direction::Inbound));
        match tls_stream::Builder::new().accept(cred, stream) {
            Ok(s) => Ok(TlsStream(s)),
            Err(e) => Err(e.into()),
        }
    }
}

pub struct TlsStream<S>(tls_stream::TlsStream<S>);

impl<S: fmt::Debug> fmt::Debug for TlsStream<S> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.0, fmt)
    }
}

impl<S: io::Read + io::Write> TlsStream<S> {
    pub fn buffered_read_size(&self) -> Result<usize, Error> {
        Ok(self.0.get_buf().len())
    }

    pub fn get_ref(&self) -> &S {
        self.0.get_ref()
    }

    pub fn get_mut(&mut self) -> &mut S {
        self.0.get_mut()
    }
}

impl<S: io::Read + io::Write> io::Read for TlsStream<S> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
}

impl<S: io::Read + io::Write> io::Write for TlsStream<S> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0.flush()
    }
}

/// SChannel-specific extensions to `TlsStream`.
pub trait TlsStreamExt<S> {
    /// Returns a shared reference to the SChannel `TlsStream`.
    fn raw_stream(&self) -> &tls_stream::TlsStream<S>;

    /// Returns a mutable reference to the SChannel `TlsStream`.
    fn raw_stream_mut(&mut self) -> &mut tls_stream::TlsStream<S>;
}

impl<S> TlsStreamExt<S> for ::TlsStream<S> {
    fn raw_stream(&self) -> &tls_stream::TlsStream<S> {
        &(self.0).0
    }

    fn raw_stream_mut(&mut self) -> &mut tls_stream::TlsStream<S> {
        &mut (self.0).0
    }
}
<|endoftext|>


<commit_before>use std::sync::Arc;

use relative_path::RelativePathBuf;
use test_utils::{extract_offset, extract_range, parse_fixture, CURSOR_MARKER};
use ra_db::mock::FileMap;

use crate::{Analysis, AnalysisChange, AnalysisHost, FileId, FilePosition, FileRange, SourceRootId};

/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis
/// from a set of in-memory files.
#[derive(Debug, Default)]
pub struct MockAnalysis {
    files: Vec<(String, String)>,
}

impl MockAnalysis {
    pub fn new() -> MockAnalysis {
        MockAnalysis::default()
    }
    /// Creates `MockAnalysis` using a fixture data in the following format:
    ///
    /// ```notrust
    /// //- /main.rs
    /// mod foo;
    /// fn main() {}
    ///
    /// //- /foo.rs
    /// struct Baz;
    /// ```
    pub fn with_files(fixture: &str) -> MockAnalysis {
        let mut res = MockAnalysis::new();
        for entry in parse_fixture(fixture) {
            res.add_file(&entry.meta, &entry.text);
        }
        res
    }

    /// Same as `with_files`, but requires that a single file contains a `<|>` marker,
    /// whose position is also returned.
    pub fn with_files_and_position(fixture: &str) -> (MockAnalysis, FilePosition) {
        let mut position = None;
        let mut res = MockAnalysis::new();
        for entry in parse_fixture(fixture) {
            if entry.text.contains(CURSOR_MARKER) {
                assert!(
                    position.is_none(),
                    "only one marker (<|>) per fixture is allowed"
                );
                position = Some(res.add_file_with_position(&entry.meta, &entry.text));
            } else {
                res.add_file(&entry.meta, &entry.text);
            }
        }
        let position = position.expect("expected a marker (<|>)");
        (res, position)
    }

    /// Same as `with_files`, but requires that a single file contains two `<|>` marker,
    /// whose range is also returned.
    pub fn with_files_and_range(fixture: &str) -> (MockAnalysis, FileRange) {
        let mut range = None;
        let mut res = MockAnalysis::new();
        for entry in parse_fixture(fixture) {
            if entry.text.contains(CURSOR_MARKER) {
                assert!(
                    range.is_none(),
                    "only two marker (<|>) per fixture is allowed"
                );
                range = Some(res.add_file_with_range(&entry.meta, &entry.text));
            } else {
                res.add_file(&entry.meta, &entry.text);
            }
        }
        let range = range.expect("expected two marker (<|>)");
        (res, range)
    }

    pub fn add_file(&mut self, path: &str, text: &str) -> FileId {
        let file_id = FileId((self.files.len() + 1) as u32);
        self.files.push((path.to_string(), text.to_string()));
        file_id
    }
    pub fn add_file_with_position(&mut self, path: &str, text: &str) -> FilePosition {
        let (offset, text) = extract_offset(text);
        let file_id = FileId((self.files.len() + 1) as u32);
        self.files.push((path.to_string(), text.to_string()));
        FilePosition { file_id, offset }
    }
    pub fn add_file_with_range(&mut self, path: &str, text: &str) -> FileRange {
        let (range, text) = extract_range(text);
        let file_id = FileId((self.files.len() + 1) as u32);
        self.files.push((path.to_string(), text.to_string()));
        FileRange { file_id, range }
    }
    pub fn id_of(&self, path: &str) -> FileId {
        let (idx, _) = self
            .files
            .iter()
            .enumerate()
            .find(|(_, (p, _text))| path == p)
            .expect("no file in this mock");
        FileId(idx as u32 + 1)
    }
    pub fn analysis_host(self) -> AnalysisHost {
        let mut host = AnalysisHost::default();
        let mut file_map = FileMap::default();
        let source_root = SourceRootId(0);
        let mut change = AnalysisChange::new();
        change.add_root(source_root, true);
        for (path, contents) in self.files.into_iter() {
            assert!(path.starts_with('/'));
            let path = RelativePathBuf::from_path(&path[1..]).unwrap();
            let file_id = file_map.add(path.clone());
            change.add_file(source_root, file_id, path, Arc::new(contents));
        }
        // change.set_file_resolver(Arc::new(file_map));
        host.apply_change(change);
        host
    }
    pub fn analysis(self) -> Analysis {
        self.analysis_host().analysis()
    }
}

/// Creates analysis from a multi-file fixture, returns positions marked with a <|>.
pub fn analysis_and_position(fixture: &str) -> (Analysis, FilePosition) {
    let (mock, position) = MockAnalysis::with_files_and_position(fixture);
    (mock.analysis(), position)
}

/// Creates analysis from a multi-file fixture, returns ranges marked with two <|>.
pub fn analysis_and_range(fixture: &str) -> (Analysis, FileRange) {
    let (mock, range) = MockAnalysis::with_files_and_range(fixture);
    (mock.analysis(), range)
}

/// Creates analysis for a single file.
pub fn single_file(code: &str) -> (Analysis, FileId) {
    let mut mock = MockAnalysis::new();
    let file_id = mock.add_file("/main.rs", code);
    (mock.analysis(), file_id)
}

/// Creates analysis for a single file, returns position marked with <|>.
pub fn single_file_with_position(code: &str) -> (Analysis, FilePosition) {
    let mut mock = MockAnalysis::new();
    let pos = mock.add_file_with_position("/main.rs", code);
    (mock.analysis(), pos)
}

/// Creates analysis for a single file, returns range marked with a pair of <|>.
pub fn single_file_with_range(code: &str) -> (Analysis, FileRange) {
    let mut mock = MockAnalysis::new();
    let pos = mock.add_file_with_range("/main.rs", code);
    (mock.analysis(), pos)
}
<commit_msg>Remove unnecessary mock functions<commit_after>use std::sync::Arc;

use relative_path::RelativePathBuf;
use test_utils::{extract_offset, extract_range, parse_fixture, CURSOR_MARKER};
use ra_db::mock::FileMap;

use crate::{Analysis, AnalysisChange, AnalysisHost, FileId, FilePosition, FileRange, SourceRootId};

/// Mock analysis is used in test to bootstrap an AnalysisHost/Analysis
/// from a set of in-memory files.
#[derive(Debug, Default)]
pub struct MockAnalysis {
    files: Vec<(String, String)>,
}

impl MockAnalysis {
    pub fn new() -> MockAnalysis {
        MockAnalysis::default()
    }
    /// Creates `MockAnalysis` using a fixture data in the following format:
    ///
    /// ```notrust
    /// //- /main.rs
    /// mod foo;
    /// fn main() {}
    ///
    /// //- /foo.rs
    /// struct Baz;
    /// ```
    pub fn with_files(fixture: &str) -> MockAnalysis {
        let mut res = MockAnalysis::new();
        for entry in parse_fixture(fixture) {
            res.add_file(&entry.meta, &entry.text);
        }
        res
    }

    /// Same as `with_files`, but requires that a single file contains a `<|>` marker,
    /// whose position is also returned.
    pub fn with_files_and_position(fixture: &str) -> (MockAnalysis, FilePosition) {
        let mut position = None;
        let mut res = MockAnalysis::new();
        for entry in parse_fixture(fixture) {
            if entry.text.contains(CURSOR_MARKER) {
                assert!(
                    position.is_none(),
                    "only one marker (<|>) per fixture is allowed"
                );
                position = Some(res.add_file_with_position(&entry.meta, &entry.text));
            } else {
                res.add_file(&entry.meta, &entry.text);
            }
        }
        let position = position.expect("expected a marker (<|>)");
        (res, position)
    }

    pub fn add_file(&mut self, path: &str, text: &str) -> FileId {
        let file_id = FileId((self.files.len() + 1) as u32);
        self.files.push((path.to_string(), text.to_string()));
        file_id
    }
    pub fn add_file_with_position(&mut self, path: &str, text: &str) -> FilePosition {
        let (offset, text) = extract_offset(text);
        let file_id = FileId((self.files.len() + 1) as u32);
        self.files.push((path.to_string(), text.to_string()));
        FilePosition { file_id, offset }
    }
    pub fn add_file_with_range(&mut self, path: &str, text: &str) -> FileRange {
        let (range, text) = extract_range(text);
        let file_id = FileId((self.files.len() + 1) as u32);
        self.files.push((path.to_string(), text.to_string()));
        FileRange { file_id, range }
    }
    pub fn id_of(&self, path: &str) -> FileId {
        let (idx, _) = self
            .files
            .iter()
            .enumerate()
            .find(|(_, (p, _text))| path == p)
            .expect("no file in this mock");
        FileId(idx as u32 + 1)
    }
    pub fn analysis_host(self) -> AnalysisHost {
        let mut host = AnalysisHost::default();
        let mut file_map = FileMap::default();
        let source_root = SourceRootId(0);
        let mut change = AnalysisChange::new();
        change.add_root(source_root, true);
        for (path, contents) in self.files.into_iter() {
            assert!(path.starts_with('/'));
            let path = RelativePathBuf::from_path(&path[1..]).unwrap();
            let file_id = file_map.add(path.clone());
            change.add_file(source_root, file_id, path, Arc::new(contents));
        }
        // change.set_file_resolver(Arc::new(file_map));
        host.apply_change(change);
        host
    }
    pub fn analysis(self) -> Analysis {
        self.analysis_host().analysis()
    }
}

/// Creates analysis from a multi-file fixture, returns positions marked with <|>.
pub fn analysis_and_position(fixture: &str) -> (Analysis, FilePosition) {
    let (mock, position) = MockAnalysis::with_files_and_position(fixture);
    (mock.analysis(), position)
}

/// Creates analysis for a single file.
pub fn single_file(code: &str) -> (Analysis, FileId) {
    let mut mock = MockAnalysis::new();
    let file_id = mock.add_file("/main.rs", code);
    (mock.analysis(), file_id)
}

/// Creates analysis for a single file, returns position marked with <|>.
pub fn single_file_with_position(code: &str) -> (Analysis, FilePosition) {
    let mut mock = MockAnalysis::new();
    let pos = mock.add_file_with_position("/main.rs", code);
    (mock.analysis(), pos)
}

/// Creates analysis for a single file, returns range marked with a pair of <|>.
pub fn single_file_with_range(code: &str) -> (Analysis, FileRange) {
    let mut mock = MockAnalysis::new();
    let pos = mock.add_file_with_range("/main.rs", code);
    (mock.analysis(), pos)
}
<|endoftext|>


<commit_before>// Copyright 2016, 2017 James Bostock. See the LICENSE file at the
// top-level directory of this distribution.

// An implementation of the rm(1) command in Rust.
// See http://man.cat-v.org/unix-6th/1/rm
use std::env;
use std::fs;
use std::io;
use std::io::Write;

#[macro_use]
mod util;

fn main() {
    let args: Vec<_> = env::args().collect();
    let mut processing_options: bool = true;
    let mut force: bool = false;
    let mut recursive: bool = false;

    if args.len() > 1 {
        for arg in args.iter().skip(1) {
            if arg == "-f" {
                if processing_options {
                    force = true;
                    continue;
                }
            } else if arg == "-r" {
                if processing_options {
                    recursive = true;
                    continue;
                }
            } else {
                processing_options = false;
            }

            match fs::metadata(arg) {
                Ok(md) => {
                    if md.permissions().readonly() {
                        print!("rm: remove readonly file {}? ", arg);
                        io::stdout().flush();
                        let mut resp = String::new();
                        match io::stdin().read_line(&mut resp) {
                            Ok(_) => {
                                match resp.chars().next() {
                                    Some(c) => {
                                        if c != 'y' {
                                            continue;
                                        }
                                    },
                                    None => {}
                                }
                            },
                            Err(e) => {
                                eprintln!("Error reading response: {}", e);
                                break;
                            }
                        }
                    }
                },
                Err(e) => {
                    eprintln!("{}; {}", arg, e);
                    continue;
                }
            }

            match if recursive {
                fs::remove_dir_all(arg)
            } else {
                fs::remove_file(arg)
            } {
                Ok(_) => {},
                Err(e) => { if !force { eprintln!("{}: {}", arg, e); } }
            }
        }
    } else {
        eprintln!("usage: {} [-f][-r] file ...", args[0]);
    }
}
<commit_msg>Refactor rm.rs.<commit_after>// Copyright 2016, 2017 James Bostock. See the LICENSE file at the
// top-level directory of this distribution.

// An implementation of the rm(1) command in Rust.
// See http://man.cat-v.org/unix-6th/1/rm
use std::env;
use std::fs;
use std::io;
use std::io::Write;

#[macro_use]
mod util;

/// Prompts user for confirmation
fn confirm(msg: &str) -> io::Result<bool> {
    print!("{}: ", msg);
    io::stdout().flush()?;
    let mut resp = String::new();
    io::stdin().read_line(&mut resp)?;
    match resp.chars().next() {
        Some(c) => {
            if c == 'y' {
                Ok(true)
            } else {
                Ok(false)
            }
        },
        None => Ok(false)
    }
}

/// Removes a file or directory
fn rm(name: &str, force: bool, recursive: bool) -> io::Result<()> {
    let md = fs::metadata(name)?;
    let go = if md.permissions().readonly() {
        let mut msg = "rm: remove readonly file ".to_string();
        msg.push_str(&name);
        msg.push_str("?");
        if confirm(&msg)? {
            true
        } else {
            false
        }
    } else {
        true
    };

    if go {
        if recursive {
            fs::remove_dir_all(name)
        } else {
            fs::remove_file(name)
        }
    } else {
        Ok(())
    }
}

fn main() {
    let args: Vec<_> = env::args().collect();
    let mut processing_options: bool = true;
    let mut force: bool = false;
    let mut recursive: bool = false;

    if args.len() > 1 {
        for arg in args.iter().skip(1) {
            if arg == "-f" {
                if processing_options {
                    force = true;
                    continue;
                }
            } else if arg == "-r" {
                if processing_options {
                    recursive = true;
                    continue;
                }
            } else {
                processing_options = false;
            }

            match rm(arg, force, recursive) {
                Ok(_) => {},
                Err(e) => eprintln!("{}: {}", arg, e)
            }
        }
    } else {
        eprintln!("usage: {} [-f][-r] file ...", args[0]);
    }
}
<|endoftext|>


<commit_before>use card_strategy::CardStrategy;

use card::Card;
use game_status::GameStatus;
use player::PlayerName;

use std::collections::BTreeMap;

#[derive(Debug)]
pub struct MyCardStrategy;

impl MyCardStrategy {
    fn score_card<'a>(card: &'a Card, game_status: &'a GameStatus, player_name: &PlayerName) -> (i32, i32, i32, i32) {
        let card_penalty_to_me = MyCardStrategy::card_penalty_to_me(card, game_status, player_name);
        let card_penalty = 0 - MyCardStrategy::card_penalty(card, game_status);
        let trouble = MyCardStrategy::trouble_score(card, game_status);
        let card_rank = 0 - (u32::from(card.rank) as i32);
        (card_penalty_to_me, card_penalty, trouble, card_rank)
    }

    fn card_penalty(card: &Card, game_status: &GameStatus) -> i32 {
        game_status.round_parameters.card_points.get(card).map(|penalty| penalty.clone()).unwrap_or_default()
    }

    fn card_penalty_to_me(card: &Card, game_status: &GameStatus, player_name: &PlayerName) -> i32 {
        if MyCardStrategy::will_win_deal(card, game_status) {
            MyCardStrategy::card_penalty(card, game_status)
        } else {
            0
        }
    }

    fn trouble_score(card: &Card, game_status: &GameStatus) -> i32 {
        if MyCardStrategy::will_win_deal(card, game_status) {
            u32::from(card.rank) as i32
        } else {
            0
        }
    }

    fn will_win_deal(card: &Card, game_status: &GameStatus) -> bool {
        game_status.my_in_progress_deal.as_ref().and_then(|deal|
            deal.suit.and_then(|current_suit|
                deal.deal_cards.iter()
                    .map(|deal_card| deal_card.card)
                    .filter(|card| card.suit == current_suit)
                    .max()
                    .map(|winning_card| card.suit == current_suit && card.rank > winning_card.rank))).unwrap_or(true)
    }
}

impl CardStrategy for MyCardStrategy {

    fn pass_cards<'a>(&mut self, game_status: &'a GameStatus) -> Vec<&'a Card> {
        // Need to order cards by potential to win lowest penalty hands
        let mut initial_hand: Vec<&'a Card> = game_status.my_initial_hand.iter().collect();
        initial_hand.reverse();
        initial_hand.into_iter().take(3).collect()
    }

    fn play_card<'a>(&mut self, game_status: &'a GameStatus, player_name: &PlayerName) -> &'a Card {
        let current_suit = game_status.my_in_progress_deal.as_ref().and_then(|deal| deal.suit);
        let mut valid_cards: Vec<&'a Card> = game_status.my_current_hand.iter().filter(|card| Some(card.suit) == current_suit).collect();

        if valid_cards.is_empty() {
            valid_cards.extend(&game_status.my_current_hand);
        }

        let scored_cards: BTreeMap<((i32, i32, i32, i32), &Card), &Card> = valid_cards.into_iter().map(|card| {
            ((MyCardStrategy::score_card(card, game_status, player_name), card), card)
        }).collect();

        scored_cards.values().next().expect("No valid cards to play!")
    }

}<commit_msg>cleanup<commit_after>use card_strategy::CardStrategy;

use card::Card;
use game_status::GameStatus;
use player::PlayerName;

use std::collections::BTreeMap;

#[derive(Debug)]
pub struct MyCardStrategy;

impl MyCardStrategy {
    fn score_card<'a>(card: &'a Card, game_status: &'a GameStatus, player_name: &PlayerName) -> (i32, i32, i32, i32) {
        let card_penalty_to_me = MyCardStrategy::card_penalty_to_me(card, game_status, player_name);
        let card_penalty = 0 - MyCardStrategy::card_penalty(card, game_status);
        let trouble = MyCardStrategy::trouble_score(card, game_status);
        let card_rank = 0 - (u32::from(card.rank) as i32);
        (card_penalty_to_me, card_penalty, trouble, card_rank)
    }

    fn card_penalty(card: &Card, game_status: &GameStatus) -> i32 {
        game_status.round_parameters.card_points.get(card).map(|penalty| penalty.clone()).unwrap_or_default()
    }

    fn card_penalty_to_me(card: &Card, game_status: &GameStatus, player_name: &PlayerName) -> i32 {
        if MyCardStrategy::will_win_deal(card, game_status) {
            MyCardStrategy::card_penalty(card, game_status)
        } else {
            0
        }
    }

    fn trouble_score(card: &Card, game_status: &GameStatus) -> i32 {
        if MyCardStrategy::will_win_deal(card, game_status) {
            u32::from(card.rank) as i32
        } else {
            0
        }
    }

    fn will_win_deal(card: &Card, game_status: &GameStatus) -> bool {
        game_status.my_in_progress_deal.as_ref().and_then(|deal|
            deal.suit.and_then(|suit|
                deal.deal_cards.iter()
                    .map(|deal_card| deal_card.card)
                    .filter(|card| card.suit == suit)
                    .max()
                    .map(|winning_card| card.suit == suit && card.rank > winning_card.rank))).unwrap_or(true)
    }
}

impl CardStrategy for MyCardStrategy {

    fn pass_cards<'a>(&mut self, game_status: &'a GameStatus) -> Vec<&'a Card> {
        // Need to order cards by potential to win lowest penalty hands
        let mut initial_hand: Vec<&'a Card> = game_status.my_initial_hand.iter().collect();
        initial_hand.reverse();
        initial_hand.into_iter().take(3).collect()
    }

    fn play_card<'a>(&mut self, game_status: &'a GameStatus, player_name: &PlayerName) -> &'a Card {
        let current_suit = game_status.my_in_progress_deal.as_ref().and_then(|deal| deal.suit);
        let mut valid_cards: Vec<&'a Card> = game_status.my_current_hand.iter().filter(|card| Some(card.suit) == current_suit).collect();

        if valid_cards.is_empty() {
            valid_cards.extend(&game_status.my_current_hand);
        }

        let scored_cards = valid_cards.into_iter()
            .map(|card| ((MyCardStrategy::score_card(card, game_status, player_name), card), card)).collect::<BTreeMap<((i32, i32, i32, i32), &Card), &Card>>();

        scored_cards.values().next().expect("No valid cards to play!")
    }

}<|endoftext|>


<commit_before>extern crate serde_json;

use std;
use std::io::Read;
use std::time::Duration;
use std::collections::HashSet;
use std::net::IpAddr;
use std::net::Ipv4Addr;
use std::net::UdpSocket;
use std::str;

use hyper::Client;

/// Returns a HashSet of hue bridge SocketAddr's
pub fn discover() -> HashSet<Ipv4Addr> {

    let string_list = vec![
        "M-SEARCH * HTTP/1.1",
        "HOST:239.255.255.250:1900",
        "MAN:\"ssdp:discover\"",
        "ST:ssdp:all",
        "MX:1"
            ];
    let joined = string_list.join("\r\n");

    let socket =
        UdpSocket::bind("0.0.0.0:0").unwrap();

    let two_second_timeout = Duration::new(2, 0);
    let _ = socket.set_read_timeout(Some(two_second_timeout));
    socket.send_to(joined.as_bytes(), "239.255.255.250:1900").unwrap();

    let mut bridges = HashSet::new();
    loop {
        let mut buf = [0;255];
        let sockread = match socket.recv_from(&mut buf) {
            Ok(val) => val,
            Err(e) => {
                match e.kind() {
                    // a timeout on unix is considered a WouldBlock
                    std::io::ErrorKind::WouldBlock => break,
                    _ => panic!(e),
                }
            }
        };
        let _ = str::from_utf8(&buf).and_then(|s| {
            // Hue docs say to use "IpBridge" over "hue-bridgeid"
            if s.contains("IpBridge") {
                if let IpAddr::V4(addr) = sockread.1.ip() {
                    bridges.insert(addr);
                }
            }
            Ok(s)
        });
    }

    bridges
}

/// Hue Bridge
#[derive(Debug)]
pub struct Bridge {
    ip: Ipv4Addr,
}

impl Bridge {
    /// Returns a hue bridge with the given ip
    pub fn new(addr: Ipv4Addr) -> Bridge {
        Bridge {
            ip: addr,
        }
    }

    /// Attempt to register with the hue bridge
    pub fn register(&self, name: &str) {
        #[derive(Debug, Serialize, Deserialize)]
        struct Devicetype {
            devicetype: String,
        }

        let client = Client::new();
        let url = format!("http://{}/api", self.ip);
        let payload = Devicetype { devicetype: name.to_owned() };
	let body = serde_json::to_string(&payload).unwrap();

        // TODO handle errors and return username
        let mut response = client.post(&url).body(&body).send().unwrap();
        let mut buf = String::new();
        response.read_to_string(&mut buf).unwrap();
        println!("{}", buf);
    }
}
<commit_msg>look at statuscode returned<commit_after>extern crate serde_json;

use std;
use std::io::Read;
use std::time::Duration;
use std::collections::HashSet;
use std::net::IpAddr;
use std::net::Ipv4Addr;
use std::net::UdpSocket;
use std::str;

use hyper::Client;

/// Returns a HashSet of hue bridge SocketAddr's
pub fn discover() -> HashSet<Ipv4Addr> {

    let string_list = vec![
        "M-SEARCH * HTTP/1.1",
        "HOST:239.255.255.250:1900",
        "MAN:\"ssdp:discover\"",
        "ST:ssdp:all",
        "MX:1"
            ];
    let joined = string_list.join("\r\n");

    let socket =
        UdpSocket::bind("0.0.0.0:0").unwrap();

    let two_second_timeout = Duration::new(2, 0);
    let _ = socket.set_read_timeout(Some(two_second_timeout));
    socket.send_to(joined.as_bytes(), "239.255.255.250:1900").unwrap();

    let mut bridges = HashSet::new();
    loop {
        let mut buf = [0;255];
        let sockread = match socket.recv_from(&mut buf) {
            Ok(val) => val,
            Err(e) => {
                match e.kind() {
                    // a timeout on unix is considered a WouldBlock
                    std::io::ErrorKind::WouldBlock => break,
                    _ => panic!(e),
                }
            }
        };
        let _ = str::from_utf8(&buf).and_then(|s| {
            // Hue docs say to use "IpBridge" over "hue-bridgeid"
            if s.contains("IpBridge") {
                if let IpAddr::V4(addr) = sockread.1.ip() {
                    bridges.insert(addr);
                }
            }
            Ok(s)
        });
    }

    bridges
}

/// Hue Bridge
#[derive(Debug)]
pub struct Bridge {
    ip: Ipv4Addr,
}

impl Bridge {
    /// Returns a hue bridge with the given ip
    pub fn new(addr: Ipv4Addr) -> Bridge {
        Bridge {
            ip: addr,
        }
    }

    /// Attempt to register with the hue bridge
    pub fn register(&self, name: &str) {
        #[derive(Debug, Serialize, Deserialize)]
        struct Devicetype {
            devicetype: String,
        }

        let client = Client::new();
        let url = format!("http://{}/api", self.ip);
        let payload = Devicetype { devicetype: name.to_owned() };
	let body = serde_json::to_string(&payload).unwrap();

        // TODO handle errors and return username
        let mut response = client.post(&url).body(&body).send().unwrap();
        let mut buf = String::new();
        response.read_to_string(&mut buf).unwrap();
        println!("{}", buf);
        println!("{}", response.status);
    }
}
<|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 as i64 == rhs as *const T as i64
}

//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>,
}

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() }
    }

    pub fn subscribe(&mut self, subscriber: Rc<RefCell<T>>, topic: &str) {
        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::unsubscribe_impl(&mut self.tree, subscriber.clone(), &[], false);
    }

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

    pub fn publish(&self, topic: &str, payload: &[u8]) {
        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);
        }
    }

}

#[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>Simplified is_same<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>,
}

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() }
    }

    pub fn subscribe(&mut self, subscriber: Rc<RefCell<T>>, topic: &str) {
        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::unsubscribe_impl(&mut self.tree, subscriber.clone(), &[], false);
    }

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

    pub fn publish(&self, topic: &str, payload: &[u8]) {
        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);
        }
    }

}

#[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>

// Simple Extensible Binary Markup Language (ebml) reader and writer on a
// cursor model. See the specification here:
//     http://www.matroska.org/technical/specs/rfc/index.html
import option::none;
import option::some;

type ebml_tag = rec(uint id, uint size);

type ebml_state = rec(ebml_tag ebml_tag, uint tag_pos, uint data_pos);

// TODO: When we have module renaming, make "reader" and "writer" separate
// modules within this file.

// ebml reading
type doc = rec(@u8[] data, uint start, uint end);

fn vint_at(&@u8[] data, uint start) -> tup(uint, uint) {
    auto a = data.(start);
    if (a & 0x80u8 != 0u8) { ret tup(a & 0x7fu8 as uint, start + 1u); }
    if (a & 0x40u8 != 0u8) {
        ret tup((a & 0x3fu8 as uint) << 8u | (data.(start + 1u) as uint),
                start + 2u);
    } else if (a & 0x20u8 != 0u8) {
        ret tup((a & 0x1fu8 as uint) << 16u |
                    (data.(start + 1u) as uint) << 8u |
                    (data.(start + 2u) as uint), start + 3u);
    } else if (a & 0x10u8 != 0u8) {
        ret tup((a & 0x0fu8 as uint) << 24u |
                    (data.(start + 1u) as uint) << 16u |
                    (data.(start + 2u) as uint) << 8u |
                    (data.(start + 3u) as uint), start + 4u);
    } else { log_err "vint too big"; fail; }
}

fn new_doc(&@u8[] data) -> doc {
    ret rec(data=data, start=0u, end=ivec::len[u8](*data));
}

fn doc_at(&@u8[] data, uint start) -> doc {
    auto elt_tag = vint_at(data, start);
    auto elt_size = vint_at(data, elt_tag._1);
    auto end = elt_size._1 + elt_size._0;
    ret rec(data=data, start=elt_size._1, end=end);
}

fn maybe_get_doc(doc d, uint tg) -> option::t[doc] {
    auto pos = d.start;
    while (pos < d.end) {
        auto elt_tag = vint_at(d.data, pos);
        auto elt_size = vint_at(d.data, elt_tag._1);
        pos = elt_size._1 + elt_size._0;
        if (elt_tag._0 == tg) {
            ret some[doc](rec(data=d.data, start=elt_size._1, end=pos));
        }
    }
    ret none[doc];
}

fn get_doc(doc d, uint tg) -> doc {
    alt (maybe_get_doc(d, tg)) {
        case (some(?d)) { ret d; }
        case (none) {
            log_err "failed to find block with tag " + uint::to_str(tg, 10u);
            fail;
        }
    }
}

iter docs(doc d) -> tup(uint, doc) {
    auto pos = d.start;
    while (pos < d.end) {
        auto elt_tag = vint_at(d.data, pos);
        auto elt_size = vint_at(d.data, elt_tag._1);
        pos = elt_size._1 + elt_size._0;
        put tup(elt_tag._0, rec(data=d.data, start=elt_size._1, end=pos));
    }
}

iter tagged_docs(doc d, uint tg) -> doc {
    auto pos = d.start;
    while (pos < d.end) {
        auto elt_tag = vint_at(d.data, pos);
        auto elt_size = vint_at(d.data, elt_tag._1);
        pos = elt_size._1 + elt_size._0;
        if (elt_tag._0 == tg) {
            put rec(data=d.data, start=elt_size._1, end=pos);
        }
    }
}

fn doc_data(doc d) -> u8[] { ret ivec::slice[u8](*d.data, d.start, d.end); }

fn be_uint_from_bytes(&@u8[] data, uint start, uint size) -> uint {
    auto sz = size;
    assert (sz <= 4u);
    auto val = 0u;
    auto pos = start;
    while (sz > 0u) {
        sz -= 1u;
        val += (data.(pos) as uint) << sz * 8u;
        pos += 1u;
    }
    ret val;
}

fn doc_as_uint(doc d) -> uint {
    ret be_uint_from_bytes(d.data, d.start, d.end - d.start);
}

// ebml writing
type writer = rec(ioivec::buf_writer writer, mutable uint[] size_positions);

fn write_sized_vint(&ioivec::buf_writer w, uint n, uint size) {
    let u8[] buf;
    alt (size) {
        case (1u) { buf = ~[0x80u8 | (n as u8)]; }
        case (2u) { buf = ~[0x40u8 | (n >> 8u as u8), n & 0xffu as u8]; }
        case (3u) {
            buf =
                ~[0x20u8 | (n >> 16u as u8), n >> 8u & 0xffu as u8,
                  n & 0xffu as u8];
        }
        case (4u) {
            buf =
                ~[0x10u8 | (n >> 24u as u8), n >> 16u & 0xffu as u8,
                  n >> 8u & 0xffu as u8, n & 0xffu as u8];
        }
        case (_) { log_err "vint to write too big"; fail; }
    }
    w.write(buf);
}

fn write_vint(&ioivec::buf_writer w, uint n) {
    if (n < 0x7fu) { write_sized_vint(w, n, 1u); ret; }
    if (n < 0x4000u) { write_sized_vint(w, n, 2u); ret; }
    if (n < 0x200000u) { write_sized_vint(w, n, 3u); ret; }
    if (n < 0x10000000u) { write_sized_vint(w, n, 4u); ret; }
    log_err "vint to write too big";
    fail;
}

fn create_writer(&ioivec::buf_writer w) -> writer {
    let uint[] size_positions = ~[];
    ret rec(writer=w, mutable size_positions=size_positions);
}

// TODO: Provide a function to write the standard ebml header.
fn start_tag(&writer w, uint tag_id) {
    // Write the tag ID:

    write_vint(w.writer, tag_id);
    // Write a placeholder four-byte size.

    w.size_positions += ~[w.writer.tell()];
    let u8[] zeroes = ~[0u8, 0u8, 0u8, 0u8];
    w.writer.write(zeroes);
}

fn end_tag(&writer w) {
    auto last_size_pos = ivec::pop[uint](w.size_positions);
    auto cur_pos = w.writer.tell();
    w.writer.seek(last_size_pos as int, ioivec::seek_set);
    write_sized_vint(w.writer, cur_pos - last_size_pos - 4u, 4u);
    w.writer.seek(cur_pos as int, ioivec::seek_set);
}
// TODO: optionally perform "relaxations" on end_tag to more efficiently
// encode sizes; this is a fixed point iteration
<commit_msg>stdlib: EBML API fixes<commit_after>

// Simple Extensible Binary Markup Language (ebml) reader and writer on a
// cursor model. See the specification here:
//     http://www.matroska.org/technical/specs/rfc/index.html
import option::none;
import option::some;

type ebml_tag = rec(uint id, uint size);

type ebml_state = rec(ebml_tag ebml_tag, uint tag_pos, uint data_pos);

// TODO: When we have module renaming, make "reader" and "writer" separate
// modules within this file.

// ebml reading
type doc = rec(@u8[] data, uint start, uint end);

fn vint_at(&u8[] data, uint start) -> tup(uint, uint) {
    auto a = data.(start);
    if (a & 0x80u8 != 0u8) { ret tup(a & 0x7fu8 as uint, start + 1u); }
    if (a & 0x40u8 != 0u8) {
        ret tup((a & 0x3fu8 as uint) << 8u | (data.(start + 1u) as uint),
                start + 2u);
    } else if (a & 0x20u8 != 0u8) {
        ret tup((a & 0x1fu8 as uint) << 16u |
                    (data.(start + 1u) as uint) << 8u |
                    (data.(start + 2u) as uint), start + 3u);
    } else if (a & 0x10u8 != 0u8) {
        ret tup((a & 0x0fu8 as uint) << 24u |
                    (data.(start + 1u) as uint) << 16u |
                    (data.(start + 2u) as uint) << 8u |
                    (data.(start + 3u) as uint), start + 4u);
    } else { log_err "vint too big"; fail; }
}

fn new_doc(&@u8[] data) -> doc {
    ret rec(data=data, start=0u, end=ivec::len[u8](*data));
}

fn doc_at(&@u8[] data, uint start) -> doc {
    auto elt_tag = vint_at(*data, start);
    auto elt_size = vint_at(*data, elt_tag._1);
    auto end = elt_size._1 + elt_size._0;
    ret rec(data=data, start=elt_size._1, end=end);
}

fn maybe_get_doc(doc d, uint tg) -> option::t[doc] {
    auto pos = d.start;
    while (pos < d.end) {
        auto elt_tag = vint_at(*d.data, pos);
        auto elt_size = vint_at(*d.data, elt_tag._1);
        pos = elt_size._1 + elt_size._0;
        if (elt_tag._0 == tg) {
            ret some[doc](rec(data=d.data, start=elt_size._1, end=pos));
        }
    }
    ret none[doc];
}

fn get_doc(doc d, uint tg) -> doc {
    alt (maybe_get_doc(d, tg)) {
        case (some(?d)) { ret d; }
        case (none) {
            log_err "failed to find block with tag " + uint::to_str(tg, 10u);
            fail;
        }
    }
}

iter docs(doc d) -> tup(uint, doc) {
    auto pos = d.start;
    while (pos < d.end) {
        auto elt_tag = vint_at(*d.data, pos);
        auto elt_size = vint_at(*d.data, elt_tag._1);
        pos = elt_size._1 + elt_size._0;
        put tup(elt_tag._0, rec(data=d.data, start=elt_size._1, end=pos));
    }
}

iter tagged_docs(doc d, uint tg) -> doc {
    auto pos = d.start;
    while (pos < d.end) {
        auto elt_tag = vint_at(*d.data, pos);
        auto elt_size = vint_at(*d.data, elt_tag._1);
        pos = elt_size._1 + elt_size._0;
        if (elt_tag._0 == tg) {
            put rec(data=d.data, start=elt_size._1, end=pos);
        }
    }
}

fn doc_data(doc d) -> u8[] { ret ivec::slice[u8](*d.data, d.start, d.end); }

fn be_uint_from_bytes(&@u8[] data, uint start, uint size) -> uint {
    auto sz = size;
    assert (sz <= 4u);
    auto val = 0u;
    auto pos = start;
    while (sz > 0u) {
        sz -= 1u;
        val += (data.(pos) as uint) << sz * 8u;
        pos += 1u;
    }
    ret val;
}

fn doc_as_uint(doc d) -> uint {
    ret be_uint_from_bytes(d.data, d.start, d.end - d.start);
}

// ebml writing
type writer = rec(ioivec::buf_writer writer, mutable uint[] size_positions);

fn write_sized_vint(&ioivec::buf_writer w, uint n, uint size) {
    let u8[] buf;
    alt (size) {
        case (1u) { buf = ~[0x80u8 | (n as u8)]; }
        case (2u) { buf = ~[0x40u8 | (n >> 8u as u8), n & 0xffu as u8]; }
        case (3u) {
            buf =
                ~[0x20u8 | (n >> 16u as u8), n >> 8u & 0xffu as u8,
                  n & 0xffu as u8];
        }
        case (4u) {
            buf =
                ~[0x10u8 | (n >> 24u as u8), n >> 16u & 0xffu as u8,
                  n >> 8u & 0xffu as u8, n & 0xffu as u8];
        }
        case (_) { log_err "vint to write too big"; fail; }
    }
    w.write(buf);
}

fn write_vint(&ioivec::buf_writer w, uint n) {
    if (n < 0x7fu) { write_sized_vint(w, n, 1u); ret; }
    if (n < 0x4000u) { write_sized_vint(w, n, 2u); ret; }
    if (n < 0x200000u) { write_sized_vint(w, n, 3u); ret; }
    if (n < 0x10000000u) { write_sized_vint(w, n, 4u); ret; }
    log_err "vint to write too big";
    fail;
}

fn create_writer(&ioivec::buf_writer w) -> writer {
    let uint[] size_positions = ~[];
    ret rec(writer=w, mutable size_positions=size_positions);
}

// TODO: Provide a function to write the standard ebml header.
fn start_tag(&writer w, uint tag_id) {
    // Write the tag ID:

    write_vint(w.writer, tag_id);
    // Write a placeholder four-byte size.

    w.size_positions += ~[w.writer.tell()];
    let u8[] zeroes = ~[0u8, 0u8, 0u8, 0u8];
    w.writer.write(zeroes);
}

fn end_tag(&writer w) {
    auto last_size_pos = ivec::pop[uint](w.size_positions);
    auto cur_pos = w.writer.tell();
    w.writer.seek(last_size_pos as int, ioivec::seek_set);
    write_sized_vint(w.writer, cur_pos - last_size_pos - 4u, 4u);
    w.writer.seek(cur_pos as int, ioivec::seek_set);
}
// TODO: optionally perform "relaxations" on end_tag to more efficiently
// encode sizes; this is a fixed point iteration
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! # The Rust core allocation library
//!
//! This is the lowest level library through which allocation in Rust can be
//! performed.
//!
//! This library, like libcore, is not intended for general usage, but rather as
//! a building block of other libraries. The types and interfaces in this
//! library are reexported through the [standard library](../std/index.html),
//! and should not be used through this library.
//!
//! Currently, there are four major definitions in this library.
//!
//! ## Boxed values
//!
//! The [`Box`](boxed/index.html) type is a smart pointer type. There can
//! only be one owner of a `Box`, and the owner can decide to mutate the
//! contents, which live on the heap.
//!
//! This type can be sent among threads efficiently as the size of a `Box` value
//! is the same as that of a pointer. Tree-like data structures are often built
//! with boxes because each node often has only one owner, the parent.
//!
//! ## Reference counted pointers
//!
//! The [`Rc`](rc/index.html) type is a non-threadsafe reference-counted pointer
//! type intended for sharing memory within a thread. An `Rc` pointer wraps a
//! type, `T`, and only allows access to `&T`, a shared reference.
//!
//! This type is useful when inherited mutability (such as using `Box`) is too
//! constraining for an application, and is often paired with the `Cell` or
//! `RefCell` types in order to allow mutation.
//!
//! ## Atomically reference counted pointers
//!
//! The [`Arc`](arc/index.html) type is the threadsafe equivalent of the `Rc`
//! type. It provides all the same functionality of `Rc`, except it requires
//! that the contained type `T` is shareable. Additionally, `Arc<T>` is itself
//! sendable while `Rc<T>` is not.
//!
//! This types allows for shared access to the contained data, and is often
//! paired with synchronization primitives such as mutexes to allow mutation of
//! shared resources.
//!
//! ## Heap interfaces
//!
//! The [`heap`](heap/index.html) module defines the low-level interface to the
//! default global allocator. It is not compatible with the libc allocator API.

// Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364)
#![cfg_attr(stage0, feature(custom_attribute))]
#![crate_name = "alloc"]
#![crate_type = "rlib"]
#![staged_api]
#![unstable(feature = "alloc",
            reason = "this library is unlikely to be stabilized in its current \
                      form or name")]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/nightly/",
       test(no_crate_inject))]
#![no_std]

#![feature(allocator)]
#![feature(box_syntax)]
#![feature(coerce_unsized)]
#![feature(core)]
#![feature(core_intrinsics)]
#![feature(core_prelude)]
#![feature(custom_attribute)]
#![feature(fundamental)]
#![feature(lang_items)]
#![feature(no_std)]
#![feature(nonzero)]
#![feature(optin_builtin_traits)]
#![feature(placement_in_syntax)]
#![feature(raw)]
#![feature(staged_api)]
#![feature(placement_in_syntax)]
#![feature(unboxed_closures)]
#![feature(unique)]
#![feature(unsafe_no_drop_flag, filling_drop)]
#![feature(unsize)]
#![feature(core_slice_ext)]

#![cfg_attr(test, feature(test, alloc, rustc_private, box_raw))]
#![cfg_attr(all(not(feature = "external_funcs"), not(feature = "external_crate")),
            feature(libc))]

#[macro_use]
extern crate core;

#[cfg(all(not(feature = "external_funcs"), not(feature = "external_crate")))]
extern crate libc;

// Allow testing this library

#[cfg(test)] #[macro_use] extern crate std;
#[cfg(test)] #[macro_use] extern crate log;

// Heaps provided for low-level allocation strategies

pub mod heap;

// Primitive types using the heaps above

// Need to conditionally define the mod from `boxed.rs` to avoid
// duplicating the lang-items when building in test cfg; but also need
// to allow code to have `use boxed::HEAP;`
// and `use boxed::Box;` declarations.
#[cfg(not(test))]
pub mod boxed;
#[cfg(test)]
mod boxed { pub use std::boxed::{Box, HEAP}; }
#[cfg(test)]
mod boxed_test;
pub mod arc;
pub mod rc;
pub mod raw_vec;

/// Common out-of-memory routine
#[cold]
#[inline(never)]
#[unstable(feature = "oom", reason = "not a scrutinized interface")]
pub fn oom() -> ! {
    // FIXME(#14674): This really needs to do something other than just abort
    //                here, but any printing done must be *guaranteed* to not
    //                allocate.
    unsafe { core::intrinsics::abort() }
}
<commit_msg>address review feedback: remove dupe feature opt-in.<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! # The Rust core allocation library
//!
//! This is the lowest level library through which allocation in Rust can be
//! performed.
//!
//! This library, like libcore, is not intended for general usage, but rather as
//! a building block of other libraries. The types and interfaces in this
//! library are reexported through the [standard library](../std/index.html),
//! and should not be used through this library.
//!
//! Currently, there are four major definitions in this library.
//!
//! ## Boxed values
//!
//! The [`Box`](boxed/index.html) type is a smart pointer type. There can
//! only be one owner of a `Box`, and the owner can decide to mutate the
//! contents, which live on the heap.
//!
//! This type can be sent among threads efficiently as the size of a `Box` value
//! is the same as that of a pointer. Tree-like data structures are often built
//! with boxes because each node often has only one owner, the parent.
//!
//! ## Reference counted pointers
//!
//! The [`Rc`](rc/index.html) type is a non-threadsafe reference-counted pointer
//! type intended for sharing memory within a thread. An `Rc` pointer wraps a
//! type, `T`, and only allows access to `&T`, a shared reference.
//!
//! This type is useful when inherited mutability (such as using `Box`) is too
//! constraining for an application, and is often paired with the `Cell` or
//! `RefCell` types in order to allow mutation.
//!
//! ## Atomically reference counted pointers
//!
//! The [`Arc`](arc/index.html) type is the threadsafe equivalent of the `Rc`
//! type. It provides all the same functionality of `Rc`, except it requires
//! that the contained type `T` is shareable. Additionally, `Arc<T>` is itself
//! sendable while `Rc<T>` is not.
//!
//! This types allows for shared access to the contained data, and is often
//! paired with synchronization primitives such as mutexes to allow mutation of
//! shared resources.
//!
//! ## Heap interfaces
//!
//! The [`heap`](heap/index.html) module defines the low-level interface to the
//! default global allocator. It is not compatible with the libc allocator API.

// Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364)
#![cfg_attr(stage0, feature(custom_attribute))]
#![crate_name = "alloc"]
#![crate_type = "rlib"]
#![staged_api]
#![unstable(feature = "alloc",
            reason = "this library is unlikely to be stabilized in its current \
                      form or name")]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/nightly/",
       test(no_crate_inject))]
#![no_std]

#![feature(allocator)]
#![feature(box_syntax)]
#![feature(coerce_unsized)]
#![feature(core)]
#![feature(core_intrinsics)]
#![feature(core_prelude)]
#![feature(custom_attribute)]
#![feature(fundamental)]
#![feature(lang_items)]
#![feature(no_std)]
#![feature(nonzero)]
#![feature(optin_builtin_traits)]
#![feature(placement_in_syntax)]
#![feature(raw)]
#![feature(staged_api)]
#![feature(unboxed_closures)]
#![feature(unique)]
#![feature(unsafe_no_drop_flag, filling_drop)]
#![feature(unsize)]
#![feature(core_slice_ext)]

#![cfg_attr(test, feature(test, alloc, rustc_private, box_raw))]
#![cfg_attr(all(not(feature = "external_funcs"), not(feature = "external_crate")),
            feature(libc))]

#[macro_use]
extern crate core;

#[cfg(all(not(feature = "external_funcs"), not(feature = "external_crate")))]
extern crate libc;

// Allow testing this library

#[cfg(test)] #[macro_use] extern crate std;
#[cfg(test)] #[macro_use] extern crate log;

// Heaps provided for low-level allocation strategies

pub mod heap;

// Primitive types using the heaps above

// Need to conditionally define the mod from `boxed.rs` to avoid
// duplicating the lang-items when building in test cfg; but also need
// to allow code to have `use boxed::HEAP;`
// and `use boxed::Box;` declarations.
#[cfg(not(test))]
pub mod boxed;
#[cfg(test)]
mod boxed { pub use std::boxed::{Box, HEAP}; }
#[cfg(test)]
mod boxed_test;
pub mod arc;
pub mod rc;
pub mod raw_vec;

/// Common out-of-memory routine
#[cold]
#[inline(never)]
#[unstable(feature = "oom", reason = "not a scrutinized interface")]
pub fn oom() -> ! {
    // FIXME(#14674): This really needs to do something other than just abort
    //                here, but any printing done must be *guaranteed* to not
    //                allocate.
    unsafe { core::intrinsics::abort() }
}
<|endoftext|>