<commit_before>use std::cmp::max;
use std::collections::VecDeque;

use futures::{Future, Stream, Poll, Async};

use telegram_bot_raw::{GetUpdates, Update, Integer};

use api::{Api, TelegramFuture};
use errors::{Error};

const TELEGRAM_LONG_POLL_TIMEOUT: usize = 5;

#[must_use = "streams do nothing unless polled"]
pub struct UpdatesStream {
    api: Api,
    last_update: Integer,
    buffer: VecDeque<Update>,
    current_request: Option<TelegramFuture<Vec<Update>>>,
    timeout: usize,
}

impl Stream for UpdatesStream {
    type Item = Update;
    type Error = Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        if let Some(value) = self.buffer.pop_front() {
            return Ok(Async::Ready(Some(value)))
        }

        let result = match self.current_request {
            None => None,
            Some(ref mut current_request) => {
                let polled_update = current_request.poll();
                match polled_update {
                    Ok(Async::NotReady) => return Ok(Async::NotReady),
                    Ok(Async::Ready(updates)) => {
                        if updates.is_empty() {
                            None
                        } else {
                            for update in updates.iter() {
                                self.last_update = max(update.id, self.last_update);
                            }
                            Some(updates)
                        }
                    },
                    Err(err) => return Err(err)
                }
            }
        };

        match result {
            None => {
                let request = self.api.send(GetUpdates {
                    offset: Some(self.last_update + 1),
                    limit: None,
                    timeout: Some(self.timeout as Integer),
                    allowed_updates: Vec::new(),
                });

                self.current_request = Some(request);
                self.poll()
            },
            Some(mut updates) => {
                self.current_request = None;
                // Updates are guarantied to be not empty
                self.buffer.extend(updates.drain(1..));
                let result = updates.pop().unwrap();
                return Ok(Async::Ready(Some(result)))
            }
        }
    }
}

impl UpdatesStream {
    pub fn new(api: &Api) -> Self {
        UpdatesStream {
            api: api.clone(),
            last_update: 0,
            buffer: VecDeque::new(),
            current_request: None,
            timeout: TELEGRAM_LONG_POLL_TIMEOUT,
        }
    }
}<commit_msg>feat: add UpdatesStream::timeout method<commit_after>use std::cmp::max;
use std::collections::VecDeque;

use futures::{Future, Stream, Poll, Async};

use telegram_bot_raw::{GetUpdates, Update, Integer};

use api::{Api, TelegramFuture};
use errors::{Error};

const TELEGRAM_LONG_POLL_TIMEOUT: usize = 5;

#[must_use = "streams do nothing unless polled"]
pub struct UpdatesStream {
    api: Api,
    last_update: Integer,
    buffer: VecDeque<Update>,
    current_request: Option<TelegramFuture<Vec<Update>>>,
    timeout: usize,
}

impl Stream for UpdatesStream {
    type Item = Update;
    type Error = Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        if let Some(value) = self.buffer.pop_front() {
            return Ok(Async::Ready(Some(value)))
        }

        let result = match self.current_request {
            None => None,
            Some(ref mut current_request) => {
                let polled_update = current_request.poll();
                match polled_update {
                    Ok(Async::NotReady) => return Ok(Async::NotReady),
                    Ok(Async::Ready(updates)) => {
                        if updates.is_empty() {
                            None
                        } else {
                            for update in updates.iter() {
                                self.last_update = max(update.id, self.last_update);
                            }
                            Some(updates)
                        }
                    },
                    Err(err) => return Err(err)
                }
            }
        };

        match result {
            None => {
                let request = self.api.send(GetUpdates {
                    offset: Some(self.last_update + 1),
                    limit: None,
                    timeout: Some(self.timeout as Integer),
                    allowed_updates: Vec::new(),
                });

                self.current_request = Some(request);
                self.poll()
            },
            Some(mut updates) => {
                self.current_request = None;
                // Updates are guarantied to be not empty
                self.buffer.extend(updates.drain(1..));
                let result = updates.pop().unwrap();
                return Ok(Async::Ready(Some(result)))
            }
        }
    }
}

impl UpdatesStream {
    pub fn new(api: &Api) -> Self {
        UpdatesStream {
            api: api.clone(),
            last_update: 0,
            buffer: VecDeque::new(),
            current_request: None,
            timeout: TELEGRAM_LONG_POLL_TIMEOUT,
        }
    }

    pub fn timeout(&mut self, timeout: usize) -> &mut Self {
        self.timeout = timeout;
        self
    }
}
<|endoftext|>


<commit_before>mod atom;

use super::*;
pub(super) use self::atom::literal;

const EXPR_FIRST: TokenSet = LHS_FIRST;

pub(super) fn expr(p: &mut Parser) {
    let r = Restrictions { forbid_structs: false };
    expr_bp(p, r, 1)
}

fn expr_no_struct(p: &mut Parser) {
    let r = Restrictions { forbid_structs: true };
    expr_bp(p, r, 1)
}

// test block
// fn a() {}
// fn b() { let _ = 1; }
// fn c() { 1; 2; }
// fn d() { 1; 2 }
pub(super) fn block(p: &mut Parser) {
    if !p.at(L_CURLY) {
        p.error("expected block");
        return;
    }
    atom::block_expr(p);
}

#[derive(Clone, Copy)]
struct Restrictions {
    forbid_structs: bool
}

enum Op {
    Simple,
    Composite(SyntaxKind, u8),
}

fn current_op(p: &Parser) -> (u8, Op) {
    if p.at_compound2(PLUS, EQ) {
        return (1, Op::Composite(PLUSEQ, 2));
    }
    if p.at_compound2(MINUS, EQ) {
        return (1, Op::Composite(MINUSEQ, 2));
    }
    if p.at_compound3(L_ANGLE, L_ANGLE, EQ) {
        return (1, Op::Composite(SHLEQ, 3));
    }
    if p.at_compound3(R_ANGLE, R_ANGLE, EQ) {
        return (1, Op::Composite(SHREQ, 3));
    }
    if p.at_compound2(PIPE, PIPE) {
        return (3, Op::Composite(PIPEPIPE, 2));
    }
    if p.at_compound2(AMP, AMP) {
        return (4, Op::Composite(AMPAMP, 2));
    }
    if p.at_compound2(L_ANGLE, EQ) {
        return (5, Op::Composite(LTEQ, 2));
    }
    if p.at_compound2(R_ANGLE, EQ) {
        return (5, Op::Composite(GTEQ, 2));
    }
    if p.at_compound2(L_ANGLE, L_ANGLE) {
        return (9, Op::Composite(SHL, 2));
    }
    if p.at_compound2(R_ANGLE, R_ANGLE) {
        return (9, Op::Composite(SHR, 2));
    }

    let bp = match p.current() {
        EQ => 1,
        DOTDOT => 2,
        EQEQ | NEQ => 5,
        PIPE => 6,
        CARET => 7,
        AMP => 8,
        MINUS | PLUS => 10,
        STAR | SLASH | PERCENT => 11,
        _ => 0,
    };
    (bp, Op::Simple)
}

// Parses expression with binding power of at least bp.
fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) {
    let mut lhs = match lhs(p, r) {
        Some(lhs) => lhs,
        None => return,
    };

    loop {
        let (op_bp, op) = current_op(p);
        if op_bp < bp {
            break;
        }
        match op {
            Op::Simple => p.bump(),
            Op::Composite(kind, n) => {
                p.bump_compound(kind, n);
            }
        }
        lhs = bin_expr(p, r, lhs, op_bp + 1);
    }
}

const LHS_FIRST: TokenSet =
    token_set_union![
        token_set![AMP, STAR, EXCL, DOTDOT, MINUS],
        atom::ATOM_EXPR_FIRST,
    ];

fn lhs(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> {
    let m;
    let kind = match p.current() {
        // test ref_expr
        // fn foo() {
        //     let _ = &1;
        //     let _ = &mut &f();
        // }
        AMP => {
            m = p.start();
            p.bump();
            p.eat(MUT_KW);
            REF_EXPR
        }
        // test deref_expr
        // fn foo() {
        //     **&1;
        // }
        STAR => {
            m = p.start();
            p.bump();
            DEREF_EXPR
        }
        // test not_expr
        // fn foo() {
        //     !!true;
        // }
        EXCL => {
            m = p.start();
            p.bump();
            NOT_EXPR
        }
        // test neg_expr
        // fn foo() {
        //     --1;
        // }
        MINUS => {
            m = p.start();
            p.bump();
            NEG_EXPR
        }
        DOTDOT => {
            m = p.start();
            p.bump();
            expr_bp(p, r, 2);
            return Some(m.complete(p, RANGE_EXPR));
        }
        _ => {
            let lhs = atom::atom_expr(p, r)?;
            return Some(postfix_expr(p, lhs));
        }
    };
    expr_bp(p, r, 255);
    Some(m.complete(p, kind))
}

fn postfix_expr(p: &mut Parser, mut lhs: CompletedMarker) -> CompletedMarker {
    loop {
        lhs = match p.current() {
            L_PAREN => call_expr(p, lhs),
            L_BRACK => index_expr(p, lhs),
            DOT if p.nth(1) == IDENT => if p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON {
                method_call_expr(p, lhs)
            } else {
                field_expr(p, lhs)
            },
            DOT if p.nth(1) == INT_NUMBER => field_expr(p, lhs),
            // test postfix_range
            // fn foo() { let x = 1..; }
            DOTDOT if !EXPR_FIRST.contains(p.nth(1)) => {
                let m = lhs.precede(p);
                p.bump();
                m.complete(p, RANGE_EXPR)
            }
            QUESTION => try_expr(p, lhs),
            AS_KW => cast_expr(p, lhs),
            _ => break,
        }
    }
    lhs
}

// test call_expr
// fn foo() {
//     let _ = f();
//     let _ = f()(1)(1, 2,);
// }
fn call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
    assert!(p.at(L_PAREN));
    let m = lhs.precede(p);
    arg_list(p);
    m.complete(p, CALL_EXPR)
}

// test index_expr
// fn foo() {
//     x[1][2];
// }
fn index_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
    assert!(p.at(L_BRACK));
    let m = lhs.precede(p);
    p.bump();
    expr(p);
    p.expect(R_BRACK);
    m.complete(p, INDEX_EXPR)
}

// test method_call_expr
// fn foo() {
//     x.foo();
//     y.bar::<T>(1, 2,);
// }
fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
    assert!(
        p.at(DOT) && p.nth(1) == IDENT
            && (p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON)
    );
    let m = lhs.precede(p);
    p.bump();
    name_ref(p);
    type_args::type_arg_list(p, true);
    arg_list(p);
    m.complete(p, METHOD_CALL_EXPR)
}

// test field_expr
// fn foo() {
//     x.foo;
//     x.0.bar;
// }
fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
    assert!(p.at(DOT) && (p.nth(1) == IDENT || p.nth(1) == INT_NUMBER));
    let m = lhs.precede(p);
    p.bump();
    if p.at(IDENT) {
        name_ref(p)
    } else {
        p.bump()
    }
    m.complete(p, FIELD_EXPR)
}

// test try_expr
// fn foo() {
//     x?;
// }
fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
    assert!(p.at(QUESTION));
    let m = lhs.precede(p);
    p.bump();
    m.complete(p, TRY_EXPR)
}

// test cast_expr
// fn foo() {
//     82 as i32;
// }
fn cast_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
    assert!(p.at(AS_KW));
    let m = lhs.precede(p);
    p.bump();
    types::type_(p);
    m.complete(p, CAST_EXPR)
}

