<commit_before>
use std;
use input;
use {
    Action,
    AlwaysSucceed,
    Behavior,
    Event,
    Failure,
    If,
    Input,
    Fail,
    Pressed,
    Released,
    Running,
    Select,
    Sequence,
    Status,
    Success,
    Update,
    UpdateArgs,
    Wait,
    WaitForever,
    WhenAll,
    WhenAny,
    While,
};

/// Keeps track of a behavior.
#[deriving(Clone, PartialEq)]
pub enum State<A, S> {
    /// Returns `Success` when button is pressed.
    PressedState(input::Button),
    /// Returns `Success` when button is released.
    ReleasedState(input::Button),
    /// Executes an action.
    ActionState(A, Option<S>),
    /// Converts `Success` into `Failure` and vice versa.
    FailState(Box<State<A, S>>),
    /// Ignores failures and always return `Success`.
    AlwaysSucceedState(Box<State<A, S>>),
    /// Keeps track of waiting for a period of time before continuing.
    ///
    /// f64: Total time in seconds to wait
    ///
    /// f64: Time elapsed in seconds
    WaitState(f64, f64),
    /// Waits forever.
    WaitForeverState,
    /// Keeps track of an `If` behavior.
    /// If status is `Running`, then it evaluates the condition.
    /// If status is `Success`, then it evaluates the success behavior.
    /// If status is `Failure`, then it evaluates the failure behavior.
    IfState(Box<Behavior<A>>, Box<Behavior<A>>, Status, Box<State<A, S>>),
    /// Keeps track of a `Select` behavior.
    SelectState(Vec<Behavior<A>>, uint, Box<State<A, S>>),
    /// Keeps track of an `Sequence` behavior.
    SequenceState(Vec<Behavior<A>>, uint, Box<State<A, S>>),
    /// Keeps track of a `While` behavior.
    WhileState(Box<State<A, S>>, Vec<Behavior<A>>, uint, Box<State<A, S>>),
    /// Keeps track of a `WhenAll` behavior.
    WhenAllState(Vec<Option<State<A, S>>>),
    /// Keeps track of a `WhenAny` behavior.
    WhenAnyState(Vec<Option<State<A, S>>>),
}

// `WhenAll` and `WhenAny` share same algorithm.
//
// `WhenAll` fails if any fails and succeeds when all succeeds.
// `WhenAny` succeeds if any succeeds and fails when all fails.
fn when_all<A: Clone, S>(
    any: bool,
    cursors: &mut Vec<Option<State<A, S>>>,
    e: &Event,
    f: |dt: f64, action: &A, state: &mut Option<S>| -> (Status, f64)
) -> (Status, f64) {
    let (status, inv_status) = if any {
        // `WhenAny`
        (Failure, Success)
    } else {
        // `WhenAll`
        (Success, Failure)
    };
    // Get the least delta time left over.
    let mut min_dt = std::f64::MAX_VALUE;
    // Count number of terminated events.
    let mut terminated = 0;
    for cur in cursors.iter_mut() {
        match *cur {
            None => {}
            Some(ref mut cur) => {
                match cur.update(e, |dt, a, s| f(dt, a, s)) {
                    (Running, _) => { continue; },
                    (s, new_dt) if s == inv_status => {
                        // Fail for `WhenAll`.
                        // Succeed for `WhenAny`.
                        return (inv_status, new_dt);
                    }
                    (s, new_dt) if s == status => {
                        min_dt = min_dt.min(new_dt);
                    }
                    _ => unreachable!()
                }
            }
        }

        terminated += 1;
        *cur = None;
    }
    match terminated {
        // If there are no events, there is a whole 'dt' left.
        0 if cursors.len() == 0 => (status, match *e {
                Update(UpdateArgs { dt }) => dt,
                // Other kind of events happen instantly.
                _ => 0.0
            }),
        // If all events terminated, the least delta time is left.
        n if cursors.len() == n => (status, min_dt),
        _ => (Running, 0.0)
    }
}

impl<A: Clone, S> State<A, S> {
    /// Creates a state from a behavior.
    pub fn new(behavior: Behavior<A>) -> State<A, S> {
        match behavior {
            Pressed(button) => PressedState(button),
            Released(button) => ReleasedState(button),
            Action(action) => ActionState(action, None),
            Fail(ev) => FailState(box State::new(*ev)),
            AlwaysSucceed(ev) => AlwaysSucceedState(box State::new(*ev)),
            Wait(dt) => WaitState(dt, 0.0),
            WaitForever => WaitForeverState,
            If(condition, success, failure) => {
                let state = State::new(*condition);
                IfState(success, failure, Running, box state)
            }
            Select(sel) => {
                let state = State::new(sel[0].clone());
                SelectState(sel, 0, box state)
            }
            Sequence(seq) => {
                let state = State::new(seq[0].clone());
                SequenceState(seq, 0, box state)
            }
            While(ev, rep) => {
                let state = State::new(rep[0].clone());
                WhileState(box State::new(*ev), rep, 0, box state)
            }
            WhenAll(all)
                => WhenAllState(all.into_iter().map(
                    |ev| Some(State::new(ev))).collect()),
            WhenAny(all)
                => WhenAnyState(all.into_iter().map(
                    |ev| Some(State::new(ev))).collect()),
        }
    }

    /// Updates the cursor that tracks an event.
    ///
    /// The action need to return status and remaining delta time.
    /// Returns status and the remaining delta time.
    pub fn update(
        &mut self,
        e: &Event,
        f: |dt: f64, action: &A, state: &mut Option<S>| -> (Status, f64)
    ) -> (Status, f64) {
        match (e, self) {
            (&Input(input::Press(button_pressed)), &PressedState(button))
            if button_pressed == button => {
                // Button press is considered to happen instantly.
                // There is no remaining delta time because this is input event.
                (Success, 0.0)
            }
            (&Input(input::Release(button_released)), &ReleasedState(button))
            if button_released == button => {
                // Button release is considered to happen instantly.
                // There is no remaining delta time because this is input event.
                (Success, 0.0)
            }
            (&Update(UpdateArgs { dt }),
             &ActionState(ref action, ref mut state)) => {
                // Execute action.
                f(dt, action, state)
            }
            (_, &FailState(ref mut cur)) => {
                match cur.update(e, f) {
                    (Running, dt) => (Running, dt),
                    (Failure, dt) => (Success, dt),
                    (Success, dt) => (Failure, dt),
                }
            }
            (_, &AlwaysSucceedState(ref mut cur)) => {
                match cur.update(e, f) {
                    (Running, dt) => (Running, dt),
                    (_, dt) => (Success, dt),
                }
            }
            (&Update(UpdateArgs { dt }), &WaitState(wait_t, ref mut t)) => {
                if *t + dt >= wait_t {
                    let remaining_dt = *t + dt - wait_t;
                    *t = wait_t;
                    (Success, remaining_dt)
                } else {
                    *t += dt;
                    (Running, 0.0)
                }
            }
            (_, &IfState(ref success, ref failure,
                         ref mut status, ref mut state)) => {
                let mut remaining_dt = match *e {
                        Update(UpdateArgs { dt }) => dt,
                        _ => 0.0,
                    };
                let mut remaining_e;
                // Run in a loop to evaluate success or failure with
                // remaining delta time after condition.
                loop {
                    *status = match *status {
                        Running => {
                            match state.update(e, |dt, a, s| f(dt, a, s)) {
                                (Running, dt) => { return (Running, dt); },
                                (Success, dt) => {
                                    **state = State::new((**success).clone());
                                    remaining_dt = dt;
                                    Success
                                }
                                (Failure, dt) => {
                                    **state = State::new((**failure).clone());
                                    remaining_dt = dt;
                                    Failure
                                }
                            }
                        }
                        _ => {
                            return state.update(match *e {
                                Update(_) => {
                                    remaining_e = Update(UpdateArgs {
                                            dt: remaining_dt
                                        });
                                    &remaining_e
                                }
                                _ => e
                            }, |dt, a, s| f(dt, a, s));
                        }
                    }
                }
            }
            (_, &SelectState(
                ref seq,
                ref mut i,
                ref mut cursor
            )) => {
                let mut remaining_dt = match *e {
                        Update(UpdateArgs { dt }) => dt,
                        _ => 0.0,
                    };
                let mut remaining_e;
                while *i < seq.len() {
                    match cursor.update(
                        match *e {
                            Update(_) => {
                                remaining_e = Update(UpdateArgs {
                                        dt: remaining_dt
                                    });
                                &remaining_e
                            }
                            _ => e
                        },
                        |dt, a, s| f(dt, a, s)) {
                        (Success, x) => { return (Success, x) }
                        (Running, _) => { break }
                        (Failure, new_dt) => { remaining_dt = new_dt }
                    };
                    *i += 1;
                    // If end of sequence,
                    // return the 'dt' that is left.
                    if *i >= seq.len() { return (Failure, remaining_dt); }
                    // Create a new cursor for next event.
                    // Use the same pointer to avoid allocation.
                    **cursor = State::new(seq[*i].clone());
                }
                (Running, 0.0)
            }
            (_, &SequenceState(ref seq, ref mut i, ref mut cursor)) => {
                let cur = cursor;
                let mut remaining_dt = match *e {
                        Update(UpdateArgs { dt }) => dt,
                        _ => 0.0,
                    };
                let mut remaining_e;
                while *i < seq.len() {
                    match cur.update(match *e {
                            Update(_) => {
                                remaining_e = Update(UpdateArgs {
                                        dt: remaining_dt
                                    });
                                &remaining_e
                            }
                            _ => e
                        },
                        |dt, a, s| f(dt, a, s)) {
                        (Failure, x) => return (Failure, x),
                        (Running, _) => { break },
                        (Success, new_dt) => {
                            remaining_dt = match *e {
                                // Change update event with remaining delta time.
                                Update(_) => new_dt,
                                // Other events are 'consumed' and not passed to next.
                                // If this is the last event, then the sequence succeeded.
                                _ => if *i == seq.len() - 1 {
                                        return (Success, new_dt)
                                    } else {
                                        return (Running, 0.0)
                                    }
                            }
                        }
                    };
                    *i += 1;
                    // If end of sequence,
                    // return the 'dt' that is left.
                    if *i >= seq.len() { return (Success, remaining_dt); }
                    // Create a new cursor for next event.
                    // Use the same pointer to avoid allocation.
                    **cur = State::new(seq[*i].clone());
                }
                (Running, 0.0)
            }
            (_, &WhileState(ref mut ev_cursor, ref rep, ref mut i,
                            ref mut cursor)) => {
                // If the event terminates, do not execute the loop.
                match ev_cursor.update(e, |dt, a, s| f(dt, a, s)) {
                    (Running, _) => {}
                    x => return x,
                };
                let cur = cursor;
                let mut remaining_dt = match *e {
                        Update(UpdateArgs { dt }) => dt,
                        _ => 0.0,
                    };
                let mut remaining_e;
                loop {
                    match cur.update(match *e {
                            Update(_) => {
                                remaining_e = Update(UpdateArgs {
                                        dt: remaining_dt
                                    });
                                &remaining_e
                            }
                            _ => e
                        },
                        |dt, a, s| f(dt, a, s)) {
                        (Failure, x) => return (Failure, x),
                        (Running, _) => { break },
                        (Success, new_dt) => {
                            remaining_dt = match *e {
                                // Change update event with remaining delta time.
                                Update(_) => new_dt,
                                // Other events are 'consumed' and not passed to next.
                                _ => return (Running, 0.0)
                            }
                        }
                    };
                    *i += 1;
                    // If end of repeated events,
                    // start over from the first one.
                    if *i >= rep.len() { *i = 0; }
                    // Create a new cursor for next event.
                    // Use the same pointer to avoid allocation.
                    **cur = State::new(rep[*i].clone());
                }
                (Running, 0.0)
            }
            (_, &WhenAllState(ref mut cursors)) => {
                let any = false;
                when_all(any, cursors, e, f)
            }
            (_, &WhenAnyState(ref mut cursors)) => {
                let any = true;
                when_all(any, cursors, e, f)
            }
            _ => (Running, 0.0)
        }
    }
}
<commit_msg>Use same algorithm for `Select` and `Sequence`<commit_after>
use std;
use input;
use {
    Action,
    AlwaysSucceed,
    Behavior,
    Event,
    Failure,
    If,
    Input,
    Fail,
    Pressed,
    Released,
    Running,
    Select,
    Sequence,
    Status,
    Success,
    Update,
    UpdateArgs,
    Wait,
    WaitForever,
    WhenAll,
    WhenAny,
    While,
};