fn arg_list(p: &mut Parser) {
    assert!(p.at(L_PAREN));
    let m = p.start();
    p.bump();
    while !p.at(R_PAREN) && !p.at(EOF) {
        expr(p);
        if !p.at(R_PAREN) && !p.expect(COMMA) {
            break;
        }
    }
    p.eat(R_PAREN);
    m.complete(p, ARG_LIST);
}

// test path_expr
// fn foo() {
//     let _ = a;
//     let _ = a::b;
//     let _ = ::a::<b>;
//     let _ = format!();
// }
fn path_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker {
    assert!(paths::is_path_start(p));
    let m = p.start();
    paths::expr_path(p);
    match p.current() {
        L_CURLY if !r.forbid_structs => {
            struct_lit(p);
            m.complete(p, STRUCT_LIT)
        }
        EXCL => {
            items::macro_call_after_excl(p);
            m.complete(p, MACRO_CALL)
        }
        _ => m.complete(p, PATH_EXPR)
    }
}

// test struct_lit
// fn foo() {
//     S {};
//     S { x, y: 32, };
//     S { x, y: 32, ..Default::default() };
// }
fn struct_lit(p: &mut Parser) {
    assert!(p.at(L_CURLY));
    p.bump();
    while !p.at(EOF) && !p.at(R_CURLY) {
        match p.current() {
            IDENT => {
                let m = p.start();
                name_ref(p);
                if p.eat(COLON) {
                    expr(p);
                }
                m.complete(p, STRUCT_LIT_FIELD);
            }
            DOTDOT => {
                p.bump();
                expr(p);
            }
            _ => p.err_and_bump("expected identifier"),
        }
        if !p.at(R_CURLY) {
            p.expect(COMMA);
        }
    }
    p.expect(R_CURLY);
}

fn bin_expr(p: &mut Parser, r: Restrictions, lhs: CompletedMarker, bp: u8) -> CompletedMarker {
    let m = lhs.precede(p);
    expr_bp(p, r, bp);
    m.complete(p, BIN_EXPR)
}
<commit_msg>comparison ops<commit_after>mod atom;

use super::*;
pub(super) use self::atom::literal;

const EXPR_FIRST: TokenSet = LHS_FIRST;

pub(super) fn expr(p: &mut Parser) {
    let r = Restrictions { forbid_structs: false };
    expr_bp(p, r, 1)
}

fn expr_no_struct(p: &mut Parser) {
    let r = Restrictions { forbid_structs: true };
    expr_bp(p, r, 1)
}

// test block
// fn a() {}
// fn b() { let _ = 1; }
// fn c() { 1; 2; }
// fn d() { 1; 2 }
pub(super) fn block(p: &mut Parser) {
    if !p.at(L_CURLY) {
        p.error("expected block");
        return;
    }
    atom::block_expr(p);
}

#[derive(Clone, Copy)]
struct Restrictions {
    forbid_structs: bool
}

enum Op {
    Simple,
    Composite(SyntaxKind, u8),
}

fn current_op(p: &Parser) -> (u8, Op) {
    if p.at_compound2(PLUS, EQ) {
        return (1, Op::Composite(PLUSEQ, 2));
    }
    if p.at_compound2(MINUS, EQ) {
        return (1, Op::Composite(MINUSEQ, 2));
    }
    if p.at_compound3(L_ANGLE, L_ANGLE, EQ) {
        return (1, Op::Composite(SHLEQ, 3));
    }
    if p.at_compound3(R_ANGLE, R_ANGLE, EQ) {
        return (1, Op::Composite(SHREQ, 3));
    }
    if p.at_compound2(PIPE, PIPE) {
        return (3, Op::Composite(PIPEPIPE, 2));
    }
    if p.at_compound2(AMP, AMP) {
        return (4, Op::Composite(AMPAMP, 2));
    }
    if p.at_compound2(L_ANGLE, EQ) {
        return (5, Op::Composite(LTEQ, 2));
    }
    if p.at_compound2(R_ANGLE, EQ) {
        return (5, Op::Composite(GTEQ, 2));
    }
    if p.at_compound2(L_ANGLE, L_ANGLE) {
        return (9, Op::Composite(SHL, 2));
    }
    if p.at_compound2(R_ANGLE, R_ANGLE) {
        return (9, Op::Composite(SHR, 2));
    }

    let bp = match p.current() {
        EQ => 1,
        DOTDOT => 2,
        EQEQ | NEQ | L_ANGLE | R_ANGLE => 5,
        PIPE => 6,
        CARET => 7,
        AMP => 8,
        MINUS | PLUS => 10,
        STAR | SLASH | PERCENT => 11,
        _ => 0,
    };
    (bp, Op::Simple)
}

// Parses expression with binding power of at least bp.
fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) {
    let mut lhs = match lhs(p, r) {
        Some(lhs) => lhs,
        None => return,
    };

    loop {
        let (op_bp, op) = current_op(p);
        if op_bp < bp {
            break;
        }
        match op {
            Op::Simple => p.bump(),
            Op::Composite(kind, n) => {
                p.bump_compound(kind, n);
            }
        }
        lhs = bin_expr(p, r, lhs, op_bp + 1);
    }
}

const LHS_FIRST: TokenSet =
    token_set_union![
        token_set![AMP, STAR, EXCL, DOTDOT, MINUS],
        atom::ATOM_EXPR_FIRST,
    ];

fn lhs(p: &mut Parser, r: Restrictions) -> Option<CompletedMarker> {
    let m;
    let kind = match p.current() {
        // test ref_expr
        // fn foo() {
        //     let _ = &1;
        //     let _ = &mut &f();
        // }
        AMP => {
            m = p.start();
            p.bump();
            p.eat(MUT_KW);
            REF_EXPR
        }
        // test deref_expr
        // fn foo() {
        //     **&1;
        // }
        STAR => {
            m = p.start();
            p.bump();
            DEREF_EXPR
        }
        // test not_expr
        // fn foo() {
        //     !!true;
        // }
        EXCL => {
            m = p.start();
            p.bump();
            NOT_EXPR
        }
        // test neg_expr
        // fn foo() {
        //     --1;
        // }
        MINUS => {
            m = p.start();
            p.bump();
            NEG_EXPR
        }
        DOTDOT => {
            m = p.start();
            p.bump();
            expr_bp(p, r, 2);
            return Some(m.complete(p, RANGE_EXPR));
        }
        _ => {
            let lhs = atom::atom_expr(p, r)?;
            return Some(postfix_expr(p, lhs));
        }
    };
    expr_bp(p, r, 255);
    Some(m.complete(p, kind))
}

fn postfix_expr(p: &mut Parser, mut lhs: CompletedMarker) -> CompletedMarker {
    loop {
        lhs = match p.current() {
            L_PAREN => call_expr(p, lhs),
            L_BRACK => index_expr(p, lhs),
            DOT if p.nth(1) == IDENT => if p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON {
                method_call_expr(p, lhs)
            } else {
                field_expr(p, lhs)
            },
            DOT if p.nth(1) == INT_NUMBER => field_expr(p, lhs),
            // test postfix_range
            // fn foo() { let x = 1..; }
            DOTDOT if !EXPR_FIRST.contains(p.nth(1)) => {
                let m = lhs.precede(p);
                p.bump();
                m.complete(p, RANGE_EXPR)
            }
            QUESTION => try_expr(p, lhs),
            AS_KW => cast_expr(p, lhs),
            _ => break,
        }
    }
    lhs
}

// test call_expr
// fn foo() {
//     let _ = f();
//     let _ = f()(1)(1, 2,);
// }
fn call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
    assert!(p.at(L_PAREN));
    let m = lhs.precede(p);
    arg_list(p);
    m.complete(p, CALL_EXPR)
}

// test index_expr
// fn foo() {
//     x[1][2];
// }
fn index_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
    assert!(p.at(L_BRACK));
    let m = lhs.precede(p);
    p.bump();
    expr(p);
    p.expect(R_BRACK);
    m.complete(p, INDEX_EXPR)
}

// test method_call_expr
// fn foo() {
//     x.foo();
//     y.bar::<T>(1, 2,);
// }
fn method_call_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
    assert!(
        p.at(DOT) && p.nth(1) == IDENT
            && (p.nth(2) == L_PAREN || p.nth(2) == COLONCOLON)
    );
    let m = lhs.precede(p);
    p.bump();
    name_ref(p);
    type_args::type_arg_list(p, true);
    arg_list(p);
    m.complete(p, METHOD_CALL_EXPR)
}

// test field_expr
// fn foo() {
//     x.foo;
//     x.0.bar;
// }
fn field_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
    assert!(p.at(DOT) && (p.nth(1) == IDENT || p.nth(1) == INT_NUMBER));
    let m = lhs.precede(p);
    p.bump();
    if p.at(IDENT) {
        name_ref(p)
    } else {
        p.bump()
    }
    m.complete(p, FIELD_EXPR)
}

// test try_expr
// fn foo() {
//     x?;
// }
fn try_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
    assert!(p.at(QUESTION));
    let m = lhs.precede(p);
    p.bump();
    m.complete(p, TRY_EXPR)
}

// test cast_expr
// fn foo() {
//     82 as i32;
// }
fn cast_expr(p: &mut Parser, lhs: CompletedMarker) -> CompletedMarker {
    assert!(p.at(AS_KW));
    let m = lhs.precede(p);
    p.bump();
    types::type_(p);
    m.complete(p, CAST_EXPR)
}

fn arg_list(p: &mut Parser) {
    assert!(p.at(L_PAREN));
    let m = p.start();
    p.bump();
    while !p.at(R_PAREN) && !p.at(EOF) {
        expr(p);
        if !p.at(R_PAREN) && !p.expect(COMMA) {
            break;
        }
    }
    p.eat(R_PAREN);
    m.complete(p, ARG_LIST);
}

// test path_expr
// fn foo() {
//     let _ = a;
//     let _ = a::b;
//     let _ = ::a::<b>;
//     let _ = format!();
// }
fn path_expr(p: &mut Parser, r: Restrictions) -> CompletedMarker {
    assert!(paths::is_path_start(p));
    let m = p.start();
    paths::expr_path(p);
    match p.current() {
        L_CURLY if !r.forbid_structs => {
            struct_lit(p);
            m.complete(p, STRUCT_LIT)
        }
        EXCL => {
            items::macro_call_after_excl(p);
            m.complete(p, MACRO_CALL)
        }
        _ => m.complete(p, PATH_EXPR)
    }
}

// test struct_lit
// fn foo() {
//     S {};
//     S { x, y: 32, };
//     S { x, y: 32, ..Default::default() };
// }
fn struct_lit(p: &mut Parser) {
    assert!(p.at(L_CURLY));
    p.bump();
    while !p.at(EOF) && !p.at(R_CURLY) {
        match p.current() {
            IDENT => {
                let m = p.start();
                name_ref(p);
                if p.eat(COLON) {
                    expr(p);
                }
                m.complete(p, STRUCT_LIT_FIELD);
            }
            DOTDOT => {
                p.bump();
                expr(p);
            }
            _ => p.err_and_bump("expected identifier"),
        }
        if !p.at(R_CURLY) {
            p.expect(COMMA);
        }
    }
    p.expect(R_CURLY);
}

fn bin_expr(p: &mut Parser, r: Restrictions, lhs: CompletedMarker, bp: u8) -> CompletedMarker {
    let m = lhs.precede(p);
    expr_bp(p, r, bp);
    m.complete(p, BIN_EXPR)
}
<|endoftext|>


<commit_before>// Copyright 2018 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.

use session::config::Options;

use std::fs;
use std::io::{self, StdoutLock, Write};
use std::time::{Duration, Instant};

macro_rules! define_categories {
    ($($name:ident,)*) => {
        #[derive(Clone, Copy, Debug, PartialEq, Eq)]
        pub enum ProfileCategory {
            $($name),*
        }

        #[allow(nonstandard_style)]
        struct Categories<T> {
            $($name: T),*
        }

        impl<T: Default> Categories<T> {
            fn new() -> Categories<T> {
                Categories {
                    $($name: T::default()),*
                }
            }
        }

        impl<T> Categories<T> {
            fn get(&self, category: ProfileCategory) -> &T {
                match category {
                    $(ProfileCategory::$name => &self.$name),*
                }
            }

            fn set(&mut self, category: ProfileCategory, value: T) {
                match category {
                    $(ProfileCategory::$name => self.$name = value),*
                }
            }
        }

        struct CategoryData {
            times: Categories<u64>,
            query_counts: Categories<(u64, u64)>,
        }

        impl CategoryData {
            fn new() -> CategoryData {
                CategoryData {
                    times: Categories::new(),
                    query_counts: Categories::new(),
                }
            }

            fn print(&self, lock: &mut StdoutLock<'_>) {
                writeln!(lock, "| Phase            | Time (ms)      | Queries        | Hits (%) |")
                    .unwrap();
                writeln!(lock, "| ---------------- | -------------- | -------------- | -------- |")
                    .unwrap();

                $(
                    let (hits, total) = self.query_counts.$name;
                    let (hits, total) = if total > 0 {
                        (format!("{:.2}",
                        (((hits as f32) / (total as f32)) * 100.0)), total.to_string())
                    } else {
                        (String::new(), String::new())
                    };

                    writeln!(
                        lock,
                        "| {0: <16} | {1: <14} | {2: <14} | {3: <8} |",
                        stringify!($name),
                        self.times.$name / 1_000_000,
                        total,
                        hits
                    ).unwrap();
                )*
            }

            fn json(&self) -> String {
                let mut json = String::from("[");

                $(
                    let (hits, total) = self.query_counts.$name;

                    //normalize hits to 0%
                    let hit_percent =
                        if total > 0 {
                            ((hits as f32) / (total as f32)) * 100.0
                        } else {
                            0.0
                        };

                    json.push_str(&format!(
                        "{{ \"category\": \"{}\", \"time_ms\": {},\
                            \"query_count\": {}, \"query_hits\": {} }},",
                        stringify!($name),
                        self.times.$name / 1_000_000,
                        total,
                        format!("{:.2}", hit_percent)
                    ));
                )*

                //remove the trailing ',' character
                json.pop();

                json.push(']');

                json
            }
        }
    }
}

define_categories! {
    Parsing,
    Expansion,
    TypeChecking,
    BorrowChecking,
    Codegen,
    Linking,
    Other,
}

pub struct SelfProfiler {
    timer_stack: Vec<ProfileCategory>,
    data: CategoryData,
    current_timer: Instant,
}

impl SelfProfiler {
    pub fn new() -> SelfProfiler {
        let mut profiler = SelfProfiler {
            timer_stack: Vec::new(),
            data: CategoryData::new(),
            current_timer: Instant::now(),
        };

        profiler.start_activity(ProfileCategory::Other);

        profiler
    }

    pub fn start_activity(&mut self, category: ProfileCategory) {
        match self.timer_stack.last().cloned() {
            None => {
                self.current_timer = Instant::now();
            },
            Some(current_category) if current_category == category => {
                //since the current category is the same as the new activity's category,
                //we don't need to do anything with the timer, we just need to push it on the stack
            }
            Some(current_category) => {
                let elapsed = self.stop_timer();

                //record the current category's time
                let new_time = self.data.times.get(current_category) + elapsed;
                self.data.times.set(current_category, new_time);
            }
        }

        //push the new category
        self.timer_stack.push(category);
    }

    pub fn record_query(&mut self, category: ProfileCategory) {
        let (hits, total) = *self.data.query_counts.get(category);
        self.data.query_counts.set(category, (hits, total + 1));
    }

    pub fn record_query_hit(&mut self, category: ProfileCategory) {
        let (hits, total) = *self.data.query_counts.get(category);
        self.data.query_counts.set(category, (hits + 1, total));
    }

    pub fn end_activity(&mut self, category: ProfileCategory) {
        match self.timer_stack.pop() {
            None => bug!("end_activity() was called but there was no running activity"),
            Some(c) =>
                assert!(
                    c == category,
                    "end_activity() was called but a different activity was running"),
        }

        //check if the new running timer is in the same category as this one
        //if it is, we don't need to do anything
        if let Some(c) = self.timer_stack.last() {
            if *c == category {
                return;
            }
        }

        //the new timer is different than the previous,
        //so record the elapsed time and start a new timer
        let elapsed = self.stop_timer();
        let new_time = self.data.times.get(category) + elapsed;
        self.data.times.set(category, new_time);
    }

    fn stop_timer(&mut self) -> u64 {
        let elapsed = if cfg!(windows) {
            // On Windows, timers don't always appear to be monotonic (see #51648)
            // which can lead to panics when calculating elapsed time.
            // Work around this by testing to see if the current time is less than
            // our recorded time, and if it is, just returning 0.
            let now = Instant::now();
            if self.current_timer >= now {
                Duration::new(0, 0)
            } else {
                self.current_timer.elapsed()
            }
        } else {
            self.current_timer.elapsed()
        };

        self.current_timer = Instant::now();

        (elapsed.as_secs() * 1_000_000_000) + (elapsed.subsec_nanos() as u64)
    }

    pub fn print_results(&mut self, opts: &Options) {
        self.end_activity(ProfileCategory::Other);

        assert!(
            self.timer_stack.is_empty(),
            "there were timers running when print_results() was called");

        let out = io::stdout();
        let mut lock = out.lock();

        let crate_name =
            opts.crate_name
            .as_ref()
            .map(|n| format!(" for {}", n))
            .unwrap_or_default();

        writeln!(lock, "Self profiling results{}:", crate_name).unwrap();
        writeln!(lock).unwrap();

        self.data.print(&mut lock);

        writeln!(lock).unwrap();
        writeln!(lock, "Optimization level: {:?}", opts.optimize).unwrap();

        let incremental = if opts.incremental.is_some() { "on" } else { "off" };
        writeln!(lock, "Incremental: {}", incremental).unwrap();
    }

    pub fn save_results(&self, opts: &Options) {
        let category_data = self.data.json();
        let compilation_options =
            format!("{{ \"optimization_level\": \"{:?}\", \"incremental\": {} }}",
                    opts.optimize,
                    if opts.incremental.is_some() { "true" } else { "false" });

        let json = format!("{{ \"category_data\": {}, \"compilation_options\": {} }}",
                        category_data,
                        compilation_options);

        fs::write("self_profiler_results.json", json).unwrap();
    }
}
<commit_msg>Send textual profile data to stderr, not stdout<commit_after>// Copyright 2018 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.

use session::config::Options;

use std::fs;
use std::io::{self, StderrLock, Write};
use std::time::{Duration, Instant};

macro_rules! define_categories {
    ($($name:ident,)*) => {
        #[derive(Clone, Copy, Debug, PartialEq, Eq)]
        pub enum ProfileCategory {
            $($name),*
        }

        #[allow(nonstandard_style)]
        struct Categories<T> {
            $($name: T),*
        }

        impl<T: Default> Categories<T> {
            fn new() -> Categories<T> {
                Categories {
                    $($name: T::default()),*
                }
            }
        }

        impl<T> Categories<T> {
            fn get(&self, category: ProfileCategory) -> &T {
                match category {
                    $(ProfileCategory::$name => &self.$name),*
                }
            }

            fn set(&mut self, category: ProfileCategory, value: T) {
                match category {
                    $(ProfileCategory::$name => self.$name = value),*
                }
            }
        }

        struct CategoryData {
            times: Categories<u64>,
            query_counts: Categories<(u64, u64)>,
        }

        impl CategoryData {
            fn new() -> CategoryData {
                CategoryData {
                    times: Categories::new(),
                    query_counts: Categories::new(),
                }
            }

            fn print(&self, lock: &mut StderrLock<'_>) {
                writeln!(lock, "| Phase            | Time (ms)      | Queries        | Hits (%) |")
                    .unwrap();
                writeln!(lock, "| ---------------- | -------------- | -------------- | -------- |")
                    .unwrap();

                $(
                    let (hits, total) = self.query_counts.$name;
                    let (hits, total) = if total > 0 {
                        (format!("{:.2}",
                        (((hits as f32) / (total as f32)) * 100.0)), total.to_string())
                    } else {
                        (String::new(), String::new())
                    };

                    writeln!(
                        lock,
                        "| {0: <16} | {1: <14} | {2: <14} | {3: <8} |",
                        stringify!($name),
                        self.times.$name / 1_000_000,
                        total,
                        hits
                    ).unwrap();
                )*
            }

            fn json(&self) -> String {
                let mut json = String::from("[");

                $(
                    let (hits, total) = self.query_counts.$name;

                    //normalize hits to 0%
                    let hit_percent =
                        if total > 0 {
                            ((hits as f32) / (total as f32)) * 100.0
                        } else {
                            0.0
                        };

                    json.push_str(&format!(
                        "{{ \"category\": \"{}\", \"time_ms\": {},\
                            \"query_count\": {}, \"query_hits\": {} }},",
                        stringify!($name),
                        self.times.$name / 1_000_000,
                        total,
                        format!("{:.2}", hit_percent)
                    ));
                )*

                //remove the trailing ',' character
                json.pop();

                json.push(']');

                json
            }
        }
    }
}

define_categories! {
    Parsing,
    Expansion,
    TypeChecking,
    BorrowChecking,
    Codegen,
    Linking,
    Other,
}

pub struct SelfProfiler {
    timer_stack: Vec<ProfileCategory>,
    data: CategoryData,
    current_timer: Instant,
}

impl SelfProfiler {
    pub fn new() -> SelfProfiler {
        let mut profiler = SelfProfiler {
            timer_stack: Vec::new(),
            data: CategoryData::new(),
            current_timer: Instant::now(),
        };

        profiler.start_activity(ProfileCategory::Other);

        profiler
    }

    pub fn start_activity(&mut self, category: ProfileCategory) {
        match self.timer_stack.last().cloned() {
            None => {
                self.current_timer = Instant::now();
            },
            Some(current_category) if current_category == category => {
                //since the current category is the same as the new activity's category,
                //we don't need to do anything with the timer, we just need to push it on the stack
            }
            Some(current_category) => {
                let elapsed = self.stop_timer();

                //record the current category's time
                let new_time = self.data.times.get(current_category) + elapsed;
                self.data.times.set(current_category, new_time);
            }
        }

        //push the new category
        self.timer_stack.push(category);
    }

    pub fn record_query(&mut self, category: ProfileCategory) {
        let (hits, total) = *self.data.query_counts.get(category);
        self.data.query_counts.set(category, (hits, total + 1));
    }

    pub fn record_query_hit(&mut self, category: ProfileCategory) {
        let (hits, total) = *self.data.query_counts.get(category);
        self.data.query_counts.set(category, (hits + 1, total));
    }