/// Keeps track of a behavior.
#[deriving(Clone, PartialEq)]
pub enum State<A, S> {
    /// Returns `Success` when button is pressed.
    PressedState(input::Button),
    /// Returns `Success` when button is released.
    ReleasedState(input::Button),
    /// Executes an action.
    ActionState(A, Option<S>),
    /// Converts `Success` into `Failure` and vice versa.
    FailState(Box<State<A, S>>),
    /// Ignores failures and always return `Success`.
    AlwaysSucceedState(Box<State<A, S>>),
    /// Keeps track of waiting for a period of time before continuing.
    ///
    /// f64: Total time in seconds to wait
    ///
    /// f64: Time elapsed in seconds
    WaitState(f64, f64),
    /// Waits forever.
    WaitForeverState,
    /// Keeps track of an `If` behavior.
    /// If status is `Running`, then it evaluates the condition.
    /// If status is `Success`, then it evaluates the success behavior.
    /// If status is `Failure`, then it evaluates the failure behavior.
    IfState(Box<Behavior<A>>, Box<Behavior<A>>, Status, Box<State<A, S>>),
    /// Keeps track of a `Select` behavior.
    SelectState(Vec<Behavior<A>>, uint, Box<State<A, S>>),
    /// Keeps track of an `Sequence` behavior.
    SequenceState(Vec<Behavior<A>>, uint, Box<State<A, S>>),
    /// Keeps track of a `While` behavior.
    WhileState(Box<State<A, S>>, Vec<Behavior<A>>, uint, Box<State<A, S>>),
    /// Keeps track of a `WhenAll` behavior.
    WhenAllState(Vec<Option<State<A, S>>>),
    /// Keeps track of a `WhenAny` behavior.
    WhenAnyState(Vec<Option<State<A, S>>>),
}

// `Sequence` and `Select` share same algorithm.
//
// `Sequence` fails if any fails and succeeds when all succeeds.
// `Select` succeeds if any succeeds and fails when all fails.
fn sequence<A: Clone, S>(
    select: bool,
    seq: &Vec<Behavior<A>>,
    i: &mut uint,
    cursor: &mut Box<State<A, S>>,
    e: &Event,
    f: |dt: f64, action: &A, state: &mut Option<S>| -> (Status, f64)
) -> (Status, f64) {
    let (status, inv_status) = if select {
        // `Select`
        (Failure, Success)
    } else {
        // `Sequence`
        (Success, Failure)
    };
    let mut remaining_dt = match *e {
            Update(UpdateArgs { dt }) => dt,
            _ => 0.0,
        };
    let mut remaining_e;
    while *i < seq.len() {
        match cursor.update(
            match *e {
                Update(_) => {
                    remaining_e = Update(
                        UpdateArgs {
                            dt: remaining_dt
                        }
                    );
                    &remaining_e
                }
                _ => e
            },
            |dt, a, s| f(dt, a, s)) {
            (Running, _) => { break; },
            (s, new_dt) if s == inv_status => {
                return (inv_status, new_dt);
            }
            (s, new_dt) if s == status => {
                remaining_dt = match *e {
                    // Change update event with remaining delta time.
                    Update(_) => new_dt,
                    // Other events are 'consumed' and not passed to next.
                    // If this is the last event, then the sequence succeeded.
                    _ => if *i == seq.len() - 1 {
                            return (status, new_dt)
                        } else {
                            return (Running, 0.0)
                        }
                }
            }
            _ => unreachable!()
        };
        *i += 1;
        // If end of sequence,
        // return the 'dt' that is left.
        if *i >= seq.len() { return (status, remaining_dt); }
        // Create a new cursor for next event.
        // Use the same pointer to avoid allocation.
        **cursor  = State::new(seq[*i].clone());
    }
    (Running, 0.0)
}

// `WhenAll` and `WhenAny` share same algorithm.
//
// `WhenAll` fails if any fails and succeeds when all succeeds.
// `WhenAny` succeeds if any succeeds and fails when all fails.
fn when_all<A: Clone, S>(
    any: bool,
    cursors: &mut Vec<Option<State<A, S>>>,
    e: &Event,
    f: |dt: f64, action: &A, state: &mut Option<S>| -> (Status, f64)
) -> (Status, f64) {
    let (status, inv_status) = if any {
        // `WhenAny`
        (Failure, Success)
    } else {
        // `WhenAll`
        (Success, Failure)
    };
    // Get the least delta time left over.
    let mut min_dt = std::f64::MAX_VALUE;
    // Count number of terminated events.
    let mut terminated = 0;
    for cur in cursors.iter_mut() {
        match *cur {
            None => {}
            Some(ref mut cur) => {
                match cur.update(e, |dt, a, s| f(dt, a, s)) {
                    (Running, _) => { continue; },
                    (s, new_dt) if s == inv_status => {
                        // Fail for `WhenAll`.
                        // Succeed for `WhenAny`.
                        return (inv_status, new_dt);
                    }
                    (s, new_dt) if s == status => {
                        min_dt = min_dt.min(new_dt);
                    }
                    _ => unreachable!()
                }
            }
        }

        terminated += 1;
        *cur = None;
    }
    match terminated {
        // If there are no events, there is a whole 'dt' left.
        0 if cursors.len() == 0 => (status, match *e {
                Update(UpdateArgs { dt }) => dt,
                // Other kind of events happen instantly.
                _ => 0.0
            }),
        // If all events terminated, the least delta time is left.
        n if cursors.len() == n => (status, min_dt),
        _ => (Running, 0.0)
    }
}

impl<A: Clone, S> State<A, S> {
    /// Creates a state from a behavior.
    pub fn new(behavior: Behavior<A>) -> State<A, S> {
        match behavior {
            Pressed(button) => PressedState(button),
            Released(button) => ReleasedState(button),
            Action(action) => ActionState(action, None),
            Fail(ev) => FailState(box State::new(*ev)),
            AlwaysSucceed(ev) => AlwaysSucceedState(box State::new(*ev)),
            Wait(dt) => WaitState(dt, 0.0),
            WaitForever => WaitForeverState,
            If(condition, success, failure) => {
                let state = State::new(*condition);
                IfState(success, failure, Running, box state)
            }
            Select(sel) => {
                let state = State::new(sel[0].clone());
                SelectState(sel, 0, box state)
            }
            Sequence(seq) => {
                let state = State::new(seq[0].clone());
                SequenceState(seq, 0, box state)
            }
            While(ev, rep) => {
                let state = State::new(rep[0].clone());
                WhileState(box State::new(*ev), rep, 0, box state)
            }
            WhenAll(all)
                => WhenAllState(all.into_iter().map(
                    |ev| Some(State::new(ev))).collect()),
            WhenAny(all)
                => WhenAnyState(all.into_iter().map(
                    |ev| Some(State::new(ev))).collect()),
        }
    }