    pub fn end_activity(&mut self, category: ProfileCategory) {
        match self.timer_stack.pop() {
            None => bug!("end_activity() was called but there was no running activity"),
            Some(c) =>
                assert!(
                    c == category,
                    "end_activity() was called but a different activity was running"),
        }

        //check if the new running timer is in the same category as this one
        //if it is, we don't need to do anything
        if let Some(c) = self.timer_stack.last() {
            if *c == category {
                return;
            }
        }

        //the new timer is different than the previous,
        //so record the elapsed time and start a new timer
        let elapsed = self.stop_timer();
        let new_time = self.data.times.get(category) + elapsed;
        self.data.times.set(category, new_time);
    }

    fn stop_timer(&mut self) -> u64 {
        let elapsed = if cfg!(windows) {
            // On Windows, timers don't always appear to be monotonic (see #51648)
            // which can lead to panics when calculating elapsed time.
            // Work around this by testing to see if the current time is less than
            // our recorded time, and if it is, just returning 0.
            let now = Instant::now();
            if self.current_timer >= now {
                Duration::new(0, 0)
            } else {
                self.current_timer.elapsed()
            }
        } else {
            self.current_timer.elapsed()
        };

        self.current_timer = Instant::now();

        (elapsed.as_secs() * 1_000_000_000) + (elapsed.subsec_nanos() as u64)
    }

    pub fn print_results(&mut self, opts: &Options) {
        self.end_activity(ProfileCategory::Other);

        assert!(
            self.timer_stack.is_empty(),
            "there were timers running when print_results() was called");

        let out = io::stderr();
        let mut lock = out.lock();

        let crate_name =
            opts.crate_name
            .as_ref()
            .map(|n| format!(" for {}", n))
            .unwrap_or_default();

        writeln!(lock, "Self profiling results{}:", crate_name).unwrap();
        writeln!(lock).unwrap();

        self.data.print(&mut lock);

        writeln!(lock).unwrap();
        writeln!(lock, "Optimization level: {:?}", opts.optimize).unwrap();

        let incremental = if opts.incremental.is_some() { "on" } else { "off" };
        writeln!(lock, "Incremental: {}", incremental).unwrap();
    }

    pub fn save_results(&self, opts: &Options) {
        let category_data = self.data.json();
        let compilation_options =
            format!("{{ \"optimization_level\": \"{:?}\", \"incremental\": {} }}",
                    opts.optimize,
                    if opts.incremental.is_some() { "true" } else { "false" });

        let json = format!("{{ \"category_data\": {}, \"compilation_options\": {} }}",
                        category_data,
                        compilation_options);

        fs::write("self_profiler_results.json", json).unwrap();
    }
}
<|endoftext|>


<commit_before>// Copyright 2016 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.

//! constant evaluation on the HIR and code to validate patterns/matches
//!
//! # Note
//!
//! This API is completely unstable and subject to change.

#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
      html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
      html_root_url = "https://doc.rust-lang.org/nightly/")]
#![deny(warnings)]

#![feature(rustc_diagnostic_macros)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(macro_lifetime_matcher)]
#![cfg_attr(stage0, feature(i128_type))]
#![feature(from_ref)]

extern crate arena;
#[macro_use] extern crate syntax;
#[macro_use] extern crate log;
#[macro_use] extern crate rustc;
extern crate rustc_const_math;
extern crate rustc_data_structures;
extern crate rustc_errors;
extern crate syntax_pos;

// NB: This module needs to be declared first so diagnostics are
// registered before they are used.
mod diagnostics;

mod eval;
mod _match;
pub mod check_match;
pub mod pattern;

pub use eval::*;

use rustc::ty::maps::Providers;

pub fn provide(providers: &mut Providers) {
    *providers = Providers {
        check_match: check_match::check_match,
        ..*providers
    };
}

// Build the diagnostics array at the end so that the metadata includes error use sites.
__build_diagnostic_array! { librustc_const_eval, DIAGNOSTICS }
<commit_msg>Rollup merge of #49444 - rust-lang:oli-obk-patch-1, r=Mark-Simulacrum<commit_after><|endoftext|>


<commit_before>use regex::Regex;
use super::{CompileError, SourcePos};

#[deriving(Show, Clone)]
pub enum TokenType<'a> {
	// tokenize gives:
	Ident(&'a str),
	Const(&'a str),
	Operator(&'a str),
	Newline,
	Paren(&'a str),
	Colon,
	Equals,
	Period,
}

#[deriving(Show, Clone)]
pub struct Token<'a> {
	pub t: TokenType<'a>,
	pub pos: SourcePos,
}

static IDENT_REGEX: Regex = regex!(r"[a-zA-Z_~']+[a-zA-Z_~0-9']*");
static WHITESPACE_REGEX: Regex = regex!(r"[ \t]+");
static NEWLINE_REGEX: Regex = regex!(r"[\n]+");
static CONST_REGEX: Regex = regex!(r"[0-9]+\.?[0-9]*|[0-9]*\.?[0-9]+");
static OPERATOR_REGEX: Regex = regex!(r"\^\^|>=|<=|~=|[\+\*/\^><!%-]|&&|\|\||==|!=");
static PAREN_REGEX: Regex = regex!(r"[\(\)\{\}]|\[|\]");
static COLON_REGEX: Regex = regex!(r":");
static EQUALS_REGEX: Regex = regex!(r"=");
static PERIOD_REGEX: Regex = regex!(r"\.");
static COMMENT_REGEX: Regex = regex!(r"//.*");

pub fn tokenize<'a>(s: &'a str) -> Result<Vec<Token<'a>>, CompileError> {
	let mut walk = s;
	let mut tokens = Vec::new();
	let mut pos = SourcePos { line: 1u, col: 1u };

	while walk.len() > 0 {
		let mut found = false;

		let ident_match = IDENT_REGEX.find(walk);
		let whitespace_match = WHITESPACE_REGEX.find(walk);
		let newline_match = NEWLINE_REGEX.find(walk);
		let const_match = CONST_REGEX.find(walk);
		let operator_match = OPERATOR_REGEX.find(walk);
		let paren_match = PAREN_REGEX.find(walk);
		let colon_match = COLON_REGEX.find(walk);
		let equals_match = EQUALS_REGEX.find(walk);
		let period_match = PERIOD_REGEX.find(walk);
		let comment_match = COMMENT_REGEX.find(walk);
		if let Some((0, x)) = comment_match { // Strip comments, don't add any tokens
			walk = walk[x..];
			found = true;
		} else if let Some((0, x)) = operator_match {
			tokens.push(Token { t: Operator(walk[0..x]), pos: pos });
			walk = walk[x..];
			found = true;
			pos.col += x;
		} else if let Some((0, x)) = ident_match {
			tokens.push(Token { t: Ident(walk[0..x]), pos: pos });
			walk = walk[x..];
			found = true;
			pos.col += x;
		} else if let Some((0, x)) = whitespace_match {
			walk = walk[x..];
			found = true;
			pos.col += x;
		} else if let Some((0, x)) = newline_match {
			tokens.push(Token { t: Newline, pos: pos });
			walk = walk[x..];
			found = true;
			pos.line += x;
			pos.col = 1;
		} else if let Some((0, x)) = const_match {
			tokens.push(Token { t: Const(walk[0..x]), pos: pos });
			walk = walk[x..];
			found = true;
			pos.col += x;
		} else if let Some((0, x)) = paren_match {
			tokens.push(Token { t: Paren(walk[0..x]), pos: pos });
			walk = walk[x..];
			found = true;
			pos.col += x;
		} else if let Some((0, x)) = colon_match {
			tokens.push(Token { t: Colon, pos: pos });
			walk = walk[x..];
			found = true;
			pos.col += x;
		} else if let Some((0, x)) = equals_match {
			tokens.push(Token { t: Equals, pos: pos });
			walk = walk[x..];
			found = true;
			pos.col += x;
		} else if let Some((0, x)) = period_match {
			tokens.push(Token { t: Period, pos: pos });
			walk = walk[x..];
			found = true;
			pos.col += x;
		}

		if !found {
			return Err(CompileError { msg: format!("unrecognized token `{}`", walk[0..1]), pos: pos});
		}
	}
	Ok(tokens)
}

<commit_msg>Simplify paren regex<commit_after>use regex::Regex;
use super::{CompileError, SourcePos};

#[deriving(Show, Clone)]
pub enum TokenType<'a> {
	// tokenize gives:
	Ident(&'a str),
	Const(&'a str),
	Operator(&'a str),
	Newline,
	Paren(&'a str),
	Colon,
	Equals,
	Period,
}

#[deriving(Show, Clone)]
pub struct Token<'a> {
	pub t: TokenType<'a>,
	pub pos: SourcePos,
}

static IDENT_REGEX: Regex = regex!(r"[a-zA-Z_~']+[a-zA-Z_~0-9']*");
static WHITESPACE_REGEX: Regex = regex!(r"[ \t]+");
static NEWLINE_REGEX: Regex = regex!(r"[\n]+");
static CONST_REGEX: Regex = regex!(r"[0-9]+\.?[0-9]*|[0-9]*\.?[0-9]+");
static OPERATOR_REGEX: Regex = regex!(r"\^\^|>=|<=|~=|[\+\*/\^><!%-]|&&|\|\||==|!=");
static PAREN_REGEX: Regex = regex!(r"[\(\)\{\}\]\[]");
static COLON_REGEX: Regex = regex!(r":");
static EQUALS_REGEX: Regex = regex!(r"=");
static PERIOD_REGEX: Regex = regex!(r"\.");
static COMMENT_REGEX: Regex = regex!(r"//.*");

pub fn tokenize<'a>(s: &'a str) -> Result<Vec<Token<'a>>, CompileError> {
	let mut walk = s;
	let mut tokens = Vec::new();
	let mut pos = SourcePos { line: 1u, col: 1u };

	while walk.len() > 0 {
		let mut found = false;

		let ident_match = IDENT_REGEX.find(walk);
		let whitespace_match = WHITESPACE_REGEX.find(walk);
		let newline_match = NEWLINE_REGEX.find(walk);
		let const_match = CONST_REGEX.find(walk);
		let operator_match = OPERATOR_REGEX.find(walk);
		let paren_match = PAREN_REGEX.find(walk);
		let colon_match = COLON_REGEX.find(walk);
		let equals_match = EQUALS_REGEX.find(walk);
		let period_match = PERIOD_REGEX.find(walk);
		let comment_match = COMMENT_REGEX.find(walk);
		if let Some((0, x)) = comment_match { // Strip comments, don't add any tokens
			walk = walk[x..];
			found = true;
		} else if let Some((0, x)) = operator_match {
			tokens.push(Token { t: Operator(walk[0..x]), pos: pos });
			walk = walk[x..];
			found = true;
			pos.col += x;
		} else if let Some((0, x)) = ident_match {
			tokens.push(Token { t: Ident(walk[0..x]), pos: pos });
			walk = walk[x..];
			found = true;
			pos.col += x;
		} else if let Some((0, x)) = whitespace_match {
			walk = walk[x..];
			found = true;
			pos.col += x;
		} else if let Some((0, x)) = newline_match {
			tokens.push(Token { t: Newline, pos: pos });
			walk = walk[x..];
			found = true;
			pos.line += x;
			pos.col = 1;
		} else if let Some((0, x)) = const_match {
			tokens.push(Token { t: Const(walk[0..x]), pos: pos });
			walk = walk[x..];
			found = true;
			pos.col += x;
		} else if let Some((0, x)) = paren_match {
			tokens.push(Token { t: Paren(walk[0..x]), pos: pos });
			walk = walk[x..];
			found = true;
			pos.col += x;
		} else if let Some((0, x)) = colon_match {
			tokens.push(Token { t: Colon, pos: pos });
			walk = walk[x..];
			found = true;
			pos.col += x;
		} else if let Some((0, x)) = equals_match {
			tokens.push(Token { t: Equals, pos: pos });
			walk = walk[x..];
			found = true;
			pos.col += x;
		} else if let Some((0, x)) = period_match {
			tokens.push(Token { t: Period, pos: pos });
			walk = walk[x..];
			found = true;
			pos.col += x;
		}

		if !found {
			return Err(CompileError { msg: format!("unrecognized token `{}`", walk[0..1]), pos: pos});
		}
	}
	Ok(tokens)
}

<|endoftext|>


<commit_before>//! Functions relating to network packets

/// A struct defining the header of a Packet
#[derive(Clone, Debug)]
pub struct PacketHeader {

    /// The number of bytes contained in the ID and the packet data
    pub length: u32,

    /// The ID of this packet
    pub id: u32

}<commit_msg>Add constants defining every packet ID in vanilla 1.8<commit_after>//! Functions relating to network packets

/// A struct defining the header of a Packet
#[derive(Clone, Debug)]
pub struct PacketHeader {

    /// The number of bytes contained in the ID and the packet data
    pub length: u32,

    /// The ID of this packet
    pub id: u32

}

/// The ID of a handshake packet
pub const ID_HANDSHAKE_CTS_HANDSHAKING: u8 = 0x00;

/// The ID of a legacy server list ping packet
pub const ID_HANDSHAKE_CTS_LEGACY_PING: u8 = 0xFE;

/// The ID of a keep-alive packet
///
/// One of these must be sent periodically, and if the client does not receive one at least every 30 seconds, it will disconnect
pub const ID_PLAY_STC_KEEP_ALIVE: u8 = 0x00;

/// The ID of a "join game" packet packet
pub const ID_PLAY_STC_JOIN_GAME: u8 = 0x01;

/// The ID of a chat message packet
pub const ID_PLAY_STC_CHAT_MESSAGE: u8 = 0x02;

/// The ID of a time update packet
pub const ID_PLAY_STC_TIME_UPDATE: u8 = 0x03;

/// The ID of a entity equipment packet
pub const ID_PLAY_STC_ENTITY_EQUIPMENT: u8 = 0x04;

/// The ID of a spawn position packet
pub const ID_PLAY_STC_SPAWN_POSITION: u8 = 0x05;

/// The ID of a health update packet
pub const ID_PLAY_STC_UPDATE_HEALTH: u8 = 0x06;

/// The ID of a respawn packet
pub const ID_PLAY_STC_RESPAWN: u8 = 0x07;

/// The ID of a player position **and** look packet
pub const ID_PLAY_STC_PLAYER_POSITION_AND_LOOK: u8 = 0x08;

/// The ID of a change held item packet
pub const ID_PLAY_STC_CHANGE_HELD_ITEM: u8 = 0x09;

/// The ID of a use bed packet
pub const ID_PLAY_STC_USE_BED: u8 = 0x0A;

/// The ID of an animation packet
pub const ID_PLAY_STC_ANIMATION: u8 = 0x0B;

/// The ID of a spawn player packet
pub const ID_PLAY_STC_SPAWN_PLAYER: u8 = 0x0C;

/// The ID of a collect item packet
pub const ID_PLAY_STC_COLLECT_ITEM: u8 = 0x0D;

/// The ID of a spawn object packet
pub const ID_PLAY_STC_SPAWN_OBJECT: u8 = 0x0E;

/// The ID of a spawn mob packet
pub const ID_PLAY_STC_SPAWN_MOB: u8 = 0x0F;

/// The ID of a spawn painting packet
pub const ID_PLAY_STC_SPAWN_PAINTING: u8 = 0x10;

/// The ID of a spawn experience orb packet
pub const ID_PLAY_STC_SPAWN_EXPERIENCE_ORB: u8 = 0x11;

/// The ID of an entity velocity packet
pub const ID_PLAY_STC_ENTITY_VELOCITY: u8 = 0x12;

/// The ID of a destroy entities packet
pub const ID_PLAY_STC_DESTROY_ENTITIES: u8 = 0x13;

/// The ID of an entity packet
pub const ID_PLAY_STC_ENTITY: u8 = 0x14;

/// The ID of an entity relative move packet
pub const ID_PLAY_STC_ENTITY_RELATIVE_MOVE: u8 = 0x15;

/// The ID of an entity look packet
pub const ID_PLAY_STC_ENTITY_LOOK: u8 = 0x16;

/// The ID of an entity look and relative move packet
pub const ID_PLAY_STC_ENTITY_LOOK_AND_RELATIVE_MOVE: u8 = 0x17;

/// The ID of an entity teleport packet
pub const ID_PLAY_STC_ENTITY_TELEPORT: u8 = 0x18;

/// The ID of an entity head look packet
pub const ID_PLAY_STC_HEAD_LOOK: u8 = 0x19;

/// The ID of an entity status packet
pub const ID_PLAY_STC_ENTITY_STATUS: u8 = 0x1A;

/// The ID of an attach entity packet
pub const ID_PLAY_STC_ATTACH_ENTITY: u8 = 0x1B;

/// The ID of an entity metadata packet
pub const ID_PLAY_STC_ENTITY_METADATA: u8 = 0x1C;

/// The ID of an entity effect packet
pub const ID_PLAY_STC_ENTITY_EFFECT: u8 = 0x1D;

/// The ID of a remove entity effect packet
pub const ID_PLAY_STC_REMOVE_ENTITY_EFFECT: u8 = 0x1E;

/// The ID of a set experience packet
pub const ID_PLAY_STC_SET_EXPERIENCE: u8 = 0x1F;

/// The ID of an entity properties packet
pub const ID_PLAY_STC_ENTITY_PROPERTIES: u8 = 0x20;

/// The ID of a chunk data packet
pub const ID_PLAY_STC_CHUNK_DATA: u8 = 0x21;

/// The ID of a multi block change packet
pub const ID_PLAY_STC_MULTI_BLOCK_CHANGE: u8 = 0x22;

/// The ID of a block change packet
pub const ID_PLAY_STC_BLOCK_CHANGE: u8 = 0x23;

/// The ID of a block action packet
pub const ID_PLAY_STC_BLOCK_ACTION: u8 = 0x24;

/// The ID of a block break animation packet
pub const ID_PLAY_STC_BLOCK_BREAK_ANIMATION: u8 = 0x25;

/// The ID of a map chunk bulk packet
pub const ID_PLAY_STC_MAP_CHUNK_BULK: u8 = 0x26;

/// The ID of an explosion packet
pub const ID_PLAY_STC_EXPLOSION: u8 = 0x27;

/// The ID of an effect packet
pub const ID_PLAY_STC_EFFECT: u8 = 0x28;

/// The ID of a sound effect packet
pub const ID_PLAY_STC_SOUND_EFFECT: u8 = 0x29;

/// The ID of a particle packet
pub const ID_PLAY_STC_PARTICLE: u8 = 0x2A;

/// The ID of a change game state packet
pub const ID_PLAY_STC_CHANGE_GAME_STATE: u8 = 0x2B;

/// The ID of a spawn global entity packet
pub const ID_PLAY_STC_SPAWN_GLOBAL_ENTITY: u8 = 0x2C;

/// The ID of an open window packet
pub const ID_PLAY_STC_OPEN_WINDOW: u8 = 0x2D;

/// The ID of a close window packet
pub const ID_PLAY_STC_CLOSE_WINDOW: u8 = 0x2E;

/// The ID of a set slot packet
pub const ID_PLAY_STC_SET_SLOT: u8 = 0x2F;

/// The ID of a window items packet
pub const ID_PLAY_STC_WINDOW_ITEMS: u8 = 0x30;

/// The ID of a window property packet
pub const ID_PLAY_STC_WINDOW_PROPERTY: u8 = 0x31;

/// The ID of a confirm transaction packet
pub const ID_PLAY_STC_CONFIRM_TRANSACTION: u8 = 0x32;

/// The ID of a sign update packet
pub const ID_PLAY_STC_SIGN_UPDATE: u8 = 0x33;

/// The ID of a maps packet
pub const ID_PLAY_STC_MAPS: u8 = 0x34;

/// The ID of a block entity update packet
pub const ID_PLAY_STC_BLOCK_ENTITY_UPDATE: u8 = 0x35;

/// The ID of an open sign editor packet
pub const ID_PLAY_STC_OPEN_SIGN_EDITOR: u8 = 0x36;

/// The ID of a statistics packet
pub const ID_PLAY_STC_STATISTICS: u8 = 0x37;

/// The ID of a player list item packet
pub const ID_PLAY_STC_PLAYER_LIST_ITEM: u8 = 0x38;

/// The ID of a player abilities packet
pub const ID_PLAY_STC_PLAYER_ABILITIES: u8 = 0x39;

/// The ID of a tab complete packet
pub const ID_PLAY_STC_TAB_COMPLETE: u8 = 0x3A;

/// The ID of a scoreboard objective packet
pub const ID_PLAY_STC_SCOREBOARD_OBJECTIVE: u8 = 0x3B;

/// The ID of an update score packet
pub const ID_PLAY_STC_UPDATE_SCORE: u8 = 0x3C;

/// The ID of a display scoreboard packet
pub const ID_PLAY_STC_DISPLAY_SCOREBOARD: u8 = 0x3D;

/// The ID of a teams packet
pub const ID_PLAY_STC_TEAMS: u8 = 0x3E;

/// The ID of a plugin message packet
pub const ID_PLAY_STC_PLUGIN_MESSAGE: u8 = 0x3F;

/// The ID of a disconnect packet
pub const ID_PLAY_STC_DISCONNECT: u8 = 0x40;

/// The ID of a server difficulty packet
pub const ID_PLAY_STC_SERVER_DIFFICULTY: u8 = 0x41;

/// The ID of a combat event packet
pub const ID_PLAY_STC_COMBAT_EVENT: u8 = 0x42;

/// The ID of a camera packet
pub const ID_PLAY_STC_CAMERA: u8 = 0x43;

/// The ID of a world border packet
pub const ID_PLAY_STC_WORLD_BORDER: u8 = 0x44;

/// The ID of a title packet
pub const ID_PLAY_STC_TITLE: u8 = 0x45;

/// The ID of a set compression packet
pub const ID_PLAY_STC_SET_COMPRESSION: u8 = 0x46;

/// The ID of a player list header/footer packet
pub const ID_PLAY_STC_PLAYER_LIST_HEADER_FOOTER: u8 = 0x47;

/// The ID of a send resource pack packet
pub const ID_PLAY_STC_SEND_RESOURCE_PACK: u8 = 0x48;

/// The ID of an update entity NBT packet
pub const ID_PLAY_STC_UPDATE_ENTITY_NBT: u8 = 0x49;

/// The ID of a keep alive packet
pub const ID_PLAY_CTS_KEEP_ALIVE: u8 = 0x00;

/// The ID of a chat message packet
pub const ID_PLAY_CTS_CHAT_MESSAGE: u8 = 0x01;

/// The ID of a use entity packet
pub const ID_PLAY_CTS_USE_ENTITY: u8 = 0x02;

/// The ID of a player packet
pub const ID_PLAY_CTS_PLAYER: u8 = 0x03;

/// The ID of a player position packet
pub const ID_PLAY_CTS_PLAYER_POSITION: u8 = 0x04;

/// The ID of a player look packet
pub const ID_PLAY_CTS_PLAYER_LOOK: u8 = 0x05;

/// The ID of a player position and look packet
pub const ID_PLAY_CTS_PLAYER_POSITION_AND_LOOK: u8 = 0x06;