    /// Updates the cursor that tracks an event.
    ///
    /// The action need to return status and remaining delta time.
    /// Returns status and the remaining delta time.
    pub fn update(
        &mut self,
        e: &Event,
        f: |dt: f64, action: &A, state: &mut Option<S>| -> (Status, f64)
    ) -> (Status, f64) {
        match (e, self) {
            (&Input(input::Press(button_pressed)), &PressedState(button))
            if button_pressed == button => {
                // Button press is considered to happen instantly.
                // There is no remaining delta time because this is input event.
                (Success, 0.0)
            }
            (&Input(input::Release(button_released)), &ReleasedState(button))
            if button_released == button => {
                // Button release is considered to happen instantly.
                // There is no remaining delta time because this is input event.
                (Success, 0.0)
            }
            (&Update(UpdateArgs { dt }),
             &ActionState(ref action, ref mut state)) => {
                // Execute action.
                f(dt, action, state)
            }
            (_, &FailState(ref mut cur)) => {
                match cur.update(e, f) {
                    (Running, dt) => (Running, dt),
                    (Failure, dt) => (Success, dt),
                    (Success, dt) => (Failure, dt),
                }
            }
            (_, &AlwaysSucceedState(ref mut cur)) => {
                match cur.update(e, f) {
                    (Running, dt) => (Running, dt),
                    (_, dt) => (Success, dt),
                }
            }
            (&Update(UpdateArgs { dt }), &WaitState(wait_t, ref mut t)) => {
                if *t + dt >= wait_t {
                    let remaining_dt = *t + dt - wait_t;
                    *t = wait_t;
                    (Success, remaining_dt)
                } else {
                    *t += dt;
                    (Running, 0.0)
                }
            }
            (_, &IfState(ref success, ref failure,
                         ref mut status, ref mut state)) => {
                let mut remaining_dt = match *e {
                        Update(UpdateArgs { dt }) => dt,
                        _ => 0.0,
                    };
                let mut remaining_e;
                // Run in a loop to evaluate success or failure with
                // remaining delta time after condition.
                loop {
                    *status = match *status {
                        Running => {
                            match state.update(e, |dt, a, s| f(dt, a, s)) {
                                (Running, dt) => { return (Running, dt); },
                                (Success, dt) => {
                                    **state = State::new((**success).clone());
                                    remaining_dt = dt;
                                    Success
                                }
                                (Failure, dt) => {
                                    **state = State::new((**failure).clone());
                                    remaining_dt = dt;
                                    Failure
                                }
                            }
                        }
                        _ => {
                            return state.update(match *e {
                                Update(_) => {
                                    remaining_e = Update(UpdateArgs {
                                            dt: remaining_dt
                                        });
                                    &remaining_e
                                }
                                _ => e
                            }, |dt, a, s| f(dt, a, s));
                        }
                    }
                }
            }
            (_, &SelectState(ref seq, ref mut i, ref mut cursor)) => {
                let select = false;
                sequence(select, seq, i, cursor, e, f)
            }
            (_, &SequenceState(ref seq, ref mut i, ref mut cursor)) => {
                let select = true;
                sequence(select, seq, i, cursor, e, f)
            }
            (_, &WhileState(ref mut ev_cursor, ref rep, ref mut i,
                            ref mut cursor)) => {
                // If the event terminates, do not execute the loop.
                match ev_cursor.update(e, |dt, a, s| f(dt, a, s)) {
                    (Running, _) => {}
                    x => return x,
                };
                let cur = cursor;
                let mut remaining_dt = match *e {
                        Update(UpdateArgs { dt }) => dt,
                        _ => 0.0,
                    };
                let mut remaining_e;
                loop {
                    match cur.update(match *e {
                            Update(_) => {
                                remaining_e = Update(UpdateArgs {
                                        dt: remaining_dt
                                    });
                                &remaining_e
                            }
                            _ => e
                        },
                        |dt, a, s| f(dt, a, s)) {
                        (Failure, x) => return (Failure, x),
                        (Running, _) => { break },
                        (Success, new_dt) => {
                            remaining_dt = match *e {
                                // Change update event with remaining delta time.
                                Update(_) => new_dt,
                                // Other events are 'consumed' and not passed to next.
                                _ => return (Running, 0.0)
                            }
                        }
                    };
                    *i += 1;
                    // If end of repeated events,
                    // start over from the first one.
                    if *i >= rep.len() { *i = 0; }
                    // Create a new cursor for next event.
                    // Use the same pointer to avoid allocation.
                    **cur = State::new(rep[*i].clone());
                }
                (Running, 0.0)
            }
            (_, &WhenAllState(ref mut cursors)) => {
                let any = false;
                when_all(any, cursors, e, f)
            }
            (_, &WhenAnyState(ref mut cursors)) => {
                let any = true;
                when_all(any, cursors, e, f)
            }
            _ => (Running, 0.0)
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use js::jsapi::{JSContext, jsid, JSPropertyDescriptor, JSObject, JSString, jschar};
use js::jsapi::bindgen::{JS_GetPropertyDescriptorById, JS_NewUCString, JS_malloc, JS_free};
use js::glue::bindgen::{RUST_JSVAL_IS_VOID, RUST_JSVAL_TO_OBJECT, GetProxyExtra};
use js::glue::bindgen::{GetObjectProto};

use core::sys::size_of;

type c_bool = libc::c_int;

pub extern fn getPropertyDescriptor(cx: *JSContext, proxy: *JSObject, id: jsid,
                                set: c_bool, desc: *mut JSPropertyDescriptor) -> c_bool {
  unsafe {
    if _getOwnPropertyDescriptor(cx, proxy, id, set, desc) == 0 {
        return 0;
    }
    if (*desc).obj.is_not_null() {
        return 1;
    }

    //let proto = JS_GetPrototype(proxy);
    let proto = GetObjectProto(proxy);
    if proto.is_null() {
        (*desc).obj = ptr::null();
        return 1;
    }

    JS_GetPropertyDescriptorById(cx, proto, id, 0x01 /*JSRESOLVE_QUALIFIED*/,
                                 cast::transmute(desc))
  }
}

fn _getOwnPropertyDescriptor(cx: *JSContext, proxy: *JSObject, id: jsid,
                             _set: c_bool, desc: *mut JSPropertyDescriptor) -> c_bool {
  unsafe {
    let v = GetProxyExtra(proxy, 0 /*JSPROXYSLOT_EXPANDO*/);
    if RUST_JSVAL_IS_VOID(v) == 0 {
        let expando = RUST_JSVAL_TO_OBJECT(v);
        if JS_GetPropertyDescriptorById(cx, expando, id, 0x01 /*JSRESOLVE_QUALIFIED*/,
                                        cast::transmute(desc)) == 0 {
            return 0;
        }
        if (*desc).obj.is_not_null() {
            (*desc).obj = proxy;
            return 1;
        }
    }
    (*desc).obj = ptr::null();
    1
  }
}

pub extern fn getOwnPropertyDescriptor(cx: *JSContext, proxy: *JSObject, id: jsid,
                                   set: c_bool, desc: *mut JSPropertyDescriptor) -> c_bool {
    _getOwnPropertyDescriptor(cx, proxy, id, set, desc)
}

pub fn _obj_toString(cx: *JSContext, className: *libc::c_char) -> *JSString {
  unsafe {
    let name = str::raw::from_buf(className as *u8);
    let nchars = "[object ]".len() + name.len();
    let chars: *mut jschar = cast::transmute(JS_malloc(cx, nchars as u64 * (size_of::<jschar>() as u64)));
    if chars.is_null() {
        return ptr::null();
    }

    let result = ~"[object " + name + ~"]";
    for result.each_chari |i, c| {
      *chars.offset(i) = c as jschar;
    }
    *chars.offset(nchars) = 0;
    let jsstr = JS_NewUCString(cx, cast::transmute(chars), nchars as u64);
    if jsstr.is_null() {
        JS_free(cx, cast::transmute(chars));
    }
    jsstr
  }
}

pub fn GetExpandoObject(_proxy: *JSObject) -> *JSObject {
    ptr::null()
}<commit_msg>Fix write past buffer length for proxy toString operation.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use js::jsapi::{JSContext, jsid, JSPropertyDescriptor, JSObject, JSString, jschar};
use js::jsapi::bindgen::{JS_GetPropertyDescriptorById, JS_NewUCString, JS_malloc, JS_free};
use js::glue::bindgen::{RUST_JSVAL_IS_VOID, RUST_JSVAL_TO_OBJECT, GetProxyExtra};
use js::glue::bindgen::{GetObjectProto};

use core::sys::size_of;

type c_bool = libc::c_int;

pub extern fn getPropertyDescriptor(cx: *JSContext, proxy: *JSObject, id: jsid,
                                set: c_bool, desc: *mut JSPropertyDescriptor) -> c_bool {
  unsafe {
    if _getOwnPropertyDescriptor(cx, proxy, id, set, desc) == 0 {
        return 0;
    }
    if (*desc).obj.is_not_null() {
        return 1;
    }

    //let proto = JS_GetPrototype(proxy);
    let proto = GetObjectProto(proxy);
    if proto.is_null() {
        (*desc).obj = ptr::null();
        return 1;
    }

    JS_GetPropertyDescriptorById(cx, proto, id, 0x01 /*JSRESOLVE_QUALIFIED*/,
                                 cast::transmute(desc))
  }
}

fn _getOwnPropertyDescriptor(cx: *JSContext, proxy: *JSObject, id: jsid,
                             _set: c_bool, desc: *mut JSPropertyDescriptor) -> c_bool {
  unsafe {
    let v = GetProxyExtra(proxy, 0 /*JSPROXYSLOT_EXPANDO*/);
    if RUST_JSVAL_IS_VOID(v) == 0 {
        let expando = RUST_JSVAL_TO_OBJECT(v);
        if JS_GetPropertyDescriptorById(cx, expando, id, 0x01 /*JSRESOLVE_QUALIFIED*/,
                                        cast::transmute(desc)) == 0 {
            return 0;
        }
        if (*desc).obj.is_not_null() {
            (*desc).obj = proxy;
            return 1;
        }
    }
    (*desc).obj = ptr::null();
    1
  }
}

pub extern fn getOwnPropertyDescriptor(cx: *JSContext, proxy: *JSObject, id: jsid,
                                   set: c_bool, desc: *mut JSPropertyDescriptor) -> c_bool {
    _getOwnPropertyDescriptor(cx, proxy, id, set, desc)
}

pub fn _obj_toString(cx: *JSContext, className: *libc::c_char) -> *JSString {
  unsafe {
    let name = str::raw::from_buf(className as *u8);
    let nchars = "[object ]".len() + name.len();
    let chars: *mut jschar = cast::transmute(JS_malloc(cx, (nchars + 1) as u64 * (size_of::<jschar>() as u64)));
    if chars.is_null() {
        return ptr::null();
    }

    let result = ~"[object " + name + ~"]";
    for result.each_chari |i, c| {
      *chars.offset(i) = c as jschar;
    }
    *chars.offset(nchars) = 0;
    let jsstr = JS_NewUCString(cx, cast::transmute(chars), nchars as u64);
    if jsstr.is_null() {
        JS_free(cx, cast::transmute(chars));
    }
    jsstr
  }
}

pub fn GetExpandoObject(_proxy: *JSObject) -> *JSObject {
    ptr::null()
}<|endoftext|>


<commit_before>#![feature(cfg_target_thread_local, thread_local_internals)]

// On platforms *without* `#[thread_local]`, use
// a custom non-`Sync` type to fake the same error.
#[cfg(not(target_thread_local))]
struct Key<T> {
    _data: std::cell::UnsafeCell<Option<T>>,
    _flag: std::cell::Cell<bool>,
}

#[cfg(not(target_thread_local))]
impl<T> Key<T> {
    const fn new() -> Self {
        Key {
            _data: std::cell::UnsafeCell::new(None),
            _flag: std::cell::Cell::new(false),
        }
    }
}

#[cfg(target_thread_local)]
use std::thread::__FastLocalKeyInner as Key;

static __KEY: Key<()> = Key::new();
//~^ ERROR `std::cell::UnsafeCell<std::option::Option<()>>` cannot be shared between threads
//~| ERROR `std::cell::Cell<std::thread::local::fast::DtorState>` cannot be shared between threads
// safely [E0277]

fn main() {}
<commit_msg>fix compile-fail test for targets without thread locals<commit_after>#![feature(cfg_target_thread_local, thread_local_internals)]

// On platforms *without* `#[thread_local]`, use
// a custom non-`Sync` type to fake the same error.
#[cfg(not(target_thread_local))]
struct Key<T> {
    _data: std::cell::UnsafeCell<Option<T>>,
    _flag: std::cell::Cell<()>,
}

#[cfg(not(target_thread_local))]
impl<T> Key<T> {
    const fn new() -> Self {
        Key {
            _data: std::cell::UnsafeCell::new(None),
            _flag: std::cell::Cell::new(()),
        }
    }
}

#[cfg(target_thread_local)]
use std::thread::__FastLocalKeyInner as Key;

static __KEY: Key<()> = Key::new();
//~^ ERROR `std::cell::UnsafeCell<std::option::Option<()>>` cannot be shared between threads
//~| ERROR cannot be shared between threads safely [E0277]

fn main() {}
<|endoftext|>


<commit_before>//xfail-stage1
//xfail-stage2
//xfail-stage3

// Test case for issue #435.
obj foo() {
    fn add5(n: int) -> int {
        ret n + 5;
    }
}

fn add5(n: int) -> int {
    ret n + 5;
}

fn main() {
    let fiveplusseven = bind add5(7);
    assert add5(7) == 12;
    assert fiveplusseven() == 12;

    let my_foo = foo();
    let fiveplusseven_too = bind my_foo.add5(7);
    assert my_foo.add5(7) == 12;
    assert fiveplusseven_too() == 12;
}

<commit_msg>Un-XFAIL a test.  Issue #435.<commit_after>// Test case for issue #435.
obj foo() {
    fn add5(n: int) -> int {
        ret n + 5;
    }
}

fn add5(n: int) -> int {
    ret n + 5;
}

fn main() {
    let fiveplusseven = bind add5(7);
    assert add5(7) == 12;
    assert fiveplusseven() == 12;

    let my_foo = foo();
    let fiveplusseven_too = bind my_foo.add5(7);
    assert my_foo.add5(7) == 12;
    assert fiveplusseven_too() == 12;
}

<|endoftext|>


<commit_before>use bytes::Buf;
use h2::SendStream;
use http::header::{
    HeaderName, CONNECTION, PROXY_AUTHENTICATE, PROXY_AUTHORIZATION, TE, TRAILER,
    TRANSFER_ENCODING, UPGRADE,
};
use http::HeaderMap;
use pin_project::pin_project;
use std::error::Error as StdError;

use super::DecodedLength;
use crate::body::HttpBody;
use crate::common::{task, Future, Pin, Poll};
use crate::headers::content_length_parse_all;

pub(crate) mod client;
pub(crate) mod ping;
pub(crate) mod server;

pub(crate) use self::client::ClientTask;
pub(crate) use self::server::Server;

/// Default initial stream window size defined in HTTP2 spec.
pub(crate) const SPEC_WINDOW_SIZE: u32 = 65_535;

fn strip_connection_headers(headers: &mut HeaderMap, is_request: bool) {
    // List of connection headers from:
    // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Connection
    //
    // TE headers are allowed in HTTP/2 requests as long as the value is "trailers", so they're
    // tested separately.
    let connection_headers = [
        HeaderName::from_lowercase(b"keep-alive").unwrap(),
        HeaderName::from_lowercase(b"proxy-connection").unwrap(),
        PROXY_AUTHENTICATE,
        PROXY_AUTHORIZATION,
        TRAILER,
        TRANSFER_ENCODING,
        UPGRADE,
    ];

    for header in connection_headers.iter() {
        if headers.remove(header).is_some() {
            warn!("Connection header illegal in HTTP/2: {}", header.as_str());
        }
    }

    if is_request {
        if headers
            .get(TE)
            .map(|te_header| te_header != "trailers")
            .unwrap_or(false)
        {
            warn!("TE headers not set to \"trailers\" are illegal in HTTP/2 requests");
            headers.remove(TE);
        }
    } else if headers.remove(TE).is_some() {
        warn!("TE headers illegal in HTTP/2 responses");
    }

    if let Some(header) = headers.remove(CONNECTION) {
        warn!(
            "Connection header illegal in HTTP/2: {}",
            CONNECTION.as_str()
        );
        let header_contents = header.to_str().unwrap();

        // A `Connection` header may have a comma-separated list of names of other headers that
        // are meant for only this specific connection.
        //
        // Iterate these names and remove them as headers. Connection-specific headers are
        // forbidden in HTTP2, as that information has been moved into frame types of the h2
        // protocol.
        for name in header_contents.split(',') {
            let name = name.trim();
            headers.remove(name);
        }
    }
}

fn decode_content_length(headers: &HeaderMap) -> DecodedLength {
    if let Some(len) = content_length_parse_all(headers) {
        // If the length is u64::MAX, oh well, just reported chunked.
        DecodedLength::checked_new(len).unwrap_or_else(|_| DecodedLength::CHUNKED)
    } else {
        DecodedLength::CHUNKED
    }
}

// body adapters used by both Client and Server

#[pin_project]
struct PipeToSendStream<S>
where
    S: HttpBody,
{
    body_tx: SendStream<SendBuf<S::Data>>,
    data_done: bool,
    #[pin]
    stream: S,
}

impl<S> PipeToSendStream<S>
where
    S: HttpBody,
{
    fn new(stream: S, tx: SendStream<SendBuf<S::Data>>) -> PipeToSendStream<S> {
        PipeToSendStream {
            body_tx: tx,
            data_done: false,
            stream,
        }
    }
}

impl<S> Future for PipeToSendStream<S>
where
    S: HttpBody,
    S::Error: Into<Box<dyn StdError + Send + Sync>>,
{
    type Output = crate::Result<()>;

    fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
        let mut me = self.project();
        loop {
            if !*me.data_done {
                // we don't have the next chunk of data yet, so just reserve 1 byte to make
                // sure there's some capacity available. h2 will handle the capacity management
                // for the actual body chunk.
                me.body_tx.reserve_capacity(1);

                if me.body_tx.capacity() == 0 {
                    loop {
                        match ready!(me.body_tx.poll_capacity(cx)) {
                            Some(Ok(0)) => {}
                            Some(Ok(_)) => break,
                            Some(Err(e)) => {
                                return Poll::Ready(Err(crate::Error::new_body_write(e)))
                            }
                            None => {
                                // None means the stream is no longer in a
                                // streaming state, we either finished it
                                // somehow, or the remote reset us.
                                return Poll::Ready(Err(crate::Error::new_body_write(
                                    "send stream capacity unexpectedly closed",
                                )));
                            }
                        }
                    }
                } else if let Poll::Ready(reason) = me
                    .body_tx
                    .poll_reset(cx)
                    .map_err(crate::Error::new_body_write)?
                {
                    debug!("stream received RST_STREAM: {:?}", reason);
                    return Poll::Ready(Err(crate::Error::new_body_write(::h2::Error::from(
                        reason,
                    ))));
                }

                match ready!(me.stream.as_mut().poll_data(cx)) {
                    Some(Ok(chunk)) => {
                        let is_eos = me.stream.is_end_stream();
                        trace!(
                            "send body chunk: {} bytes, eos={}",
                            chunk.remaining(),
                            is_eos,
                        );

                        let buf = SendBuf(Some(chunk));
                        me.body_tx
                            .send_data(buf, is_eos)
                            .map_err(crate::Error::new_body_write)?;

                        if is_eos {
                            return Poll::Ready(Ok(()));
                        }
                    }
                    Some(Err(e)) => return Poll::Ready(Err(me.body_tx.on_user_err(e))),
                    None => {
                        me.body_tx.reserve_capacity(0);
                        let is_eos = me.stream.is_end_stream();
                        if is_eos {
                            return Poll::Ready(me.body_tx.send_eos_frame());
                        } else {
                            *me.data_done = true;
                            // loop again to poll_trailers
                        }
                    }
                }
            } else {
                if let Poll::Ready(reason) = me
                    .body_tx
                    .poll_reset(cx)
                    .map_err(crate::Error::new_body_write)?
                {
                    debug!("stream received RST_STREAM: {:?}", reason);
                    return Poll::Ready(Err(crate::Error::new_body_write(::h2::Error::from(
                        reason,
                    ))));
                }

                match ready!(me.stream.poll_trailers(cx)) {
                    Ok(Some(trailers)) => {
                        me.body_tx
                            .send_trailers(trailers)
                            .map_err(crate::Error::new_body_write)?;
                        return Poll::Ready(Ok(()));
                    }
                    Ok(None) => {
                        // There were no trailers, so send an empty DATA frame...
                        return Poll::Ready(me.body_tx.send_eos_frame());
                    }
                    Err(e) => return Poll::Ready(Err(me.body_tx.on_user_err(e))),
                }
            }
        }
    }
}

trait SendStreamExt {
    fn on_user_err<E>(&mut self, err: E) -> crate::Error
    where
        E: Into<Box<dyn std::error::Error + Send + Sync>>;
    fn send_eos_frame(&mut self) -> crate::Result<()>;
}

impl<B: Buf> SendStreamExt for SendStream<SendBuf<B>> {
    fn on_user_err<E>(&mut self, err: E) -> crate::Error
    where
        E: Into<Box<dyn std::error::Error + Send + Sync>>,
    {
        let err = crate::Error::new_user_body(err);
        debug!("send body user stream error: {}", err);
        self.send_reset(err.h2_reason());
        err
    }

    fn send_eos_frame(&mut self) -> crate::Result<()> {
        trace!("send body eos");
        self.send_data(SendBuf(None), true)
            .map_err(crate::Error::new_body_write)
    }
}

struct SendBuf<B>(Option<B>);

impl<B: Buf> Buf for SendBuf<B> {
    #[inline]
    fn remaining(&self) -> usize {
        self.0.as_ref().map(|b| b.remaining()).unwrap_or(0)
    }

    #[inline]
    fn bytes(&self) -> &[u8] {
        self.0.as_ref().map(|b| b.bytes()).unwrap_or(&[])
    }

    #[inline]
    fn advance(&mut self, cnt: usize) {
        if let Some(b) = self.0.as_mut() {
            b.advance(cnt)
        }
    }
}
<commit_msg>perf(h2): forward Buf::bytes_vectored to SendBuf<commit_after>use bytes::Buf;
use h2::SendStream;
use http::header::{
    HeaderName, CONNECTION, PROXY_AUTHENTICATE, PROXY_AUTHORIZATION, TE, TRAILER,
    TRANSFER_ENCODING, UPGRADE,
};
use http::HeaderMap;
use pin_project::pin_project;
use std::error::Error as StdError;
use std::io::IoSlice;

use super::DecodedLength;
use crate::body::HttpBody;
use crate::common::{task, Future, Pin, Poll};
use crate::headers::content_length_parse_all;

pub(crate) mod client;
pub(crate) mod ping;
pub(crate) mod server;

pub(crate) use self::client::ClientTask;
pub(crate) use self::server::Server;

/// Default initial stream window size defined in HTTP2 spec.
pub(crate) const SPEC_WINDOW_SIZE: u32 = 65_535;

fn strip_connection_headers(headers: &mut HeaderMap, is_request: bool) {
    // List of connection headers from:
    // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Connection
    //
    // TE headers are allowed in HTTP/2 requests as long as the value is "trailers", so they're
    // tested separately.
    let connection_headers = [
        HeaderName::from_lowercase(b"keep-alive").unwrap(),
        HeaderName::from_lowercase(b"proxy-connection").unwrap(),
        PROXY_AUTHENTICATE,
        PROXY_AUTHORIZATION,
        TRAILER,
        TRANSFER_ENCODING,
        UPGRADE,
    ];

    for header in connection_headers.iter() {
        if headers.remove(header).is_some() {
            warn!("Connection header illegal in HTTP/2: {}", header.as_str());
        }
    }

    if is_request {
        if headers
            .get(TE)
            .map(|te_header| te_header != "trailers")
            .unwrap_or(false)
        {
            warn!("TE headers not set to \"trailers\" are illegal in HTTP/2 requests");
            headers.remove(TE);
        }
    } else if headers.remove(TE).is_some() {
        warn!("TE headers illegal in HTTP/2 responses");
    }

    if let Some(header) = headers.remove(CONNECTION) {
        warn!(
            "Connection header illegal in HTTP/2: {}",
            CONNECTION.as_str()
        );
        let header_contents = header.to_str().unwrap();

        // A `Connection` header may have a comma-separated list of names of other headers that
        // are meant for only this specific connection.
        //
        // Iterate these names and remove them as headers. Connection-specific headers are
        // forbidden in HTTP2, as that information has been moved into frame types of the h2
        // protocol.
        for name in header_contents.split(',') {
            let name = name.trim();
            headers.remove(name);
        }
    }
}

fn decode_content_length(headers: &HeaderMap) -> DecodedLength {
    if let Some(len) = content_length_parse_all(headers) {
        // If the length is u64::MAX, oh well, just reported chunked.
        DecodedLength::checked_new(len).unwrap_or_else(|_| DecodedLength::CHUNKED)
    } else {
        DecodedLength::CHUNKED
    }
}

// body adapters used by both Client and Server

#[pin_project]
struct PipeToSendStream<S>
where
    S: HttpBody,
{
    body_tx: SendStream<SendBuf<S::Data>>,
    data_done: bool,
    #[pin]
    stream: S,
}

impl<S> PipeToSendStream<S>
where
    S: HttpBody,
{
    fn new(stream: S, tx: SendStream<SendBuf<S::Data>>) -> PipeToSendStream<S> {
        PipeToSendStream {
            body_tx: tx,
            data_done: false,
            stream,
        }
    }
}

impl<S> Future for PipeToSendStream<S>
where
    S: HttpBody,
    S::Error: Into<Box<dyn StdError + Send + Sync>>,
{
    type Output = crate::Result<()>;

    fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Self::Output> {
        let mut me = self.project();
        loop {
            if !*me.data_done {
                // we don't have the next chunk of data yet, so just reserve 1 byte to make
                // sure there's some capacity available. h2 will handle the capacity management
                // for the actual body chunk.
                me.body_tx.reserve_capacity(1);

                if me.body_tx.capacity() == 0 {
                    loop {
                        match ready!(me.body_tx.poll_capacity(cx)) {
                            Some(Ok(0)) => {}
                            Some(Ok(_)) => break,
                            Some(Err(e)) => {
                                return Poll::Ready(Err(crate::Error::new_body_write(e)))
                            }
                            None => {
                                // None means the stream is no longer in a
                                // streaming state, we either finished it
                                // somehow, or the remote reset us.
                                return Poll::Ready(Err(crate::Error::new_body_write(
                                    "send stream capacity unexpectedly closed",
                                )));
                            }
                        }
                    }
                } else if let Poll::Ready(reason) = me
                    .body_tx
                    .poll_reset(cx)
                    .map_err(crate::Error::new_body_write)?
                {
                    debug!("stream received RST_STREAM: {:?}", reason);
                    return Poll::Ready(Err(crate::Error::new_body_write(::h2::Error::from(
                        reason,
                    ))));
                }

                match ready!(me.stream.as_mut().poll_data(cx)) {
                    Some(Ok(chunk)) => {
                        let is_eos = me.stream.is_end_stream();
                        trace!(
                            "send body chunk: {} bytes, eos={}",
                            chunk.remaining(),
                            is_eos,
                        );

                        let buf = SendBuf(Some(chunk));
                        me.body_tx
                            .send_data(buf, is_eos)
                            .map_err(crate::Error::new_body_write)?;

                        if is_eos {
                            return Poll::Ready(Ok(()));
                        }
                    }
                    Some(Err(e)) => return Poll::Ready(Err(me.body_tx.on_user_err(e))),
                    None => {
                        me.body_tx.reserve_capacity(0);
                        let is_eos = me.stream.is_end_stream();
                        if is_eos {
                            return Poll::Ready(me.body_tx.send_eos_frame());
                        } else {
                            *me.data_done = true;
                            // loop again to poll_trailers
                        }
                    }
                }
            } else {
                if let Poll::Ready(reason) = me
                    .body_tx
                    .poll_reset(cx)
                    .map_err(crate::Error::new_body_write)?
                {
                    debug!("stream received RST_STREAM: {:?}", reason);
                    return Poll::Ready(Err(crate::Error::new_body_write(::h2::Error::from(
                        reason,
                    ))));
                }

                match ready!(me.stream.poll_trailers(cx)) {
                    Ok(Some(trailers)) => {
                        me.body_tx
                            .send_trailers(trailers)
                            .map_err(crate::Error::new_body_write)?;
                        return Poll::Ready(Ok(()));
                    }
                    Ok(None) => {
                        // There were no trailers, so send an empty DATA frame...
                        return Poll::Ready(me.body_tx.send_eos_frame());
                    }
                    Err(e) => return Poll::Ready(Err(me.body_tx.on_user_err(e))),
                }
            }
        }
    }
}

trait SendStreamExt {
    fn on_user_err<E>(&mut self, err: E) -> crate::Error
    where
        E: Into<Box<dyn std::error::Error + Send + Sync>>;
    fn send_eos_frame(&mut self) -> crate::Result<()>;
}

impl<B: Buf> SendStreamExt for SendStream<SendBuf<B>> {
    fn on_user_err<E>(&mut self, err: E) -> crate::Error
    where
        E: Into<Box<dyn std::error::Error + Send + Sync>>,
    {
        let err = crate::Error::new_user_body(err);
        debug!("send body user stream error: {}", err);
        self.send_reset(err.h2_reason());
        err
    }

    fn send_eos_frame(&mut self) -> crate::Result<()> {
        trace!("send body eos");
        self.send_data(SendBuf(None), true)
            .map_err(crate::Error::new_body_write)
    }
}

struct SendBuf<B>(Option<B>);

impl<B: Buf> Buf for SendBuf<B> {
    #[inline]
    fn remaining(&self) -> usize {
        self.0.as_ref().map(|b| b.remaining()).unwrap_or(0)
    }

    #[inline]
    fn bytes(&self) -> &[u8] {
        self.0.as_ref().map(|b| b.bytes()).unwrap_or(&[])
    }

    #[inline]
    fn advance(&mut self, cnt: usize) {
        if let Some(b) = self.0.as_mut() {
            b.advance(cnt)
        }
    }

    fn bytes_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize {
        self.0.as_ref().map(|b| b.bytes_vectored(dst)).unwrap_or(0)
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! retry
//!
//! this is an abstraction over the regular http get request. it allows you to
//! have a request retry until it succeeds, with a configurable number of
//! of attempts and a backoff strategy. It also takes care of automatically
//! deserializing responses and handles headers in a sane way.

use std::borrow::Cow;
use std::io::Read;
use std::time::Duration;

use reqwest::{self, Method, Request};
use reqwest::header;

use serde;
use serde_xml_rs;
use serde_json;

use retry::Retry;
use errors::*;

use retry::raw_deserializer;

pub trait Deserializer {
    fn deserialize<T, R>(&self, R) -> Result<T>
        where T: for<'de> serde::Deserialize<'de>, R: Read;
    fn content_type(&self) -> header::HeaderValue;
}

#[derive(Debug, Clone, Copy)]
pub struct Xml;

impl Deserializer for Xml {
    fn deserialize<T, R>(&self, r: R) -> Result<T>
        where T: for<'de> serde::Deserialize<'de>, R: Read
    {
        serde_xml_rs::deserialize(r)
            .chain_err(|| "failed xml deserialization")
    }
    fn content_type(&self) -> header::HeaderValue {
        header::HeaderValue::from_static("text/xml; charset=utf-8")
    }
}

#[derive(Debug, Clone, Copy)]
pub struct Json;

impl Deserializer for Json {
    fn deserialize<T, R>(&self, r: R) -> Result<T>
        where T: serde::de::DeserializeOwned, R: Read
    {
        serde_json::from_reader(r)
            .chain_err(|| "failed json deserialization")
    }
    fn content_type(&self) -> header::HeaderValue {
        header::HeaderValue::from_static("text/json; charset=utf-8")
    }
}

#[derive(Debug, Clone, Copy)]
pub struct Raw;

impl Deserializer for Raw {
    fn deserialize<T, R>(&self, r: R) -> Result<T>
        where T: for<'de> serde::Deserialize<'de>, R: Read
    {
        raw_deserializer::from_reader(r)
            .chain_err(|| "failed raw deserialization")
    }
    fn content_type(&self) -> header::HeaderValue {
        header::HeaderValue::from_static("text/plain; charset=utf-8")
    }
}

#[derive(Debug, Clone)]
pub struct Client {
    client: reqwest::Client,
    headers: header::HeaderMap,
    retry: Retry,
    return_on_404: bool,
}

impl Client {
    pub fn try_new() -> Result<Self> {
        let client = reqwest::Client::builder()
            .build()
            .chain_err(|| "failed to initialize client")?;
        Ok(Client{
            client,
            headers: header::HeaderMap::new(),
            retry: Retry::new(),
            return_on_404: false,
        })
    }

    pub fn header(mut self, k: header::HeaderName, v: header::HeaderValue) -> Self
    {
        self.headers.append(k, v);
        self
    }

    pub fn initial_backoff(mut self, initial_backoff: Duration) -> Self {
        self.retry = self.retry.initial_backoff(initial_backoff);
        self
    }

    pub fn max_backoff(mut self, max_backoff: Duration) -> Self {
        self.retry = self.retry.max_backoff(max_backoff);
        self
    }

    /// max_attempts will panic if the argument is greater than 500
    pub fn max_attempts(mut self, max_attempts: u32) -> Self {
        self.retry = self.retry.max_attempts(max_attempts);
        self
    }

    pub fn return_on_404(mut self, return_on_404: bool) -> Self {
        self.return_on_404 = return_on_404;
        self
    }

    pub fn get<D>(&self, d: D, url: String) -> RequestBuilder<D>
        where D: Deserializer
    {
        RequestBuilder{
            url,
            body: None,
            d,
            client: self.client.clone(),
            headers: self.headers.clone(),
            retry: self.retry.clone(),
            return_on_404: self.return_on_404,
        }
    }

    pub fn post<D>(&self, d: D, url: String, body: Option<Cow<str>>) -> RequestBuilder<D>
        where D: Deserializer
    {
        RequestBuilder{
            url,
            body: body.map(|b| b.into_owned()),
            d,
            client: self.client.clone(),
            headers: self.headers.clone(),
            retry: self.retry.clone(),
            return_on_404: self.return_on_404,
        }
    }
}

pub struct RequestBuilder<D>
    where D: Deserializer
{
    url: String,
    body: Option<String>,
    d: D,
    client: reqwest::Client,
    headers: header::HeaderMap,
    retry: Retry,
    return_on_404: bool,
}

impl<D> RequestBuilder<D>
    where D: Deserializer
{

    pub fn header(mut self, k: header::HeaderName, v: header::HeaderValue) -> Self
    {
        self.headers.append(k, v);
        self
    }

    pub fn send<T>(self) -> Result<Option<T>>
        where T: for<'de> serde::Deserialize<'de>
    {
        let url = reqwest::Url::parse(self.url.as_str())
            .chain_err(|| "failed to parse uri")?;
        let mut req = Request::new(Method::GET, url);
        req.headers_mut().extend(self.headers.clone().into_iter());

        self.retry.clone().retry(|attempt| {
            info!("Fetching {}: Attempt #{}", req.url(), attempt + 1);
            self.dispatch_request(&req)
        })
    }

    pub fn dispatch_post(self) -> Result<reqwest::StatusCode>
    {
        let url = reqwest::Url::parse(self.url.as_str())
            .chain_err(|| "failed to parse uri")?;

        self.retry.clone().retry(|attempt| {
            let mut builder = reqwest::Client::new()
                .post(url.clone())
                .headers(self.headers.clone())
                .header(header::CONTENT_TYPE, self.d.content_type());
            if let Some(ref content) = self.body {
                builder = builder.body(content.clone());
            };
            let req = builder.build()
                .chain_err(|| "failed to build POST request")?;

            info!("Posting {}: Attempt #{}", req.url(), attempt + 1);
            let status = self.client.execute(req)
                .chain_err(|| "failed to POST request")?
                .status();
            if status.is_success() {
                Ok(status)
            } else {
                Err(format!("POST failed: {}", status).into())
            }
        })
    }

    fn dispatch_request<T>(&self, req: &Request) -> Result<Option<T>>
        where T: for<'de> serde::Deserialize<'de>
    {
        match self.client.execute(clone_request(req)) {
            Ok(resp) => {
                match (resp.status(), self.return_on_404) {
                    (reqwest::StatusCode::OK,_) => {
                        info!("Fetch successful");
                        self.d.deserialize(resp)
                            .map(Some)
                            .chain_err(|| "failed to deserialize data")
                    }
                    (reqwest::StatusCode::NOT_FOUND,true) => {
                        info!("Fetch failed with 404: resource not found");
                        Ok(None)
                    }
                    (s,_) => {
                        info!("Failed to fetch: {}", s);
                        Err(format!("failed to fetch: {}", s).into())
                    }
                }
            }
            Err(e) => {
                info!("Failed to fetch: {}", e);
                Err(Error::with_chain(e, "failed to fetch"))
            }
        }
    }
}

/// Reqwests Request struct doesn't implement `Clone`,
/// so we have to do it here.
fn clone_request(req: &Request) -> Request {
    let mut newreq = Request::new(req.method().clone(), req.url().clone());
    newreq.headers_mut().extend(req.headers().clone().into_iter());
    newreq
}
<commit_msg>retry/client: fix JSON MIME type<commit_after>// Copyright 2017 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! retry
//!
//! this is an abstraction over the regular http get request. it allows you to
//! have a request retry until it succeeds, with a configurable number of
//! of attempts and a backoff strategy. It also takes care of automatically
//! deserializing responses and handles headers in a sane way.

use std::borrow::Cow;
use std::io::Read;
use std::time::Duration;

use reqwest::{self, Method, Request};
use reqwest::header;

use serde;
use serde_xml_rs;
use serde_json;

use retry::Retry;
use errors::*;

use retry::raw_deserializer;

pub trait Deserializer {
    fn deserialize<T, R>(&self, R) -> Result<T>
        where T: for<'de> serde::Deserialize<'de>, R: Read;
    fn content_type(&self) -> header::HeaderValue;
}

#[derive(Debug, Clone, Copy)]
pub struct Xml;

impl Deserializer for Xml {
    fn deserialize<T, R>(&self, r: R) -> Result<T>
        where T: for<'de> serde::Deserialize<'de>, R: Read
    {
        serde_xml_rs::deserialize(r)
            .chain_err(|| "failed xml deserialization")
    }
    fn content_type(&self) -> header::HeaderValue {
        header::HeaderValue::from_static("text/xml; charset=utf-8")
    }
}

#[derive(Debug, Clone, Copy)]
pub struct Json;

impl Deserializer for Json {
    fn deserialize<T, R>(&self, r: R) -> Result<T>
        where T: serde::de::DeserializeOwned, R: Read
    {
        serde_json::from_reader(r)
            .chain_err(|| "failed json deserialization")
    }
    fn content_type(&self) -> header::HeaderValue {
        header::HeaderValue::from_static("application/json")
    }
}

#[derive(Debug, Clone, Copy)]
pub struct Raw;

impl Deserializer for Raw {
    fn deserialize<T, R>(&self, r: R) -> Result<T>
        where T: for<'de> serde::Deserialize<'de>, R: Read
    {
        raw_deserializer::from_reader(r)
            .chain_err(|| "failed raw deserialization")
    }
    fn content_type(&self) -> header::HeaderValue {
        header::HeaderValue::from_static("text/plain; charset=utf-8")
    }
}

#[derive(Debug, Clone)]
pub struct Client {
    client: reqwest::Client,
    headers: header::HeaderMap,
    retry: Retry,
    return_on_404: bool,
}

impl Client {
    pub fn try_new() -> Result<Self> {
        let client = reqwest::Client::builder()
            .build()
            .chain_err(|| "failed to initialize client")?;
        Ok(Client{
            client,
            headers: header::HeaderMap::new(),
            retry: Retry::new(),
            return_on_404: false,
        })
    }

    pub fn header(mut self, k: header::HeaderName, v: header::HeaderValue) -> Self
    {
        self.headers.append(k, v);
        self
    }

    pub fn initial_backoff(mut self, initial_backoff: Duration) -> Self {
        self.retry = self.retry.initial_backoff(initial_backoff);
        self
    }

    pub fn max_backoff(mut self, max_backoff: Duration) -> Self {
        self.retry = self.retry.max_backoff(max_backoff);
        self
    }

    /// max_attempts will panic if the argument is greater than 500
    pub fn max_attempts(mut self, max_attempts: u32) -> Self {
        self.retry = self.retry.max_attempts(max_attempts);
        self
    }

    pub fn return_on_404(mut self, return_on_404: bool) -> Self {
        self.return_on_404 = return_on_404;
        self
    }

    pub fn get<D>(&self, d: D, url: String) -> RequestBuilder<D>
        where D: Deserializer
    {
        RequestBuilder{
            url,
            body: None,
            d,
            client: self.client.clone(),
            headers: self.headers.clone(),
            retry: self.retry.clone(),
            return_on_404: self.return_on_404,
        }
    }

    pub fn post<D>(&self, d: D, url: String, body: Option<Cow<str>>) -> RequestBuilder<D>
        where D: Deserializer
    {
        RequestBuilder{
            url,
            body: body.map(|b| b.into_owned()),
            d,
            client: self.client.clone(),
            headers: self.headers.clone(),
            retry: self.retry.clone(),
            return_on_404: self.return_on_404,
        }
    }
}

pub struct RequestBuilder<D>
    where D: Deserializer
{
    url: String,
    body: Option<String>,
    d: D,
    client: reqwest::Client,
    headers: header::HeaderMap,
    retry: Retry,
    return_on_404: bool,
}

impl<D> RequestBuilder<D>
    where D: Deserializer
{

    pub fn header(mut self, k: header::HeaderName, v: header::HeaderValue) -> Self
    {
        self.headers.append(k, v);
        self
    }

    pub fn send<T>(self) -> Result<Option<T>>
        where T: for<'de> serde::Deserialize<'de>
    {
        let url = reqwest::Url::parse(self.url.as_str())
            .chain_err(|| "failed to parse uri")?;
        let mut req = Request::new(Method::GET, url);
        req.headers_mut().extend(self.headers.clone().into_iter());

        self.retry.clone().retry(|attempt| {
            info!("Fetching {}: Attempt #{}", req.url(), attempt + 1);
            self.dispatch_request(&req)
        })
    }

    pub fn dispatch_post(self) -> Result<reqwest::StatusCode>
    {
        let url = reqwest::Url::parse(self.url.as_str())
            .chain_err(|| "failed to parse uri")?;

        self.retry.clone().retry(|attempt| {
            let mut builder = reqwest::Client::new()
                .post(url.clone())
                .headers(self.headers.clone())
                .header(header::CONTENT_TYPE, self.d.content_type());
            if let Some(ref content) = self.body {
                builder = builder.body(content.clone());
            };
            let req = builder.build()
                .chain_err(|| "failed to build POST request")?;

            info!("Posting {}: Attempt #{}", req.url(), attempt + 1);
            let status = self.client.execute(req)
                .chain_err(|| "failed to POST request")?
                .status();
            if status.is_success() {
                Ok(status)
            } else {
                Err(format!("POST failed: {}", status).into())
            }
        })
    }

    fn dispatch_request<T>(&self, req: &Request) -> Result<Option<T>>
        where T: for<'de> serde::Deserialize<'de>
    {
        match self.client.execute(clone_request(req)) {
            Ok(resp) => {
                match (resp.status(), self.return_on_404) {
                    (reqwest::StatusCode::OK,_) => {
                        info!("Fetch successful");
                        self.d.deserialize(resp)
                            .map(Some)
                            .chain_err(|| "failed to deserialize data")
                    }
                    (reqwest::StatusCode::NOT_FOUND,true) => {
                        info!("Fetch failed with 404: resource not found");
                        Ok(None)
                    }
                    (s,_) => {
                        info!("Failed to fetch: {}", s);
                        Err(format!("failed to fetch: {}", s).into())
                    }
                }
            }
            Err(e) => {
                info!("Failed to fetch: {}", e);
                Err(Error::with_chain(e, "failed to fetch"))
            }
        }
    }
}

/// Reqwests Request struct doesn't implement `Clone`,
/// so we have to do it here.
fn clone_request(req: &Request) -> Request {
    let mut newreq = Request::new(req.method().clone(), req.url().clone());
    newreq.headers_mut().extend(req.headers().clone().into_iter());
    newreq
}
<|endoftext|>


<commit_before>use std::fmt::Write;
use syn;
use syn::parse::Result;
use proc_macro2::TokenStream;

use attr_hack::AttrHack;
use js_shim::js_shim_extern_code;
use js_stringify::StringifiedCode;
use utils::{Target, dummy_idents};

// TODO: Delete this once expression procedural macros are stable.
pub fn js_attr( target: Target, input: TokenStream, no_return: bool ) -> Result< TokenStream > {
    let wrapper: AttrHack< StringifiedCode > = syn::parse2( input )?;
    let wrapper_name = wrapper.fn_name;
    let snippet = wrapper.inner;
    let mut arg_count = snippet.arg_count();
    if !no_return {
        arg_count += 1;
    }

    let initial_arg_index = if no_return { 0 } else { 1 };
    let mut code = snippet.code( initial_arg_index );
    if !no_return {
        code = format!( "Module.STDWEB_PRIVATE.from_js($0, (function(){{{}}})());", code );
    }

    let mut prelude = String::new();
    for nth in initial_arg_index..arg_count {
        write!( prelude, "${} = Module.STDWEB_PRIVATE.to_js(${});", nth, nth ).unwrap();
    }

    code = format!( "{}{}", prelude, code );

    let (shim_name, shim) = js_shim_extern_code( target, &code, arg_count );

    let prototype_args = dummy_idents( arg_count ).map( |name| quote! { #name: *const u8 } );
    let call_args = dummy_idents( arg_count ).map( |name| quote! { #name } );
    let output = quote! {
        fn #wrapper_name( #(#prototype_args),* ) -> i32 {
            #shim
            unsafe {
                #shim_name( #(#call_args),* )
            }
        }
    };

    Ok( output )
}
<commit_msg>Automatically derive `@(no_return)` for `js!` snippets<commit_after>use std::fmt::Write;
use syn;
use syn::parse::Result;
use proc_macro2::TokenStream;

use attr_hack::AttrHack;
use js_shim::js_shim_extern_code;
use js_stringify::StringifiedCode;
use utils::{Target, dummy_idents};

// TODO: Delete this once expression procedural macros are stable.
pub fn js_attr( target: Target, input: TokenStream, outer_no_return: bool ) -> Result< TokenStream > {
    let wrapper: AttrHack< StringifiedCode > = syn::parse2( input )?;
    let wrapper_name = wrapper.fn_name;
    let snippet = wrapper.inner;
    let inner_no_return = outer_no_return || snippet.code( 0 ).contains( "return" ) == false;
    let inner_arg_count = snippet.arg_count() + if inner_no_return { 0 } else { 1 };
    let outer_arg_count = snippet.arg_count() + if outer_no_return { 0 } else { 1 };

    let initial_arg_index = if inner_no_return { 0 } else { 1 };
    let mut code = snippet.code( initial_arg_index );
    if !inner_no_return {
        code = format!( "Module.STDWEB_PRIVATE.from_js($0, (function(){{{}}})());", code );
    }

    let mut prelude = String::new();
    for nth in initial_arg_index..inner_arg_count {
        write!( prelude, "${} = Module.STDWEB_PRIVATE.to_js(${});", nth, nth ).unwrap();
    }

    code = format!( "{}{}", prelude, code );

    let (shim_name, shim) = js_shim_extern_code( target, &code, inner_arg_count );

    let arg_names: Vec< _ > = dummy_idents( outer_arg_count ).collect();
    let prototype_args = arg_names.clone().into_iter().map( |name| quote! { #name: *const u8 } );

    let call_args: Vec< _ >;
    if inner_no_return && !outer_no_return {
        call_args = arg_names.into_iter().skip( 1 ).collect();
    } else {
        call_args = arg_names.into_iter().collect();
    }

    let call_args = call_args.into_iter().map( |name| quote! { #name } );
    let output = quote! {
        fn #wrapper_name( #(#prototype_args),* ) -> i32 {
            #shim
            unsafe {
                #shim_name( #(#call_args),* )
            }
        }
    };

    Ok( output )
}
<|endoftext|>


<commit_before>#![allow(clippy::manual_assert)]

mod progress;

use self::progress::Progress;
use anyhow::Result;
use flate2::read::GzDecoder;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

const REVISION: &str = "ee160f2f5e73b6f5954bc33f059c316d9e8582c4";

#[rustfmt::skip]
static EXCLUDE_FILES: &[&str] = &[
    // TODO: impl ~const T {}
    // https://github.com/dtolnay/syn/issues/1051
    "src/test/ui/rfc-2632-const-trait-impl/syntax.rs",

    // Compile-fail expr parameter in const generic position: f::<1 + 2>()
    "src/test/ui/const-generics/early/closing-args-token.rs",
    "src/test/ui/const-generics/early/const-expression-parameter.rs",

    // Need at least one trait in impl Trait, no such type as impl 'static
    "src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs",

    // Deprecated anonymous parameter syntax in traits
    "src/test/ui/issues/issue-13105.rs",
    "src/test/ui/issues/issue-13775.rs",
    "src/test/ui/issues/issue-34074.rs",
    "src/test/ui/proc-macro/trait-fn-args-2015.rs",
    "src/tools/rustfmt/tests/source/trait.rs",
    "src/tools/rustfmt/tests/target/trait.rs",

    // Placeholder syntax for "throw expressions"
    "src/test/pretty/yeet-expr.rs",
    "src/test/ui/try-trait/yeet-for-option.rs",
    "src/test/ui/try-trait/yeet-for-result.rs",

    // Excessive nesting
    "src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs",

    // Testing rustfmt on invalid syntax
    "src/tools/rustfmt/tests/coverage/target/comments.rs",
    "src/tools/rustfmt/tests/parser/issue-4126/invalid.rs",
    "src/tools/rustfmt/tests/parser/issue_4418.rs",
    "src/tools/rustfmt/tests/parser/unclosed-delims/issue_4466.rs",
    "src/tools/rustfmt/tests/source/configs/disable_all_formatting/true.rs",
    "src/tools/rustfmt/tests/source/configs/spaces_around_ranges/false.rs",
    "src/tools/rustfmt/tests/source/configs/spaces_around_ranges/true.rs",
    "src/tools/rustfmt/tests/source/type.rs",
    "src/tools/rustfmt/tests/target/configs/spaces_around_ranges/false.rs",
    "src/tools/rustfmt/tests/target/configs/spaces_around_ranges/true.rs",
    "src/tools/rustfmt/tests/target/type.rs",

    // Testing compiler diagnostic localization on invalid syntax
    "src/test/run-make/translation/basic-translation.rs",

    // Clippy lint lists represented as expressions
    "src/tools/clippy/clippy_lints/src/lib.deprecated.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_all.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_cargo.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_complexity.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_correctness.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_internal.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_lints.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_nursery.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_perf.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_restriction.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_style.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs",

    // Not actually test cases
    "src/test/rustdoc-ui/test-compile-fail2.rs",
    "src/test/rustdoc-ui/test-compile-fail3.rs",
    "src/test/ui/json-bom-plus-crlf-multifile-aux.rs",
    "src/test/ui/lint/expansion-time-include.rs",
    "src/test/ui/macros/auxiliary/macro-comma-support.rs",
    "src/test/ui/macros/auxiliary/macro-include-items-expr.rs",
    "src/test/ui/macros/include-single-expr-helper.rs",
    "src/test/ui/macros/include-single-expr-helper-1.rs",
    "src/test/ui/parser/issues/auxiliary/issue-21146-inc.rs",
];

#[rustfmt::skip]
static EXCLUDE_DIRS: &[&str] = &[];

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();

    let mut path_string = path.to_string_lossy();
    if cfg!(windows) {
        path_string = path_string.replace('\\', "/").into();
    }
    let path_string = if path_string == "tests/rust" {
        return true;
    } else if let Some(path) = path_string.strip_prefix("tests/rust/") {
        path
    } else {
        panic!("unexpected path in Rust dist: {}", path_string);
    };

    if path.is_dir() {
        return !EXCLUDE_DIRS.contains(&path_string);
    }

    if path.extension().map_or(true, |e| e != "rs") {
        return false;
    }

    if path_string.starts_with("src/test/ui") {
        let stderr_path = path.with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    !EXCLUDE_FILES.contains(&path_string)
}

#[allow(dead_code)]
pub fn edition(path: &Path) -> &'static str {
    if path.ends_with("dyn-2015-no-warnings-without-lints.rs") {
        "2015"
    } else {
        "2018"
    }
}

pub fn clone_rust() {
    let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
        Err(_) => true,
        Ok(contents) => contents.trim() != REVISION,
    };
    if needs_clone {
        download_and_unpack().unwrap();
    }
    let mut missing = String::new();
    let test_src = Path::new("tests/rust");
    for exclude in EXCLUDE_FILES {
        if !test_src.join(exclude).is_file() {
            missing += "\ntests/rust/";
            missing += exclude;
        }
    }
    for exclude in EXCLUDE_DIRS {
        if !test_src.join(exclude).is_dir() {
            missing += "\ntests/rust/";
            missing += exclude;
            missing += "/";
        }
    }
    if !missing.is_empty() {
        panic!("excluded test file does not exist:{}\n", missing);
    }
}

fn download_and_unpack() -> Result<()> {
    let url = format!(
        "https://github.com/rust-lang/rust/archive/{}.tar.gz",
        REVISION
    );
    let response = reqwest::blocking::get(&url)?.error_for_status()?;
    let progress = Progress::new(response);
    let decoder = GzDecoder::new(progress);
    let mut archive = Archive::new(decoder);
    let prefix = format!("rust-{}", REVISION);

    let tests_rust = Path::new("tests/rust");
    if tests_rust.exists() {
        fs::remove_dir_all(tests_rust)?;
    }

    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?;
        if path == Path::new("pax_global_header") {
            continue;
        }
        let relative = path.strip_prefix(&prefix)?;
        let out = tests_rust.join(relative);
        entry.unpack(&out)?;
    }

    fs::write("tests/rust/COMMIT", REVISION)?;
    Ok(())
}
<commit_msg>Update test suite to nightly-2022-09-18<commit_after>#![allow(clippy::manual_assert)]

mod progress;

use self::progress::Progress;
use anyhow::Result;
use flate2::read::GzDecoder;
use std::fs;
use std::path::Path;
use tar::Archive;
use walkdir::DirEntry;

const REVISION: &str = "98ad6a5519651af36e246c0335c964dd52c554ba";

#[rustfmt::skip]
static EXCLUDE_FILES: &[&str] = &[
    // TODO: impl ~const T {}
    // https://github.com/dtolnay/syn/issues/1051
    "src/test/ui/rfc-2632-const-trait-impl/syntax.rs",

    // Compile-fail expr parameter in const generic position: f::<1 + 2>()
    "src/test/ui/const-generics/early/closing-args-token.rs",
    "src/test/ui/const-generics/early/const-expression-parameter.rs",

    // Need at least one trait in impl Trait, no such type as impl 'static
    "src/test/ui/type-alias-impl-trait/generic_type_does_not_live_long_enough.rs",

    // Deprecated anonymous parameter syntax in traits
    "src/test/ui/issues/issue-13105.rs",
    "src/test/ui/issues/issue-13775.rs",
    "src/test/ui/issues/issue-34074.rs",
    "src/test/ui/proc-macro/trait-fn-args-2015.rs",
    "src/tools/rustfmt/tests/source/trait.rs",
    "src/tools/rustfmt/tests/target/trait.rs",

    // Placeholder syntax for "throw expressions"
    "src/test/pretty/yeet-expr.rs",
    "src/test/ui/try-trait/yeet-for-option.rs",
    "src/test/ui/try-trait/yeet-for-result.rs",

    // Excessive nesting
    "src/test/ui/issues/issue-74564-if-expr-stack-overflow.rs",

    // Testing rustfmt on invalid syntax
    "src/tools/rustfmt/tests/coverage/target/comments.rs",
    "src/tools/rustfmt/tests/parser/issue-4126/invalid.rs",
    "src/tools/rustfmt/tests/parser/issue_4418.rs",
    "src/tools/rustfmt/tests/parser/unclosed-delims/issue_4466.rs",
    "src/tools/rustfmt/tests/source/configs/disable_all_formatting/true.rs",
    "src/tools/rustfmt/tests/source/configs/spaces_around_ranges/false.rs",
    "src/tools/rustfmt/tests/source/configs/spaces_around_ranges/true.rs",
    "src/tools/rustfmt/tests/source/type.rs",
    "src/tools/rustfmt/tests/target/configs/spaces_around_ranges/false.rs",
    "src/tools/rustfmt/tests/target/configs/spaces_around_ranges/true.rs",
    "src/tools/rustfmt/tests/target/type.rs",

    // Clippy lint lists represented as expressions
    "src/tools/clippy/clippy_lints/src/lib.deprecated.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_all.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_cargo.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_complexity.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_correctness.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_internal.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_lints.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_nursery.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_perf.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_restriction.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_style.rs",
    "src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs",

    // Not actually test cases
    "src/test/rustdoc-ui/test-compile-fail2.rs",
    "src/test/rustdoc-ui/test-compile-fail3.rs",
    "src/test/ui/lint/expansion-time-include.rs",
    "src/test/ui/macros/auxiliary/macro-comma-support.rs",
    "src/test/ui/macros/auxiliary/macro-include-items-expr.rs",
    "src/test/ui/macros/include-single-expr-helper.rs",
    "src/test/ui/macros/include-single-expr-helper-1.rs",
    "src/test/ui/parser/issues/auxiliary/issue-21146-inc.rs",
];

#[rustfmt::skip]
static EXCLUDE_DIRS: &[&str] = &[];

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();

    let mut path_string = path.to_string_lossy();
    if cfg!(windows) {
        path_string = path_string.replace('\\', "/").into();
    }
    let path_string = if path_string == "tests/rust" {
        return true;
    } else if let Some(path) = path_string.strip_prefix("tests/rust/") {
        path
    } else {
        panic!("unexpected path in Rust dist: {}", path_string);
    };

    if path.is_dir() {
        return !EXCLUDE_DIRS.contains(&path_string);
    }

    if path.extension().map_or(true, |e| e != "rs") {
        return false;
    }

    if path_string.starts_with("src/test/ui") {
        let stderr_path = path.with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    !EXCLUDE_FILES.contains(&path_string)
}

#[allow(dead_code)]
pub fn edition(path: &Path) -> &'static str {
    if path.ends_with("dyn-2015-no-warnings-without-lints.rs") {
        "2015"
    } else {
        "2018"
    }
}

pub fn clone_rust() {
    let needs_clone = match fs::read_to_string("tests/rust/COMMIT") {
        Err(_) => true,
        Ok(contents) => contents.trim() != REVISION,
    };
    if needs_clone {
        download_and_unpack().unwrap();
    }
    let mut missing = String::new();
    let test_src = Path::new("tests/rust");
    for exclude in EXCLUDE_FILES {
        if !test_src.join(exclude).is_file() {
            missing += "\ntests/rust/";
            missing += exclude;
        }
    }
    for exclude in EXCLUDE_DIRS {
        if !test_src.join(exclude).is_dir() {
            missing += "\ntests/rust/";
            missing += exclude;
            missing += "/";
        }
    }
    if !missing.is_empty() {
        panic!("excluded test file does not exist:{}\n", missing);
    }
}

fn download_and_unpack() -> Result<()> {
    let url = format!(
        "https://github.com/rust-lang/rust/archive/{}.tar.gz",
        REVISION
    );
    let response = reqwest::blocking::get(&url)?.error_for_status()?;
    let progress = Progress::new(response);
    let decoder = GzDecoder::new(progress);
    let mut archive = Archive::new(decoder);
    let prefix = format!("rust-{}", REVISION);

    let tests_rust = Path::new("tests/rust");
    if tests_rust.exists() {
        fs::remove_dir_all(tests_rust)?;
    }

    for entry in archive.entries()? {
        let mut entry = entry?;
        let path = entry.path()?;
        if path == Path::new("pax_global_header") {
            continue;
        }
        let relative = path.strip_prefix(&prefix)?;
        let out = tests_rust.join(relative);
        entry.unpack(&out)?;
    }

    fs::write("tests/rust/COMMIT", REVISION)?;
    Ok(())
}
<|endoftext|>


<commit_before>use std::process::Command;

use walkdir::DirEntry;

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }
    let path_string = path.to_string_lossy();
    let path_string = if cfg!(windows) {
        path_string.replace('\\', "/").into()
    } else {
        path_string
    };
    // TODO assert that parsing fails on the parse-fail cases
    if path_string.starts_with("tests/rust/src/test/parse-fail")
        || path_string.starts_with("tests/rust/src/test/compile-fail")
        || path_string.starts_with("tests/rust/src/test/rustfix")
    {
        return false;
    }

    if path_string.starts_with("tests/rust/src/test/ui") {
        let stderr_path = path.with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    match path_string.as_ref() {
        // Deprecated placement syntax
        "tests/rust/src/test/ui/obsolete-in-place/bad.rs" |
        // Deprecated anonymous parameter syntax in traits
        "tests/rust/src/test/ui/error-codes/e0119/auxiliary/issue-23563-a.rs" |
        "tests/rust/src/test/ui/issues/issue-13105.rs" |
        "tests/rust/src/test/ui/issues/issue-13775.rs" |
        "tests/rust/src/test/ui/issues/issue-34074.rs" |
        // Deprecated await macro syntax
        "tests/rust/src/test/ui/async-await/await-macro.rs" |
        // 2015-style dyn that libsyntax rejects
        "tests/rust/src/test/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs" |
        // not actually test cases
        "tests/rust/src/test/ui/macros/auxiliary/macro-comma-support.rs" |
        "tests/rust/src/test/ui/macros/auxiliary/macro-include-items-expr.rs" |
        "tests/rust/src/test/ui/issues/auxiliary/issue-21146-inc.rs" => false,
        _ => true,
    }
}

pub fn clone_rust() {
    let result = Command::new("tests/clone.sh").status().unwrap();
    assert!(result.success());
}
<commit_msg>Ignore some new test auxiliary files<commit_after>use std::process::Command;

use walkdir::DirEntry;

pub fn base_dir_filter(entry: &DirEntry) -> bool {
    let path = entry.path();
    if path.is_dir() {
        return true; // otherwise walkdir does not visit the files
    }
    if path.extension().map(|e| e != "rs").unwrap_or(true) {
        return false;
    }
    let path_string = path.to_string_lossy();
    let path_string = if cfg!(windows) {
        path_string.replace('\\', "/").into()
    } else {
        path_string
    };
    // TODO assert that parsing fails on the parse-fail cases
    if path_string.starts_with("tests/rust/src/test/parse-fail")
        || path_string.starts_with("tests/rust/src/test/compile-fail")
        || path_string.starts_with("tests/rust/src/test/rustfix")
    {
        return false;
    }

    if path_string.starts_with("tests/rust/src/test/ui") {
        let stderr_path = path.with_extension("stderr");
        if stderr_path.exists() {
            // Expected to fail in some way
            return false;
        }
    }

    match path_string.as_ref() {
        // Deprecated placement syntax
        "tests/rust/src/test/ui/obsolete-in-place/bad.rs" |
        // Deprecated anonymous parameter syntax in traits
        "tests/rust/src/test/ui/error-codes/e0119/auxiliary/issue-23563-a.rs" |
        "tests/rust/src/test/ui/issues/issue-13105.rs" |
        "tests/rust/src/test/ui/issues/issue-13775.rs" |
        "tests/rust/src/test/ui/issues/issue-34074.rs" |
        // Deprecated await macro syntax
        "tests/rust/src/test/ui/async-await/await-macro.rs" |
        // 2015-style dyn that libsyntax rejects
        "tests/rust/src/test/ui/dyn-keyword/dyn-2015-no-warnings-without-lints.rs" |
        // not actually test cases
        "tests/rust/src/test/ui/include-single-expr-helper.rs" |
        "tests/rust/src/test/ui/include-single-expr-helper-1.rs" |
        "tests/rust/src/test/ui/issues/auxiliary/issue-21146-inc.rs" |
        "tests/rust/src/test/ui/macros/auxiliary/macro-comma-support.rs" |
        "tests/rust/src/test/ui/macros/auxiliary/macro-include-items-expr.rs" => false,
        _ => true,
    }
}

pub fn clone_rust() {
    let result = Command::new("tests/clone.sh").status().unwrap();
    assert!(result.success());
}
<|endoftext|>