/// The ID of a player digging packet
pub const ID_PLAY_CTS_PLAYER_DIGGING: u8 = 0x07;

/// The ID of a player block placement packet
pub const ID_PLAY_CTS_PLAYER_BLOCK_PLACEMENT: u8 = 0x08;

/// The ID of a change held item packet
pub const ID_PLAY_CTS_CHANGE_HELD_ITEM: u8 = 0x09;

/// The ID of an animation packet
pub const ID_PLAY_CTS_ANIMATION: u8 = 0x0A;

/// The ID of an entity action packet
pub const ID_PLAY_CTS_ENTITY_ACTION: u8 = 0x0B;

/// The ID of a steer vehicle packet
pub const ID_PLAY_CTS_STEER_VEHICLE: u8 = 0x0C;

/// The ID of a close window packet
pub const ID_PLAY_CTS_CLOSE_WINDOW: u8 = 0x0D;

/// The ID of a click window packet
pub const ID_PLAY_CTS_CLICK_WINDOW: u8 = 0x0E;

/// The ID of a confirm transaction packet
pub const ID_PLAY_CTS_CONFIRM_TRANSACTION: u8 = 0x0F;

/// The ID of a creative inventory action packet
pub const ID_PLAY_CTS_CREATIVE_INVENTORY_ACTION: u8 = 0x10;

/// The ID of an enchant item packet
pub const ID_PLAY_CTS_ENCHANT_ITEM: u8 = 0x11;

/// The ID of a sign update packet
pub const ID_PLAY_CTS_SIGN_UPDATE: u8 = 0x12;

/// The ID of a player abilities packet
pub const ID_PLAY_CTS_PLAYER_ABILITIES: u8 = 0x13;

/// The ID of a tab complete packet
pub const ID_PLAY_CTS_TAB_COMPLETE: u8 = 0x14;

/// The ID of a client settings packet
pub const ID_PLAY_CTS_CLIENT_SETTINGS: u8 = 0x15;

/// The ID of a client status packet
pub const ID_PLAY_CTS_CLIENT_STATUS: u8 = 0x16;

/// The ID of a plugin message packet
pub const ID_PLAY_CTS_PLUGIN_MESSAGE: u8 = 0x17;

/// The ID of a spectate packet
pub const ID_PLAY_CTS_SPECTATE: u8 = 0x18;

/// The ID of a resource pack status packet
pub const ID_PLAY_CTS_RESOURCE_PACK_STATUS: u8 = 0x19;

/// The ID of a response packet
pub const ID_STATUS_STC_RESPONSE: u8 = 0x00;

/// The ID of a pong packet
pub const ID_STATUS_STC_PONG: u8 = 0x01;

/// The ID of a request packet
pub const ID_STATUS_CTS_REQUEST: u8 = 0x00;

/// The ID of a ping packet
pub const ID_STATUS_CTS_PING: u8 = 0x01;

/// The ID of a disconnect packet
pub const ID_LOGIN_STC_DISCONNECT: u8 = 0x00;

/// The ID of an encryption request packet
pub const ID_LOGIN_STC_ENCRYPTION_REQUEST: u8 = 0x01;

/// The ID of a login success packet
pub const ID_LOGIN_STC_LOGIN_SUCCESS: u8 = 0x02;

/// The ID of a set compression packet
pub const ID_LOGIN_STC_SET_COMPRESSION: u8 = 0x03;

/// The ID of a start login packet
pub const ID_LOGIN_CTS_START_LOGIN: u8 = 0x00;

/// The ID of an encryption response packet
pub const ID_LOGIN_CTS_ENCRYPTION_RESPONSE: u8 = 0x01;
<|endoftext|>


<commit_before>use rustc_serialize::json;
use hyper;
use hyper::{Client};
use url::form_urlencoded;

use std::io::Read;

use text_view::view_as_text;
use text_view::insert_annotation;
use token::Token;
use token::Data;
use error::{Error, Result, Source};

/// Represents a grammar error from language tool
///
/// Note: lots of fields are missing
#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct GrammarError {
    pub message: String,
    pub offset: usize,
    pub length: usize,
    pub short_message: Option<String>,
    pub issue_type: Option<String>,
}

/// Contains a list of matches to errors
///
/// Corresponds to the JSON that LanguageTool-server sends back
///
/// Note: lots of fields are missing
#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct GrammarCheck {
    pub matches: Vec<GrammarError>,
}

/// GrammarChecker
pub struct GrammarChecker {
    lang: String,
    port: usize,
}

impl GrammarChecker {
    /// Initialize the grammarchecker
    pub fn new<S:Into<String>>(port: usize, lang: S) -> Result<GrammarChecker> {
        let mut checker = GrammarChecker {
            lang: lang.into(),
            port: port
        };

        // Todo: try to connect to the server
        Ok(checker)
    }

    /// Send a query to LanguageTools server and get back a list of errors
    pub fn check(&self, text: &str) -> Result<GrammarCheck> {
        let query: String = form_urlencoded::Serializer::new(String::new())
            .append_pair("language", &self.lang)
            .append_pair("text", text)
            .finish();

        let client = Client::new();

        let mut res = try!(client.post(&format!("http://localhost:{}/v2/check", self.port))
                           .body(&query)
                           .send()
                           .map_err(|e| Error::grammar_check(Source::empty(),
                                                             format!("could not send request to server: {}", e))));

        if res.status != hyper::Ok {
            return Err(Error::grammar_check(Source::empty(),
                                      format!("server didn't respond with a OK status code")));
        }

        let mut s = String::new();
        try!(res.read_to_string(&mut s)
             .map_err(|e| Error::grammar_check(Source::empty(),
                                               format!("could not read response: {}", e))));
        let reponse: GrammarCheck = try!(json::decode(&s).map_err(|e| Error::default(Source::empty(),
                                                                                format!("could not decode JSON: {}", e))));
        Ok(reponse)
    }
}

/// Check the grammar in a chapter
///
/// This modifies the AST
pub fn check_grammar(tokens: &mut Vec<Token>, lang: &str) -> Result<()> {
    let input = view_as_text(tokens);
    let checker = try!(GrammarChecker::new(8081, lang));
    let check = try!(checker.check(&input));

    for error in check.matches {
        insert_annotation(tokens, &Data::GrammarError(error.message.clone()), error.offset, error.length);
    }
    Ok(())
}

<commit_msg>Test that connection is Ok in GrammarChecker::new()<commit_after>use rustc_serialize::json;
use hyper;
use hyper::{Client};
use url::form_urlencoded;

use std::io::Read;

use text_view::view_as_text;
use text_view::insert_annotation;
use token::Token;
use token::Data;
use error::{Error, Result, Source};

/// Represents a grammar error from language tool
///
/// Note: lots of fields are missing
#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct GrammarError {
    pub message: String,
    pub offset: usize,
    pub length: usize,
    pub short_message: Option<String>,
    pub issue_type: Option<String>,
}

/// Contains a list of matches to errors
///
/// Corresponds to the JSON that LanguageTool-server sends back
///
/// Note: lots of fields are missing
#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct GrammarCheck {
    pub matches: Vec<GrammarError>,
}

/// GrammarChecker
pub struct GrammarChecker {
    lang: String,
    port: usize,
}

impl GrammarChecker {
    /// Initialize the grammarchecker
    pub fn new<S:Into<String>>(port: usize, lang: S) -> Result<GrammarChecker> {
        let mut checker = GrammarChecker {
            lang: lang.into(),
            port: port
        };

        let mut res = try!(Client::new()
                           .get(&format!("http://localhost:{}/v2/languages", port))
                           .send()
                           .map_err(|e| Error::grammar_check(Source::empty(),
                                                             format!("could not connect to language tool server: {}", e))));
        if res.status != hyper::Ok {
            return Err(Error::grammar_check(Source::empty(),
                                            format!("server didn't respond with a OK status code")));
        }
        Ok(checker)
    }

    /// Send a query to LanguageTools server and get back a list of errors
    pub fn check(&self, text: &str) -> Result<GrammarCheck> {
        let query: String = form_urlencoded::Serializer::new(String::new())
            .append_pair("language", &self.lang)
            .append_pair("text", text)
            .finish();

        let client = Client::new();

        let mut res = try!(client.post(&format!("http://localhost:{}/v2/check", self.port))
                           .body(&query)
                           .send()
                           .map_err(|e| Error::grammar_check(Source::empty(),
                                                             format!("could not send request to server: {}", e))));

        if res.status != hyper::Ok {
            return Err(Error::grammar_check(Source::empty(),
                                      format!("server didn't respond with a OK status code")));
        }

        let mut s = String::new();
        try!(res.read_to_string(&mut s)
             .map_err(|e| Error::grammar_check(Source::empty(),
                                               format!("could not read response: {}", e))));
        let reponse: GrammarCheck = try!(json::decode(&s).map_err(|e| Error::default(Source::empty(),
                                                                                format!("could not decode JSON: {}", e))));
        Ok(reponse)
    }
}

/// Check the grammar in a chapter
///
/// This modifies the AST
pub fn check_grammar(tokens: &mut Vec<Token>, lang: &str) -> Result<()> {
    let input = view_as_text(tokens);
    let checker = try!(GrammarChecker::new(8081, lang));
    let check = try!(checker.check(&input));

    for error in check.matches {
        insert_annotation(tokens, &Data::GrammarError(error.message.clone()), error.offset, error.length);
    }
    Ok(())
}

<|endoftext|>


<commit_before>//! Memory allocation APIs

#![stable(feature = "alloc_module", since = "1.28.0")]

mod global;
mod layout;

#[stable(feature = "global_alloc", since = "1.28.0")]
pub use self::global::GlobalAlloc;
#[stable(feature = "alloc_layout", since = "1.28.0")]
pub use self::layout::{Layout, LayoutErr};

use crate::fmt;
use crate::ptr::{self, NonNull};

/// The `AllocErr` error indicates an allocation failure
/// that may be due to resource exhaustion or to
/// something wrong when combining the given input arguments with this
/// allocator.
#[unstable(feature = "allocator_api", issue = "32838")]
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct AllocErr;

// (we need this for downstream impl of trait Error)
#[unstable(feature = "allocator_api", issue = "32838")]
impl fmt::Display for AllocErr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("memory allocation failed")
    }
}

/// A desired initial state for allocated memory.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[unstable(feature = "allocator_api", issue = "32838")]
pub enum AllocInit {
    /// The contents of the new memory are undefined.
    ///
    /// Reading uninitialized memory is Undefined Behavior; it must be initialized before use.
    Uninitialized,
    /// The new memory is guaranteed to be zeroed.
    Zeroed,
}

impl AllocInit {
    /// Initialize the specified memory block.
    ///
    /// This behaves like calling [`AllocInit::init_offset(memory, 0)`][off].
    ///
    /// [off]: AllocInit::init_offset
    ///
    /// # Safety
    ///
    /// * `memory.ptr` must be [valid] for writes of `memory.size` bytes.
    ///
    /// [valid]: ../ptr/index.html#safety
    #[inline]
    #[unstable(feature = "allocator_api", issue = "32838")]
    pub unsafe fn init(self, memory: MemoryBlock) {
        self.init_offset(memory, 0)
    }

    /// Initialize the memory block like specified by `init` at the specified `offset`.
    ///
    /// This is a no-op for [`AllocInit::Uninitialized`][] and writes zeroes for
    /// [`AllocInit::Zeroed`][] at `ptr + offset` until `ptr + layout.size()`.
    ///
    /// # Safety
    ///
    /// * `memory.ptr` must be [valid] for writes of `memory.size` bytes.
    /// * `offset` must be smaller than or equal to `memory.size`
    ///
    /// [valid]: ../ptr/index.html#safety
    #[inline]
    #[unstable(feature = "allocator_api", issue = "32838")]
    pub unsafe fn init_offset(self, memory: MemoryBlock, offset: usize) {
        debug_assert!(
            offset <= memory.size,
            "`offset` must be smaller than or equal to `memory.size`"
        );
        match self {
            AllocInit::Uninitialized => (),
            AllocInit::Zeroed => {
                memory.ptr.as_ptr().add(offset).write_bytes(0, memory.size - offset)
            }
        }
    }
}

/// Represents a block of allocated memory returned by an allocator.
#[derive(Debug, Copy, Clone)]
#[unstable(feature = "allocator_api", issue = "32838")]
pub struct MemoryBlock {
    pub ptr: NonNull<u8>,
    pub size: usize,
}

/// A placement constraint when growing or shrinking an existing allocation.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[unstable(feature = "allocator_api", issue = "32838")]
pub enum ReallocPlacement {
    /// The allocator is allowed to move the allocation to a different memory address.
    // FIXME(wg-allocators#46): Add a section to the module documentation "What is a legal
    //                          allocator" and link it at "valid location".
    ///
    /// If the allocation _does_ move, it's the responsibility of the allocator
    /// to also move the data from the previous location to the new location.
    MayMove,
    /// The address of the new memory must not change.
    ///
    /// If the allocation would have to be moved to a new location to fit, the
    /// reallocation request will fail.
    InPlace,
}

/// An implementation of `AllocRef` can allocate, grow, shrink, and deallocate arbitrary blocks of
/// data described via [`Layout`][].
///
/// `AllocRef` is designed to be implemented on ZSTs, references, or smart pointers because having
/// an allocator like `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the
/// allocated memory.
///
/// Unlike [`GlobalAlloc`][], zero-sized allocations are allowed in `AllocRef`. If an underlying
/// allocator does not support this (like jemalloc) or return a null pointer (such as
/// `libc::malloc`), this case must be caught.
///
/// ### Currently allocated memory
///
/// Some of the methods require that a memory block be *currently allocated* via an allocator. This
/// means that:
///
/// * the starting address for that memory block was previously returned by [`alloc`], [`grow`], or
///   [`shrink`], and
///
/// * the memory block has not been subsequently deallocated, where blocks are either deallocated
///   directly by being passed to [`dealloc`] or were changed by being passed to [`grow`] or
///   [`shrink`] that returns `Ok`. If `grow` or `shrink` have returned `Err`, the passed pointer
///   remains valid.
///
/// [`alloc`]: AllocRef::alloc
/// [`grow`]: AllocRef::grow
/// [`shrink`]: AllocRef::shrink
/// [`dealloc`]: AllocRef::dealloc
///
/// ### Memory fitting
///
/// Some of the methods require that a layout *fit* a memory block. What it means for a layout to
/// "fit" a memory block means (or equivalently, for a memory block to "fit" a layout) is that the
/// following conditions must hold:
///
/// * The block must be allocated with the same alignment as [`layout.align()`], and
///
/// * The provided [`layout.size()`] must fall in the range `min ..= max`, where:
///   - `min` is the size of the layout most recently used to allocate the block, and
///   - `max` is the latest actual size returned from [`alloc`], [`grow`], or [`shrink`].
///
/// [`layout.align()`]: Layout::align
/// [`layout.size()`]: Layout::size
///
/// # Safety
///
/// * Memory blocks returned from an allocator must point to valid memory and retain their validity
///   until the instance and all of its clones are dropped, and
///
/// * cloning or moving the allocator must not invalidate memory blocks returned from this
///   allocator. A cloned allocator must behave like the same allocator.
///
/// * any pointer to a memory block which is [*currently allocated*] may be passed to any other
///   method of the allocator.
///
/// [*currently allocated*]: #currently-allocated-memory
#[unstable(feature = "allocator_api", issue = "32838")]
pub unsafe trait AllocRef {
    /// On success, returns a memory block meeting the size and alignment guarantees of `layout`.
    ///
    /// The returned block may have a larger size than specified by `layout.size()` and is
    /// initialized as specified by [`init`], all the way up to the returned size of the block.
    ///
    /// [`init`]: AllocInit
    ///
    /// # Errors
    ///
    /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet
    /// allocator's size or alignment constraints.
    ///
    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr>;

    /// Deallocates the memory denoted by `memory`.
    ///
    /// # Safety
    ///
    /// `memory` must be a memory block returned by this allocator.
    unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout);

    /// Attempts to extend the memory block.
    ///
    /// Returns a new memory block containing a pointer and the actual size of the allocated
    /// block. The pointer is suitable for holding data described by a new layout with `layout`’s
    /// alignment and a size given by `new_size`. To accomplish this, the allocator may extend the
    /// allocation referenced by `ptr` to fit the new layout. If the [`placement`] is
    /// [`InPlace`], the returned pointer is guaranteed to be the same as the passed `ptr`.
    ///
    /// If `ReallocPlacement::MayMove` is used then ownership of the memory block referenced by `ptr`
    /// is transferred to this allocator. The memory may or may not be freed, and should be
    /// considered unusable (unless of course it is transferred back to the caller again via the
    /// return value of this method).
    ///
    /// If this method returns `Err`, then ownership of the memory block has not been transferred to
    /// this allocator, and the contents of the memory block are unaltered.
    ///
    /// The memory block will contain the following contents after a successful call to `grow`:
    ///   * Bytes `0..layout.size()` are preserved from the original allocation.
    ///   * Bytes `layout.size()..old_size` will either be preserved or initialized according to
    ///     [`init`], depending on the allocator implementation. `old_size` refers to the size of
    ///     the `MemoryBlock` prior to the `grow` call, which may be larger than the size
    ///     that was originally requested when it was allocated.
    ///   * Bytes `old_size..new_size` are initialized according to [`init`]. `new_size` refers to
    ///     the size of the `MemoryBlock` returned by the `grow` call.
    ///
    /// [`InPlace`]: ReallocPlacement::InPlace
    /// [`placement`]: ReallocPlacement
    /// [`init`]: AllocInit
    ///
    /// # Safety
    ///
    /// * `ptr` must be [*currently allocated*] via this allocator,
    /// * `layout` must [*fit*] the `ptr`. (The `new_size` argument need not fit it.)
    // We can't require that `new_size` is strictly greater than `memory.size` because of ZSTs.
    // An alternative would be
    // * `new_size must be strictly greater than `memory.size` or both are zero
    /// * `new_size` must be greater than or equal to `layout.size()`
    /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, must not overflow
    ///   (i.e., the rounded value must be less than `usize::MAX`).
    ///
    /// [*currently allocated*]: #currently-allocated-memory
    /// [*fit*]: #memory-fitting
    ///
    /// # Errors
    ///
    /// Returns `Err` if the new layout does not meet the allocator's size and alignment
    /// constraints of the allocator, or if growing otherwise fails.
    ///
    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    unsafe fn grow(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
        placement: ReallocPlacement,
        init: AllocInit,
    ) -> Result<MemoryBlock, AllocErr> {
        match placement {
            ReallocPlacement::InPlace => Err(AllocErr),
            ReallocPlacement::MayMove => {
                let size = layout.size();
                debug_assert!(
                    new_size >= size,
                    "`new_size` must be greater than or equal to `layout.size()`"
                );

                if new_size == size {
                    return Ok(MemoryBlock { ptr, size });
                }

                let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
                let new_memory = self.alloc(new_layout, init)?;
                ptr::copy_nonoverlapping(ptr.as_ptr(), new_memory.ptr.as_ptr(), size);
                self.dealloc(ptr, layout);
                Ok(new_memory)
            }
        }
    }

    /// Attempts to shrink the memory block.
    ///
    /// Returns a new memory block containing a pointer and the actual size of the allocated
    /// block. The pointer is suitable for holding data described by a new layout with `layout`’s
    /// alignment and a size given by `new_size`. To accomplish this, the allocator may shrink the
    /// allocation referenced by `ptr` to fit the new layout. If the [`placement`] is
    /// [`InPlace`], the returned pointer is guaranteed to be the same as the passed `ptr`.
    ///
    /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been
    /// transferred to this allocator. The memory may or may not have been freed, and should be
    /// considered unusable unless it was transferred back to the caller again via the
    /// return value of this method.
    ///
    /// If this method returns `Err`, then ownership of the memory block has not been transferred to
    /// this allocator, and the contents of the memory block are unaltered.
    ///
    /// The behavior of how the allocator tries to shrink the memory is specified by [`placement`].
    ///
    /// [`InPlace`]: ReallocPlacement::InPlace
    /// [`placement`]: ReallocPlacement
    ///
    /// # Safety
    ///
    /// * `ptr` must be [*currently allocated*] via this allocator,
    /// * `layout` must [*fit*] the `ptr`. (The `new_size` argument need not fit it.)
    // We can't require that `new_size` is strictly smaller than `memory.size` because of ZSTs.
    // An alternative would be
    // * `new_size must be strictly smaller than `memory.size` or both are zero
    /// * `new_size` must be smaller than or equal to `layout.size()`
    ///
    /// [*currently allocated*]: #currently-allocated-memory
    /// [*fit*]: #memory-fitting
    ///
    /// # Errors
    ///
    /// Returns `Err` if the new layout does not meet the allocator's size and alignment
    /// constraints of the allocator, or if growing otherwise fails.
    ///
    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    unsafe fn shrink(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
        placement: ReallocPlacement,
    ) -> Result<MemoryBlock, AllocErr> {
        match placement {
            ReallocPlacement::InPlace => Err(AllocErr),
            ReallocPlacement::MayMove => {
                let size = layout.size();
                debug_assert!(
                    new_size <= size,
                    "`new_size` must be smaller than or equal to `layout.size()`"
                );

                if new_size == size {
                    return Ok(MemoryBlock { ptr, size });
                }

                let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
                let new_memory = self.alloc(new_layout, AllocInit::Uninitialized)?;
                ptr::copy_nonoverlapping(ptr.as_ptr(), new_memory.ptr.as_ptr(), new_size);
                self.dealloc(ptr, layout);
                Ok(new_memory)
            }
        }
    }
}
<commit_msg>Fix links for `AllocInit` methods<commit_after>//! Memory allocation APIs

#![stable(feature = "alloc_module", since = "1.28.0")]

mod global;
mod layout;

#[stable(feature = "global_alloc", since = "1.28.0")]
pub use self::global::GlobalAlloc;
#[stable(feature = "alloc_layout", since = "1.28.0")]
pub use self::layout::{Layout, LayoutErr};

use crate::fmt;
use crate::ptr::{self, NonNull};

/// The `AllocErr` error indicates an allocation failure
/// that may be due to resource exhaustion or to
/// something wrong when combining the given input arguments with this
/// allocator.
#[unstable(feature = "allocator_api", issue = "32838")]
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct AllocErr;

// (we need this for downstream impl of trait Error)
#[unstable(feature = "allocator_api", issue = "32838")]
impl fmt::Display for AllocErr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("memory allocation failed")
    }
}

/// A desired initial state for allocated memory.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[unstable(feature = "allocator_api", issue = "32838")]
pub enum AllocInit {
    /// The contents of the new memory are undefined.
    ///
    /// Reading uninitialized memory is Undefined Behavior; it must be initialized before use.
    Uninitialized,
    /// The new memory is guaranteed to be zeroed.
    Zeroed,
}

impl AllocInit {
    /// Initialize the specified memory block.
    ///
    /// This behaves like calling [`AllocInit::init_offset(memory, 0)`][off].
    ///
    /// [off]: AllocInit::init_offset
    ///
    /// # Safety
    ///
    /// * `memory.ptr` must be [valid] for writes of `memory.size` bytes.
    ///
    /// [valid]: ../../core/ptr/index.html#safety
    #[inline]
    #[unstable(feature = "allocator_api", issue = "32838")]
    pub unsafe fn init(self, memory: MemoryBlock) {
        self.init_offset(memory, 0)
    }

    /// Initialize the memory block like specified by `init` at the specified `offset`.
    ///
    /// This is a no-op for [`AllocInit::Uninitialized`][] and writes zeroes for
    /// [`AllocInit::Zeroed`][] at `ptr + offset` until `ptr + layout.size()`.
    ///
    /// # Safety
    ///
    /// * `memory.ptr` must be [valid] for writes of `memory.size` bytes.
    /// * `offset` must be smaller than or equal to `memory.size`
    ///
    /// [valid]: ../../core/ptr/index.html#safety
    #[inline]
    #[unstable(feature = "allocator_api", issue = "32838")]
    pub unsafe fn init_offset(self, memory: MemoryBlock, offset: usize) {
        debug_assert!(
            offset <= memory.size,
            "`offset` must be smaller than or equal to `memory.size`"
        );
        match self {
            AllocInit::Uninitialized => (),
            AllocInit::Zeroed => {
                memory.ptr.as_ptr().add(offset).write_bytes(0, memory.size - offset)
            }
        }
    }
}

/// Represents a block of allocated memory returned by an allocator.
#[derive(Debug, Copy, Clone)]
#[unstable(feature = "allocator_api", issue = "32838")]
pub struct MemoryBlock {
    pub ptr: NonNull<u8>,
    pub size: usize,
}

/// A placement constraint when growing or shrinking an existing allocation.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[unstable(feature = "allocator_api", issue = "32838")]
pub enum ReallocPlacement {
    /// The allocator is allowed to move the allocation to a different memory address.
    // FIXME(wg-allocators#46): Add a section to the module documentation "What is a legal
    //                          allocator" and link it at "valid location".
    ///
    /// If the allocation _does_ move, it's the responsibility of the allocator
    /// to also move the data from the previous location to the new location.
    MayMove,
    /// The address of the new memory must not change.
    ///
    /// If the allocation would have to be moved to a new location to fit, the
    /// reallocation request will fail.
    InPlace,
}

/// An implementation of `AllocRef` can allocate, grow, shrink, and deallocate arbitrary blocks of
/// data described via [`Layout`][].
///
/// `AllocRef` is designed to be implemented on ZSTs, references, or smart pointers because having
/// an allocator like `MyAlloc([u8; N])` cannot be moved, without updating the pointers to the
/// allocated memory.
///
/// Unlike [`GlobalAlloc`][], zero-sized allocations are allowed in `AllocRef`. If an underlying
/// allocator does not support this (like jemalloc) or return a null pointer (such as
/// `libc::malloc`), this case must be caught.
///
/// ### Currently allocated memory
///
/// Some of the methods require that a memory block be *currently allocated* via an allocator. This
/// means that:
///
/// * the starting address for that memory block was previously returned by [`alloc`], [`grow`], or
///   [`shrink`], and
///
/// * the memory block has not been subsequently deallocated, where blocks are either deallocated
///   directly by being passed to [`dealloc`] or were changed by being passed to [`grow`] or
///   [`shrink`] that returns `Ok`. If `grow` or `shrink` have returned `Err`, the passed pointer
///   remains valid.
///
/// [`alloc`]: AllocRef::alloc
/// [`grow`]: AllocRef::grow
/// [`shrink`]: AllocRef::shrink
/// [`dealloc`]: AllocRef::dealloc
///
/// ### Memory fitting
///
/// Some of the methods require that a layout *fit* a memory block. What it means for a layout to
/// "fit" a memory block means (or equivalently, for a memory block to "fit" a layout) is that the
/// following conditions must hold:
///
/// * The block must be allocated with the same alignment as [`layout.align()`], and
///
/// * The provided [`layout.size()`] must fall in the range `min ..= max`, where:
///   - `min` is the size of the layout most recently used to allocate the block, and
///   - `max` is the latest actual size returned from [`alloc`], [`grow`], or [`shrink`].
///
/// [`layout.align()`]: Layout::align
/// [`layout.size()`]: Layout::size
///
/// # Safety
///
/// * Memory blocks returned from an allocator must point to valid memory and retain their validity
///   until the instance and all of its clones are dropped, and
///
/// * cloning or moving the allocator must not invalidate memory blocks returned from this
///   allocator. A cloned allocator must behave like the same allocator.
///
/// * any pointer to a memory block which is [*currently allocated*] may be passed to any other
///   method of the allocator.
///
/// [*currently allocated*]: #currently-allocated-memory
#[unstable(feature = "allocator_api", issue = "32838")]
pub unsafe trait AllocRef {
    /// On success, returns a memory block meeting the size and alignment guarantees of `layout`.
    ///
    /// The returned block may have a larger size than specified by `layout.size()` and is
    /// initialized as specified by [`init`], all the way up to the returned size of the block.
    ///
    /// [`init`]: AllocInit
    ///
    /// # Errors
    ///
    /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet
    /// allocator's size or alignment constraints.
    ///
    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr>;

    /// Deallocates the memory denoted by `memory`.
    ///
    /// # Safety
    ///
    /// `memory` must be a memory block returned by this allocator.
    unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout);

    /// Attempts to extend the memory block.
    ///
    /// Returns a new memory block containing a pointer and the actual size of the allocated
    /// block. The pointer is suitable for holding data described by a new layout with `layout`’s
    /// alignment and a size given by `new_size`. To accomplish this, the allocator may extend the
    /// allocation referenced by `ptr` to fit the new layout. If the [`placement`] is
    /// [`InPlace`], the returned pointer is guaranteed to be the same as the passed `ptr`.
    ///
    /// If `ReallocPlacement::MayMove` is used then ownership of the memory block referenced by `ptr`
    /// is transferred to this allocator. The memory may or may not be freed, and should be
    /// considered unusable (unless of course it is transferred back to the caller again via the
    /// return value of this method).
    ///
    /// If this method returns `Err`, then ownership of the memory block has not been transferred to
    /// this allocator, and the contents of the memory block are unaltered.
    ///
    /// The memory block will contain the following contents after a successful call to `grow`:
    ///   * Bytes `0..layout.size()` are preserved from the original allocation.
    ///   * Bytes `layout.size()..old_size` will either be preserved or initialized according to
    ///     [`init`], depending on the allocator implementation. `old_size` refers to the size of
    ///     the `MemoryBlock` prior to the `grow` call, which may be larger than the size
    ///     that was originally requested when it was allocated.
    ///   * Bytes `old_size..new_size` are initialized according to [`init`]. `new_size` refers to
    ///     the size of the `MemoryBlock` returned by the `grow` call.
    ///
    /// [`InPlace`]: ReallocPlacement::InPlace
    /// [`placement`]: ReallocPlacement
    /// [`init`]: AllocInit
    ///
    /// # Safety
    ///
    /// * `ptr` must be [*currently allocated*] via this allocator,
    /// * `layout` must [*fit*] the `ptr`. (The `new_size` argument need not fit it.)
    // We can't require that `new_size` is strictly greater than `memory.size` because of ZSTs.
    // An alternative would be
    // * `new_size must be strictly greater than `memory.size` or both are zero
    /// * `new_size` must be greater than or equal to `layout.size()`
    /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, must not overflow
    ///   (i.e., the rounded value must be less than `usize::MAX`).
    ///
    /// [*currently allocated*]: #currently-allocated-memory
    /// [*fit*]: #memory-fitting
    ///
    /// # Errors
    ///
    /// Returns `Err` if the new layout does not meet the allocator's size and alignment
    /// constraints of the allocator, or if growing otherwise fails.
    ///
    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    unsafe fn grow(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
        placement: ReallocPlacement,
        init: AllocInit,
    ) -> Result<MemoryBlock, AllocErr> {
        match placement {
            ReallocPlacement::InPlace => Err(AllocErr),
            ReallocPlacement::MayMove => {
                let size = layout.size();
                debug_assert!(
                    new_size >= size,
                    "`new_size` must be greater than or equal to `layout.size()`"
                );

                if new_size == size {
                    return Ok(MemoryBlock { ptr, size });
                }

                let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
                let new_memory = self.alloc(new_layout, init)?;
                ptr::copy_nonoverlapping(ptr.as_ptr(), new_memory.ptr.as_ptr(), size);
                self.dealloc(ptr, layout);
                Ok(new_memory)
            }
        }
    }

    /// Attempts to shrink the memory block.
    ///
    /// Returns a new memory block containing a pointer and the actual size of the allocated
    /// block. The pointer is suitable for holding data described by a new layout with `layout`’s
    /// alignment and a size given by `new_size`. To accomplish this, the allocator may shrink the
    /// allocation referenced by `ptr` to fit the new layout. If the [`placement`] is
    /// [`InPlace`], the returned pointer is guaranteed to be the same as the passed `ptr`.
    ///
    /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been
    /// transferred to this allocator. The memory may or may not have been freed, and should be
    /// considered unusable unless it was transferred back to the caller again via the
    /// return value of this method.
    ///
    /// If this method returns `Err`, then ownership of the memory block has not been transferred to
    /// this allocator, and the contents of the memory block are unaltered.
    ///
    /// The behavior of how the allocator tries to shrink the memory is specified by [`placement`].
    ///
    /// [`InPlace`]: ReallocPlacement::InPlace
    /// [`placement`]: ReallocPlacement
    ///
    /// # Safety
    ///
    /// * `ptr` must be [*currently allocated*] via this allocator,
    /// * `layout` must [*fit*] the `ptr`. (The `new_size` argument need not fit it.)
    // We can't require that `new_size` is strictly smaller than `memory.size` because of ZSTs.
    // An alternative would be
    // * `new_size must be strictly smaller than `memory.size` or both are zero
    /// * `new_size` must be smaller than or equal to `layout.size()`
    ///
    /// [*currently allocated*]: #currently-allocated-memory
    /// [*fit*]: #memory-fitting
    ///
    /// # Errors
    ///
    /// Returns `Err` if the new layout does not meet the allocator's size and alignment
    /// constraints of the allocator, or if growing otherwise fails.
    ///
    /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or
    /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement
    /// this trait atop an underlying native allocation library that aborts on memory exhaustion.)
    ///
    /// Clients wishing to abort computation in response to an allocation error are encouraged to
    /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar.
    ///
    /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
    unsafe fn shrink(
        &mut self,
        ptr: NonNull<u8>,
        layout: Layout,
        new_size: usize,
        placement: ReallocPlacement,
    ) -> Result<MemoryBlock, AllocErr> {
        match placement {
            ReallocPlacement::InPlace => Err(AllocErr),
            ReallocPlacement::MayMove => {
                let size = layout.size();
                debug_assert!(
                    new_size <= size,
                    "`new_size` must be smaller than or equal to `layout.size()`"
                );

                if new_size == size {
                    return Ok(MemoryBlock { ptr, size });
                }

                let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
                let new_memory = self.alloc(new_layout, AllocInit::Uninitialized)?;
                ptr::copy_nonoverlapping(ptr.as_ptr(), new_memory.ptr.as_ptr(), new_size);
                self.dealloc(ptr, layout);
                Ok(new_memory)
            }
        }
    }
}
<|endoftext|>