<commit_before>//! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s

use term::*;
use term::Term::*;

/// Set to `true` to see all the steps of β-reductions. The default is `false`.
pub const SHOW_REDUCTIONS: bool = false;

/// Applies two terms with substitution and variable update, consuming the first one in the process.
///
/// # Example
/// ```
/// use lambda_calculus::reduction::apply;
/// use lambda_calculus::parser::parse;
///
/// let lhs    = parse(&"λλ42(λ13)").unwrap();
/// let rhs    = parse(&"λ51").unwrap();
/// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
///
/// assert_eq!(apply(lhs, &rhs), Ok(result));
/// ```
pub fn apply(mut lhs: Term, rhs: &Term) -> Result<Term, Error> {
    _apply(&mut lhs, rhs, 0);

    lhs.unabs()
}

fn _apply(lhs: &mut Term, rhs: &Term, depth: usize) {
    match *lhs {
        Var(i) => if i == depth {
            *lhs = rhs.clone(); // substitute a top-level variable from lhs with rhs
            update_free_variables(lhs, depth - 1, 0); // update indices of free variables from rhs
        } else if i > depth {
            *lhs = Var(i - 1) // decrement a free variable's index
        },
        Abs(_) => {
            _apply(lhs.unabs_ref_mut().unwrap(), rhs, depth + 1)
        },
        App(_, _) => {
            _apply(lhs.lhs_ref_mut().unwrap(), rhs, depth);
            _apply(lhs.rhs_ref_mut().unwrap(), rhs, depth)
        }
    }
}

fn update_free_variables(term: &mut Term, added_depth: usize, own_depth: usize) {
    match *term {
        Var(i) => if i > own_depth {
            *term = Var(i + added_depth)
        },
        Abs(_) => {
            update_free_variables(term.unabs_ref_mut().unwrap(), added_depth, own_depth + 1)
        },
        App(_, _) => {
            update_free_variables(term.lhs_ref_mut().unwrap(), added_depth, own_depth);
            update_free_variables(term.rhs_ref_mut().unwrap(), added_depth, own_depth)
        }
    }
}

impl Term {
    /// Applies `self` to another term with substitution and variable update, consuming it
    /// in the process.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::parser::parse;
    ///
    /// let lhs    = parse(&"λλ42(λ13)").unwrap();
    /// let rhs    = parse(&"λ51").unwrap();
    /// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
    ///
    /// assert_eq!(lhs.apply(&rhs), Ok(result));
    /// ```
    pub fn apply(self, rhs: &Term) -> Result<Term, Error> {
        apply(self, rhs)
    }

    /// Reduces an `App`lication by substitution and variable update.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::{app, abs};
    /// use lambda_calculus::term::Term::Var;
    /// use lambda_calculus::arithmetic::zero;
    /// use lambda_calculus::combinators::i;
    ///
    /// assert_eq!(app(i(), zero()).eval(), Ok(zero()));
    /// ```
    pub fn eval(self) -> Result<Term, Error> {
        let (lhs, rhs) = try!(self.unapp());

        apply(lhs, &rhs)
    }

    /// Performs a single normal-order β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::succ;
    ///
    /// let mut succ_one = succ().app(1.into());
    /// succ_one.beta_once();
    ///
    /// assert_eq!(succ_one, succ().apply(&1.into()).unwrap());
    /// ```
    pub fn beta_once(&mut self) {
        let mut done = false;
        self._beta_once(&mut done, 0);
    }

    fn _beta_once(&mut self, done: &mut bool, depth: u32) {
        if *done { return }

        match *self {
            Var(_) => (),
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once(done, depth + 1),
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    let copy = self.clone();
                    if SHOW_REDUCTIONS { print!("    {} reduces to ", show_precedence(self, 0, depth)) };
                    *self = copy.eval().unwrap();
                    if SHOW_REDUCTIONS { println!("{}", show_precedence(self, 0, depth)) }
                    *done = true;
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once(done, depth);
                    self.rhs_ref_mut().unwrap()._beta_once(done, depth)
                }
            }
        }
    }

    /// Performs full normal-order β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::pred;
    ///
    /// let mut pred_one = pred().app(1.into());
    /// pred_one.beta_full();
    ///
    /// assert_eq!(pred_one, 0.into());
    /// ```
    pub fn beta_full(&mut self) {
        let mut tmp;
        loop {
            if SHOW_REDUCTIONS { println!("reducing {}", self) }
            tmp = self.clone();
            self.beta_once();
            if *self == tmp { break }
        }

        if SHOW_REDUCTIONS { println!("    doesn't reduce") }
    }
}

/// Performs full normal-order β-reduction on a `Term`, consuming it in the process.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::pred;
/// use lambda_calculus::reduction::beta_full;
///
/// let pred_one = pred().app(1.into());
///
/// assert_eq!(beta_full(pred_one), 0.into());
/// ```
pub fn beta_full(mut term: Term) -> Term {
    term.beta_full();
    term
}

/// Performs a single normal-order β-reduction on `self`.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::succ;
/// use lambda_calculus::reduction::beta_once;
///
/// let succ_one = succ().app(1.into());
///
/// assert_eq!(beta_once(succ_one), succ().apply(&1.into()).unwrap());
/// ```
pub fn beta_once(mut term: Term) -> Term {
    term.beta_once();
    term
}

#[cfg(test)]
mod test {

}
<commit_msg>test normal reduction order<commit_after>//! [β-reduction](https://en.wikipedia.org/wiki/Beta_normal_form) for lambda `Term`s

use term::*;
use term::Term::*;

/// Set to `true` to see all the steps of β-reductions. The default is `false`.
pub const SHOW_REDUCTIONS: bool = false;

/// Applies two terms with substitution and variable update, consuming the first one in the process.
///
/// # Example
/// ```
/// use lambda_calculus::reduction::apply;
/// use lambda_calculus::parser::parse;
///
/// let lhs    = parse(&"λλ42(λ13)").unwrap();
/// let rhs    = parse(&"λ51").unwrap();
/// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
///
/// assert_eq!(apply(lhs, &rhs), Ok(result));
/// ```
pub fn apply(mut lhs: Term, rhs: &Term) -> Result<Term, Error> {
    _apply(&mut lhs, rhs, 0);

    lhs.unabs()
}

fn _apply(lhs: &mut Term, rhs: &Term, depth: usize) {
    match *lhs {
        Var(i) => if i == depth {
            *lhs = rhs.clone(); // substitute a top-level variable from lhs with rhs
            update_free_variables(lhs, depth - 1, 0); // update indices of free variables from rhs
        } else if i > depth {
            *lhs = Var(i - 1) // decrement a free variable's index
        },
        Abs(_) => {
            _apply(lhs.unabs_ref_mut().unwrap(), rhs, depth + 1)
        },
        App(_, _) => {
            _apply(lhs.lhs_ref_mut().unwrap(), rhs, depth);
            _apply(lhs.rhs_ref_mut().unwrap(), rhs, depth)
        }
    }
}

fn update_free_variables(term: &mut Term, added_depth: usize, own_depth: usize) {
    match *term {
        Var(i) => if i > own_depth {
            *term = Var(i + added_depth)
        },
        Abs(_) => {
            update_free_variables(term.unabs_ref_mut().unwrap(), added_depth, own_depth + 1)
        },
        App(_, _) => {
            update_free_variables(term.lhs_ref_mut().unwrap(), added_depth, own_depth);
            update_free_variables(term.rhs_ref_mut().unwrap(), added_depth, own_depth)
        }
    }
}

impl Term {
    /// Applies `self` to another term with substitution and variable update, consuming it
    /// in the process.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::parser::parse;
    ///
    /// let lhs    = parse(&"λλ42(λ13)").unwrap();
    /// let rhs    = parse(&"λ51").unwrap();
    /// let result = parse(&"λ3(λ61)(λ1(λ71))").unwrap();
    ///
    /// assert_eq!(lhs.apply(&rhs), Ok(result));
    /// ```
    pub fn apply(self, rhs: &Term) -> Result<Term, Error> {
        apply(self, rhs)
    }

    /// Reduces an `App`lication by substitution and variable update.
    ///
    /// # Example
    /// ```
    /// use lambda_calculus::term::{app, abs};
    /// use lambda_calculus::term::Term::Var;
    /// use lambda_calculus::arithmetic::zero;
    /// use lambda_calculus::combinators::i;
    ///
    /// assert_eq!(app(i(), zero()).eval(), Ok(zero()));
    /// ```
    pub fn eval(self) -> Result<Term, Error> {
        let (lhs, rhs) = try!(self.unapp());

        apply(lhs, &rhs)
    }

    /// Performs a single normal-order β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::succ;
    ///
    /// let mut succ_one = succ().app(1.into());
    /// succ_one.beta_once();
    ///
    /// assert_eq!(succ_one, succ().apply(&1.into()).unwrap());
    /// ```
    pub fn beta_once(&mut self) {
        let mut done = false;
        self._beta_once(&mut done, 0);
    }

    fn _beta_once(&mut self, done: &mut bool, depth: u32) {
        if *done { return }

        match *self {
            Var(_) => (),
            Abs(_) => self.unabs_ref_mut().unwrap()._beta_once(done, depth + 1),
            App(_, _) => {
                if self.lhs_ref().unwrap().unabs_ref().is_ok() {
                    let copy = self.clone();
                    if SHOW_REDUCTIONS { print!("    {} reduces to ", show_precedence(self, 0, depth)) };
                    *self = copy.eval().unwrap();
                    if SHOW_REDUCTIONS { println!("{}", show_precedence(self, 0, depth)) }
                    *done = true;
                } else {
                    self.lhs_ref_mut().unwrap()._beta_once(done, depth);
                    self.rhs_ref_mut().unwrap()._beta_once(done, depth)
                }
            }
        }
    }

    /// Performs full normal-order β-reduction on `self`.
    ///
    /// # Example
    ///
    /// ```
    /// use lambda_calculus::arithmetic::pred;
    ///
    /// let mut pred_one = pred().app(1.into());
    /// pred_one.beta_full();
    ///
    /// assert_eq!(pred_one, 0.into());
    /// ```
    pub fn beta_full(&mut self) {
        let mut tmp;
        loop {
            if SHOW_REDUCTIONS { println!("reducing {}", self) }
            tmp = self.clone();
            self.beta_once();
            if *self == tmp { break }
        }

        if SHOW_REDUCTIONS { println!("    doesn't reduce") }
    }
}

/// Performs full normal-order β-reduction on a `Term`, consuming it in the process.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::pred;
/// use lambda_calculus::reduction::beta_full;
///
/// let pred_one = pred().app(1.into());
///
/// assert_eq!(beta_full(pred_one), 0.into());
/// ```
pub fn beta_full(mut term: Term) -> Term {
    term.beta_full();
    term
}

/// Performs a single normal-order β-reduction on `self`.
///
/// # Example
///
/// ```
/// use lambda_calculus::arithmetic::succ;
/// use lambda_calculus::reduction::beta_once;
///
/// let succ_one = succ().app(1.into());
///
/// assert_eq!(beta_once(succ_one), succ().apply(&1.into()).unwrap());
/// ```
pub fn beta_once(mut term: Term) -> Term {
    term.beta_once();
    term
}

#[cfg(test)]
mod test {
    use super::*;
    use parser::parse;

    #[test]
    fn normal_order() {
        let should_reduce = parse(&"(λ2)((λ111)(λ111))").unwrap();
        assert_eq!(beta_full(should_reduce), Var(1))
    }
}
<|endoftext|>


<commit_before>extern crate termion;

use termion::event::Key;
use termion::input::TermRead;
use termion::raw::IntoRawMode;
use std::io::{Write, stdout, stdin};

fn main() {
    let stdin = stdin();
    let mut stdout = stdout().into_raw_mode().unwrap();

    write!(stdout, "{}{}q to exit. Type stuff, use alt, and so on.{}",
           termion::clear::All,
           termion::cursor::Goto(1, 1),
           termion::cursor::Hide).unwrap();

    for c in stdin.keys() {
        write!(stdout, "{}{}", termion::cursor::Goto(1, 1), termion::clear::CurrentLine).unwrap();

        match c.unwrap() {
            Key::Char('q') => break,
            Key::Char(c) => println!("{}", c),
            Key::Alt(c) => println!("^{}", c),
            Key::Ctrl(c) => println!("*{}", c),
            Key::Left => println!("←"),
            Key::Right => println!("→"),
            Key::Up => println!("↑"),
            Key::Down => println!("↓"),
            Key::Backspace => println!("×"),
            _ => {},
        }
        stdout.flush().unwrap();
    }

    write!(stdout, "{}", termion::cursor::Show).unwrap();
}
<commit_msg>Update keys.rs<commit_after>extern crate termion;

use termion::event::Key;
use termion::input::TermRead;
use termion::raw::IntoRawMode;
use std::io::{Write, stdout, stdin};

fn main() {
    let stdin = stdin();
    let mut stdout = stdout().into_raw_mode().unwrap();

    write!(stdout, "{}{}q to exit. Type stuff, use alt, and so on.{}",
           termion::clear::All,
           termion::cursor::Goto(1, 1),
           termion::cursor::Hide).unwrap();
    stdout.flush().unwrap();

    for c in stdin.keys() {
        write!(stdout, "{}{}", termion::cursor::Goto(1, 1), termion::clear::CurrentLine).unwrap();

        match c.unwrap() {
            Key::Char('q') => break,
            Key::Char(c) => println!("{}", c),
            Key::Alt(c) => println!("^{}", c),
            Key::Ctrl(c) => println!("*{}", c),
            Key::Left => println!("←"),
            Key::Right => println!("→"),
            Key::Up => println!("↑"),
            Key::Down => println!("↓"),
            Key::Backspace => println!("×"),
            _ => {},
        }
        stdout.flush().unwrap();
    }

    write!(stdout, "{}", termion::cursor::Show).unwrap();
}
<|endoftext|>


<commit_before>use tokio::{time, sync::{oneshot, Mutex}};
use interpolation::lerp;

use crate::ipc_protocol::{
    ServerConnection,
    ServerResponse,
    RotationDirection,
};
use crate::renderer_client::ClientId;
use crate::radians::{self, Radians};
use crate::{Distance, Point};

use super::HandlerError;
use super::super::{
    event_loop_notifier::EventLoopNotifier,
    state::TurtleState,
    app::{TurtleId, TurtleDrawings},
    access_control::{AccessControl, RequiredData, RequiredTurtles},
    renderer::display_list::{DisplayList, PrimHandle},
};

/// Frames per second - The number of times the animation will update per second
const FPS: u64 = 60;

// 1,000,000 us in 1 s
const MICROS_PER_SEC: u64 = 1_000_000;

pub(crate) async fn move_forward(
    data_req_queued: oneshot::Sender<()>,
    conn: &ServerConnection,
    client_id: ClientId,
    app_control: &AccessControl,
    display_list: &Mutex<DisplayList>,
    event_loop: &EventLoopNotifier,
    id: TurtleId,
    distance: Distance,
) -> Result<(), HandlerError> {
    let mut data = app_control.get(RequiredData {
        drawing: false,
        turtles: Some(RequiredTurtles::One(id)),
    }, data_req_queued).await;

    // Borrow the data initially to setup the animation but then drop it so the locks on the turtle
    // and display list are released (allows for rendering to occur)
    let mut anim = {
        let mut turtles = data.turtles_mut().await;
        let turtle = turtles.one_mut();

        let TurtleState {position, heading, ..} = turtle.state;

        // The total amount we'll move in the x and y directions
        let movement = Point {
            x: distance * heading.cos(),
            y: distance * heading.sin(),
        };
        let target_pos = position + movement;

        let mut display_list = display_list.lock().await;
        MoveAnimation::new(turtle, &mut display_list, target_pos)
    };

    while anim.running {
        // Signal the main thread that the image has changed
        event_loop.request_redraw().await?;

        // Sleep until it is time to update the animation again
        anim.timer.tick().await;

        // These locks are dropped at the end of this loop iteration to allow rendering to occur
        // while we wait
        let mut turtles = data.turtles_mut().await;
        let turtle = turtles.one_mut();
        let mut display_list = display_list.lock().await;

        anim.step(turtle, &mut display_list);
    }

    // Signal the main thread one last time that the image has changed
    // This also runs if anim.running starts as false (for speed == instant)
    event_loop.request_redraw().await?;

    conn.send(client_id, ServerResponse::AnimationComplete(id)).await?;

    Ok(())
}

pub(crate) async fn move_to(
    data_req_queued: oneshot::Sender<()>,
    conn: &ServerConnection,
    client_id: ClientId,
    app_control: &AccessControl,
    display_list: &Mutex<DisplayList>,
    event_loop: &EventLoopNotifier,
    id: TurtleId,
    target_pos: Point,
) -> Result<(), HandlerError> {
    let mut data = app_control.get(RequiredData {
        drawing: false,
        turtles: Some(RequiredTurtles::One(id)),
    }, data_req_queued).await;

    // Borrow the data initially to setup the animation but then drop it so the locks on the turtle
    // and display list are released (allows for rendering to occur)
    let mut anim = {
        let mut turtles = data.turtles_mut().await;
        let turtle = turtles.one_mut();

        let mut display_list = display_list.lock().await;
        MoveAnimation::new(turtle, &mut display_list, target_pos)
    };

    while anim.running {
        // Signal the main thread that the image has changed
        event_loop.request_redraw().await?;

        // Sleep until it is time to update the animation again
        anim.timer.tick().await;

        // These locks are dropped at the end of this loop iteration to allow rendering to occur
        // while we wait
        let mut turtles = data.turtles_mut().await;
        let turtle = turtles.one_mut();
        let mut display_list = display_list.lock().await;

        anim.step(turtle, &mut display_list);
    }

    // Signal the main thread one last time that the image has changed
    // This also runs if anim.running starts as false (for speed == instant)
    event_loop.request_redraw().await?;

    conn.send(client_id, ServerResponse::AnimationComplete(id)).await?;

    Ok(())
}

struct MoveAnimation {
    /// true if the animation should continue, false if it should stop
    running: bool,
    /// A timer used to delay the execution of the animation to a reasonable FPS
    timer: time::Interval,
    /// The instant that the animation started, used to precisely determine how long the animation
    /// has been running
    start: time::Instant,
    /// The position that the turtle started at
    start_pos: Point,
    /// The target position to move to (i.e. the final value of the animation)
    target_pos: Point,
    /// The total duration of the animation in microseconds
    total_micros: f64,
    /// A handle to the line that is manipulated by this animation (if any)
    prim: Option<PrimHandle>,
    /// The index of this point in the fill polygon (if any)
    fill_poly_index: Option<usize>,
}

impl MoveAnimation {
    fn new(
        turtle: &mut TurtleDrawings,
        display_list: &mut DisplayList,
        target_pos: Point,
    ) -> Self {
        let frame_duration = time::Duration::from_micros(MICROS_PER_SEC / FPS);
        // Need to start at now() + frame_duration or else timer will initially tick for 0 seconds
        let timer = time::interval_at(time::Instant::now() + frame_duration, frame_duration);

        let TurtleState {position, speed, ref pen, ..} = turtle.state;

        if cfg!(any(feature = "test", test)) || speed.is_instant() {
            // Set to the final position and draw a line with no animation
            turtle.state.position = target_pos;
            let prim = display_list.push_line(position, target_pos, pen);
            turtle.drawings.extend(prim);

            // Append to the current fill polygon, if any
            let fill_poly_index = turtle.current_fill_polygon.map(|poly_handle| {
                display_list.polygon_push(poly_handle, position)
            });

            Self {
                // stop the animation right away since it has already completed
                running: false,
                timer,
                start: time::Instant::now(),
                start_pos: position,
                target_pos,
                total_micros: 0.0,
                prim,
                fill_poly_index,
            }

        } else {
            let px_per_sec = speed.to_px_per_sec();
            let abs_distance = (target_pos - position).len();
            // Use microseconds instead of ms for greater precision
            let total_micros = abs_distance * MICROS_PER_SEC as f64 / px_per_sec;

            // No need to update position since the turtle hasn't move anywhere yet

            // Start with a zero-length line since the animation hasn't started yet
            let prim = display_list.push_line(position, position, pen);
            turtle.drawings.extend(prim);

            // Append to the current fill polygon, if any
            let fill_poly_index = turtle.current_fill_polygon.map(|poly_handle| {
                display_list.polygon_push(poly_handle, position)
            });

            Self {
                running: true,
                timer,
                start: time::Instant::now(),
                start_pos: position,
                target_pos,
                total_micros,
                prim,
                fill_poly_index,
            }
        }

    }

    /// Advances the animation based on the amount of time that has elapsed so far
    fn step(&mut self, turtle: &mut TurtleDrawings, display_list: &mut DisplayList) {
        let &mut Self {
            ref mut running,
            timer: _,
            ref start,
            start_pos,
            target_pos,
            total_micros,
            prim,
            fill_poly_index,
        } = self;

        let elapsed = start.elapsed().as_micros() as f64;
        if elapsed >= total_micros {
            *running = false;
            turtle.state.position = target_pos;

            // Update the end of the line we have been drawing, if any
            if let Some(prim) = prim {
                display_list.line_update_end(prim, target_pos);
            }

            // Replace the point in the current fill polygon, if any
            if let Some(poly_handle) = turtle.current_fill_polygon {
                // This unwrap is safe because `current_fill_polygon` is `Some`
                display_list.polygon_update(poly_handle, fill_poly_index.unwrap(), target_pos);
            }

        } else {
            // t is the total progress made in the animation so far
            let t = elapsed / total_micros;
            let current_pos = lerp(&start_pos, &target_pos, &t);

            turtle.state.position = current_pos;

            // Update the end of the line we have been drawing, if any
            if let Some(prim) = prim {
                display_list.line_update_end(prim, current_pos);
            }

            // Replace the point in the current fill polygon, if any
            if let Some(poly_handle) = turtle.current_fill_polygon {
                // This unwrap is safe because `current_fill_polygon` is `Some`
                display_list.polygon_update(poly_handle, fill_poly_index.unwrap(), current_pos);
            }
        }
    }
}

pub(crate) async fn rotate_in_place(
    data_req_queued: oneshot::Sender<()>,
    conn: &ServerConnection,
    client_id: ClientId,
    app_control: &AccessControl,
    event_loop: &EventLoopNotifier,
    id: TurtleId,
    angle: Radians,
    direction: RotationDirection,
) -> Result<(), HandlerError> {
    let mut data = app_control.get(RequiredData {
        drawing: false,
        turtles: Some(RequiredTurtles::One(id)),
    }, data_req_queued).await;

    // Borrow the data initially to setup the animation but then drop it so the lock on the turtle
    // is released (allows for rendering to occur)
    let mut anim = {
        let mut turtles = data.turtles_mut().await;
        let turtle = turtles.one_mut();

        RotateAnimation::new(turtle, angle, direction)
    };

    while anim.running {
        // Signal the main thread that the image has changed
        event_loop.request_redraw().await?;

        // Sleep until it is time to update the animation again
        anim.timer.tick().await;

        // This lock is dropped at the end of this loop iteration to allow rendering to occur
        // while we wait
        let mut turtles = data.turtles_mut().await;
        let turtle = turtles.one_mut();

        anim.step(turtle);
    }

    // Signal the main thread one last time that the image has changed
    // This also runs if anim.running starts as false (for speed == instant)
    event_loop.request_redraw().await?;

    conn.send(client_id, ServerResponse::AnimationComplete(id)).await?;

    Ok(())
}

struct RotateAnimation {
    /// true if the animation should continue, false if it should stop
    running: bool,
    /// A timer used to delay the execution of the animation to a reasonable FPS
    timer: time::Interval,
    /// The instant that the animation started, used to precisely determine how long the animation
    /// has been running
    start: time::Instant,
    /// The start angle of the turtle
    start_heading: Radians,
    /// The angle in radians that the turtle is to have rotated by the end of the animation
    delta_angle: Radians,
    /// The direction of rotation
    direction: RotationDirection,
    /// The total duration of the animation in microseconds
    total_micros: f64,
}

impl RotateAnimation {
    fn new(
        turtle: &mut TurtleDrawings,
        delta_angle: Radians,
        direction: RotationDirection,
    ) -> Self {
        let frame_duration = time::Duration::from_micros(MICROS_PER_SEC / FPS);
        // Need to start at now() + frame_duration or else timer will initially tick for 0 seconds
        let timer = time::interval_at(time::Instant::now() + frame_duration, frame_duration);

        let TurtleState {heading, speed, ..} = turtle.state;
        if cfg!(any(feature = "test", test)) || speed.is_instant() {
            // Set to the final heading with no animation
            turtle.state.heading = rotate(heading, delta_angle, direction);

            Self {
                // stop the animation right away since it has already completed
                running: false,
                timer,
                start: time::Instant::now(),
                start_heading: heading,
                delta_angle,
                direction,
                total_micros: 0.0,
            }

        } else {
            let rad_per_sec = speed.to_rad_per_sec();
            // Use microseconds instead of ms for greater precision
            let total_micros = (delta_angle * MICROS_PER_SEC as f64 / rad_per_sec).to_radians();

            // No need to update heading since the turtle hasn't rotated yet

            Self {
                running: true,
                timer,
                start: time::Instant::now(),
                start_heading: heading,
                delta_angle,
                direction,
                total_micros,
            }
        }

    }

    /// Advances the animation based on the amount of time that has elapsed so far
    fn step(&mut self, turtle: &mut TurtleDrawings) {
        let &mut Self {
            ref mut running,
            timer: _,
            ref start,
            start_heading,
            delta_angle,
            direction,
            total_micros,
        } = self;

        let elapsed = start.elapsed().as_micros() as f64;
        if elapsed >= total_micros {
            *running = false;

            // Set to the final heading
            turtle.state.heading = rotate(start_heading, delta_angle, direction);

        } else {
            // t is the total progress made in the animation so far
            let t = elapsed / total_micros;
            let current_delta = lerp(&radians::ZERO, &delta_angle, &t);

            turtle.state.heading = rotate(start_heading, current_delta, direction);
            debug_assert!(!turtle.state.heading.is_nan(), "bug: heading became NaN");
        }
    }
}

/// Rotates the given `angle` by the given `rotation` in the given `direction`
///
/// Let's say you have a starting angle X. Standard angles go counterclockwise, so
/// if clockwise is true, we need to subtract the `rotation` from X resulting in
/// `X - rotation`. If clockwise is false, we can just add normally.
fn rotate(angle: Radians, rotation: Radians, direction: RotationDirection) -> Radians {
    use RotationDirection::*;
    let angle = match direction {
        Clockwise => angle - rotation,
        Counterclockwise => angle + rotation,
    };

    // Normalize the angle to be between 0 and 2*pi
    // Formula adapted from: https://stackoverflow.com/a/24234924/551904
    // More info: https://stackoverflow.com/a/28316446/551904
    angle - radians::TWO_PI * (angle / radians::TWO_PI).floor()
}
<commit_msg>No longer always waiting an entire frame length when the animation is actually shorter than that<commit_after>use std::cmp::min;

use tokio::{time, sync::{oneshot, Mutex}};
use interpolation::lerp;

use crate::ipc_protocol::{
    ServerConnection,
    ServerResponse,
    RotationDirection,
};
use crate::renderer_client::ClientId;
use crate::radians::{self, Radians};
use crate::{Distance, Point};

use super::HandlerError;
use super::super::{
    event_loop_notifier::EventLoopNotifier,
    state::TurtleState,
    app::{TurtleId, TurtleDrawings},
    access_control::{AccessControl, RequiredData, RequiredTurtles},
    renderer::display_list::{DisplayList, PrimHandle},
};

/// Frames per second - The number of times the animation will update per second
const FPS: u64 = 60;

/// 1,000,000 us in 1 s
const MICROS_PER_SEC: u64 = 1_000_000;

/// The maximum length of an animation frame
const FRAME_DURATION: time::Duration = time::Duration::from_micros(MICROS_PER_SEC / FPS);

pub(crate) async fn move_forward(
    data_req_queued: oneshot::Sender<()>,
    conn: &ServerConnection,
    client_id: ClientId,
    app_control: &AccessControl,
    display_list: &Mutex<DisplayList>,
    event_loop: &EventLoopNotifier,
    id: TurtleId,
    distance: Distance,
) -> Result<(), HandlerError> {
    let mut data = app_control.get(RequiredData {
        drawing: false,
        turtles: Some(RequiredTurtles::One(id)),
    }, data_req_queued).await;

    // Borrow the data initially to setup the animation but then drop it so the locks on the turtle
    // and display list are released (allows for rendering to occur)
    let mut anim = {
        let mut turtles = data.turtles_mut().await;
        let turtle = turtles.one_mut();

        let TurtleState {position, heading, ..} = turtle.state;

        // The total amount we'll move in the x and y directions
        let movement = Point {
            x: distance * heading.cos(),
            y: distance * heading.sin(),
        };
        let target_pos = position + movement;

        let mut display_list = display_list.lock().await;
        MoveAnimation::new(turtle, &mut display_list, target_pos)
    };

    while anim.running {
        // Signal the main thread that the image has changed
        event_loop.request_redraw().await?;

        // Sleep until it is time to update the animation again
        time::delay_for(anim.next_delay).await;

        // These locks are dropped at the end of this loop iteration to allow rendering to occur
        // while we wait
        let mut turtles = data.turtles_mut().await;
        let turtle = turtles.one_mut();
        let mut display_list = display_list.lock().await;

        anim.step(turtle, &mut display_list);
    }

    // Signal the main thread one last time that the image has changed
    // This also runs if anim.running starts as false (for speed == instant)
    event_loop.request_redraw().await?;

    conn.send(client_id, ServerResponse::AnimationComplete(id)).await?;

    Ok(())
}

pub(crate) async fn move_to(
    data_req_queued: oneshot::Sender<()>,
    conn: &ServerConnection,
    client_id: ClientId,
    app_control: &AccessControl,
    display_list: &Mutex<DisplayList>,
    event_loop: &EventLoopNotifier,
    id: TurtleId,
    target_pos: Point,
) -> Result<(), HandlerError> {
    let mut data = app_control.get(RequiredData {
        drawing: false,
        turtles: Some(RequiredTurtles::One(id)),
    }, data_req_queued).await;

    // Borrow the data initially to setup the animation but then drop it so the locks on the turtle
    // and display list are released (allows for rendering to occur)
    let mut anim = {
        let mut turtles = data.turtles_mut().await;
        let turtle = turtles.one_mut();

        let mut display_list = display_list.lock().await;
        MoveAnimation::new(turtle, &mut display_list, target_pos)
    };

    while anim.running {
        // Signal the main thread that the image has changed
        event_loop.request_redraw().await?;

        // Sleep until it is time to update the animation again
        time::delay_for(anim.next_delay).await;

        // These locks are dropped at the end of this loop iteration to allow rendering to occur
        // while we wait
        let mut turtles = data.turtles_mut().await;
        let turtle = turtles.one_mut();
        let mut display_list = display_list.lock().await;

        anim.step(turtle, &mut display_list);
    }

    // Signal the main thread one last time that the image has changed
    // This also runs if anim.running starts as false (for speed == instant)
    event_loop.request_redraw().await?;

    conn.send(client_id, ServerResponse::AnimationComplete(id)).await?;

    Ok(())
}

struct MoveAnimation {
    /// true if the animation should continue, false if it should stop
    running: bool,
    /// The next amount of time the animation loop should be delayed, up to `FRAME_DURATION`
    ///
    /// Updated with every call to `step`
    next_delay: time::Duration,
    /// The instant that the animation started, used to precisely determine how long the animation
    /// has been running
    start: time::Instant,
    /// The position that the turtle started at
    start_pos: Point,
    /// The target position to move to (i.e. the final value of the animation)
    target_pos: Point,
    /// The total duration of the animation
    total_duration: time::Duration,
    /// A handle to the line that is manipulated by this animation (if any)
    prim: Option<PrimHandle>,
    /// The index of this point in the fill polygon (if any)
    fill_poly_index: Option<usize>,
}

impl MoveAnimation {
    fn new(
        turtle: &mut TurtleDrawings,
        display_list: &mut DisplayList,
        target_pos: Point,
    ) -> Self {
        let TurtleState {position, speed, ref pen, ..} = turtle.state;

        if cfg!(any(feature = "test", test)) || speed.is_instant() {
            // Set to the final position and draw a line with no animation
            turtle.state.position = target_pos;
            let prim = display_list.push_line(position, target_pos, pen);
            turtle.drawings.extend(prim);

            // Append to the current fill polygon, if any
            let fill_poly_index = turtle.current_fill_polygon.map(|poly_handle| {
                display_list.polygon_push(poly_handle, position)
            });

            Self {
                // stop the animation right away since it has already completed
                running: false,
                next_delay: time::Duration::from_micros(0),
                start: time::Instant::now(),
                start_pos: position,
                target_pos,
                total_duration: time::Duration::from_micros(0),
                prim,
                fill_poly_index,
            }

        } else {
            let px_per_sec = speed.to_px_per_sec();
            let abs_distance = (target_pos - position).len();
            // Use microseconds instead of ms for greater precision
            let total_micros = abs_distance * MICROS_PER_SEC as f64 / px_per_sec;
            let total_duration = time::Duration::from_micros(total_micros as u64);

            // If the duration of the animation is less than a frame, don't wait the entire frame
            // to complete it
            let next_delay = min(total_duration, FRAME_DURATION);

            // No need to update position since the turtle hasn't move anywhere yet

            // Start with a zero-length line since the animation hasn't started yet
            let prim = display_list.push_line(position, position, pen);
            turtle.drawings.extend(prim);

            // Append to the current fill polygon, if any
            let fill_poly_index = turtle.current_fill_polygon.map(|poly_handle| {
                display_list.polygon_push(poly_handle, position)
            });

            Self {
                running: true,
                next_delay,
                start: time::Instant::now(),
                start_pos: position,
                target_pos,
                total_duration,
                prim,
                fill_poly_index,
            }
        }
    }

    /// Advances the animation based on the amount of time that has elapsed so far
    fn step(&mut self, turtle: &mut TurtleDrawings, display_list: &mut DisplayList) {
        let &mut Self {
            ref mut running,
            ref mut next_delay,
            ref start,
            start_pos,
            target_pos,
            total_duration,
            prim,
            fill_poly_index,
        } = self;

        let elapsed = start.elapsed();
        let pos = if elapsed >= total_duration {
            *running = false;
            *next_delay = time::Duration::from_micros(0);

            target_pos

        } else {
            // t is the total progress made in the animation so far
            let t = elapsed.as_micros() as f64 / total_duration.as_micros() as f64;
            let current_pos = lerp(&start_pos, &target_pos, &t);

            // If the time remaining is less than a frame, don't wait the entire frame
            let remaining = total_duration - elapsed;
            *next_delay = min(remaining, FRAME_DURATION);

            current_pos
        };

        // Update state with the current position
        turtle.state.position = pos;

        // Update the end of the line we have been drawing, if any
        if let Some(prim) = prim {
            display_list.line_update_end(prim, pos);
        }

        // Replace the point in the current fill polygon, if any
        if let Some(poly_handle) = turtle.current_fill_polygon {
            // This unwrap is safe because `current_fill_polygon` is `Some`
            display_list.polygon_update(poly_handle, fill_poly_index.unwrap(), pos);
        }
    }
}

pub(crate) async fn rotate_in_place(
    data_req_queued: oneshot::Sender<()>,
    conn: &ServerConnection,
    client_id: ClientId,
    app_control: &AccessControl,
    event_loop: &EventLoopNotifier,
    id: TurtleId,
    angle: Radians,
    direction: RotationDirection,
) -> Result<(), HandlerError> {
    let mut data = app_control.get(RequiredData {
        drawing: false,
        turtles: Some(RequiredTurtles::One(id)),
    }, data_req_queued).await;

    // Borrow the data initially to setup the animation but then drop it so the lock on the turtle
    // is released (allows for rendering to occur)
    let mut anim = {
        let mut turtles = data.turtles_mut().await;
        let turtle = turtles.one_mut();

        RotateAnimation::new(turtle, angle, direction)
    };

    while anim.running {
        // Signal the main thread that the image has changed
        event_loop.request_redraw().await?;

        // Sleep until it is time to update the animation again
        time::delay_for(anim.next_delay).await;

        // This lock is dropped at the end of this loop iteration to allow rendering to occur
        // while we wait
        let mut turtles = data.turtles_mut().await;
        let turtle = turtles.one_mut();

        anim.step(turtle);
    }

    // Signal the main thread one last time that the image has changed
    // This also runs if anim.running starts as false (for speed == instant)
    event_loop.request_redraw().await?;

    conn.send(client_id, ServerResponse::AnimationComplete(id)).await?;

    Ok(())
}

struct RotateAnimation {
    /// true if the animation should continue, false if it should stop
    running: bool,
    /// The next amount of time the animation loop should be delayed, up to `FRAME_DURATION`
    ///
    /// Updated with every call to `step`
    next_delay: time::Duration,
    /// The instant that the animation started, used to precisely determine how long the animation
    /// has been running
    start: time::Instant,
    /// The start angle of the turtle
    start_heading: Radians,
    /// The angle in radians that the turtle is to have rotated by the end of the animation
    delta_angle: Radians,
    /// The direction of rotation
    direction: RotationDirection,
    /// The total duration of the animation
    total_duration: time::Duration,
}

impl RotateAnimation {
    fn new(
        turtle: &mut TurtleDrawings,
        delta_angle: Radians,
        direction: RotationDirection,
    ) -> Self {
        let TurtleState {heading, speed, ..} = turtle.state;
        if cfg!(any(feature = "test", test)) || speed.is_instant() {
            // Set to the final heading with no animation
            turtle.state.heading = rotate(heading, delta_angle, direction);

            Self {
                // stop the animation right away since it has already completed
                running: false,
                next_delay: time::Duration::from_micros(0),
                start: time::Instant::now(),
                start_heading: heading,
                delta_angle,
                direction,
                total_duration: time::Duration::from_micros(0),
            }

        } else {
            let rad_per_sec = speed.to_rad_per_sec();
            // Use microseconds instead of ms for greater precision
            let total_micros = (delta_angle * MICROS_PER_SEC as f64 / rad_per_sec).to_radians();
            let total_duration = time::Duration::from_micros(total_micros as u64);

            // If the duration of the animation is less than a frame, don't wait the entire frame
            // to complete it
            let next_delay = min(total_duration, FRAME_DURATION);

            // No need to update heading since the turtle hasn't rotated yet

            Self {
                running: true,
                next_delay,
                start: time::Instant::now(),
                start_heading: heading,
                delta_angle,
                direction,
                total_duration,
            }
        }
    }

    /// Advances the animation based on the amount of time that has elapsed so far
    fn step(&mut self, turtle: &mut TurtleDrawings) {
        let &mut Self {
            ref mut running,
            ref mut next_delay,
            ref start,
            start_heading,
            delta_angle,
            direction,
            total_duration,
        } = self;

        let elapsed = start.elapsed();
        let heading = if elapsed >= total_duration {
            *running = false;
            *next_delay = time::Duration::from_micros(0);

            // Set to the final heading
            rotate(start_heading, delta_angle, direction)

        } else {
            // t is the total progress made in the animation so far
            let t = elapsed.as_micros() as f64 / total_duration.as_micros() as f64;
            let current_delta = lerp(&radians::ZERO, &delta_angle, &t);

            // If the time remaining is less than a frame, don't wait the entire frame
            let remaining = total_duration - elapsed;
            *next_delay = min(remaining, FRAME_DURATION);

            rotate(start_heading, current_delta, direction)
        };

        turtle.state.heading = heading;
        debug_assert!(!heading.is_nan(), "bug: heading became NaN");
    }
}

/// Rotates the given `angle` by the given `rotation` in the given `direction`
///
/// Let's say you have a starting angle X. Standard angles go counterclockwise, so
/// if clockwise is true, we need to subtract the `rotation` from X resulting in
/// `X - rotation`. If clockwise is false, we can just add normally.
fn rotate(angle: Radians, rotation: Radians, direction: RotationDirection) -> Radians {
    use RotationDirection::*;
    let angle = match direction {
        Clockwise => angle - rotation,
        Counterclockwise => angle + rotation,
    };

    // Normalize the angle to be between 0 and 2*pi
    // Formula adapted from: https://stackoverflow.com/a/24234924/551904
    // More info: https://stackoverflow.com/a/28316446/551904
    angle - radians::TWO_PI * (angle / radians::TWO_PI).floor()
}
<|endoftext|>


<commit_before>//! Due to netlink's loose treatment of types, parsing attributes can be hard to model in
//! Rust. `neli`'s current solution is the following:
//!
//! ```no_run
//! // This was received from the socket
//! let nlmsg = neli::nl::Nlmsghdr::new(None, neli::consts::GenlId::Ctrl, Vec::new(), None, None,
//!         neli::genl::Genlmsghdr::new::<u16>(neli::consts::CtrlCmd::Unspec, 2, Vec::new()).unwrap());
//!
//! // Get parsing handler for the attributes in this message where the next call
//! // to either get_nested_attributes() or get_payload_with() will expect a u16 type
//! // to be provided
//! let mut handle = nlmsg.nl_payload.get_attr_handle::<u16>();
//!
//! // Get the nested attribute where the Nlattr field of nla_type is equal to 1 and return
//! // a handler containing only this nested attribute internally
//! let mut next = handle.get_nested_attributes::<u16>(1).unwrap();
//!
//! // Get the nested attribute where the Nlattr field of nla_type is equal to 1 and return
//! // the payload of this attribute as a u32
//! let thirty_two_bit_integer = next.get_payload::<u32>(1, None).unwrap();
//! ```

use std::io::{Read,Write};
use std::slice;

use buffering::copy::{StreamReadBuffer,StreamWriteBuffer};
use libc;

use Nl;
use err::{SerError,DeError};
use consts::{alignto,NlAttrType};

impl<T> Nl for Vec<Nlattr<T>> where T: NlAttrType {
    fn serialize(&self, mem: &mut StreamWriteBuffer) -> Result<(), SerError> {
        for item in self.iter() {
            item.serialize(mem)?;
        }
        Ok(())
    }

    fn deserialize<B>(mem: &mut StreamReadBuffer<B>) -> Result<Self, DeError>
            where B: AsRef<[u8]> {
        let mut vec = Vec::new();
        let mut size_hint = mem.take_size_hint().unwrap_or(0);
        while size_hint > 0 || !mem.at_end() {
            let next = Nlattr::<T>::deserialize(mem)?;
            if size_hint > 0 {
                size_hint -= next.asize();
            }
            vec.push(next);
        }
        Ok(vec)
    }

    fn size(&self) -> usize {
        self.iter().fold(0, |acc, next| {
            acc + alignto(next.size())
        })
    }
}

/// Struct representing netlink attributes and payloads
#[derive(Debug,PartialEq)]
pub struct Nlattr<T> {
    /// Length of the attribute header and payload together
    pub nla_len: u16,
    /// Enum representing the type of the attribute payload
    pub nla_type: T,
    /// Payload of the attribute - either parsed or a binary buffer
    pub payload: Vec<u8>,
}

impl<T> Nlattr<T> where T: NlAttrType {
    /// Create new netlink attribute with a payload
    pub fn new_binary_payload(nla_len: Option<u16>, nla_type: T, payload: Vec<u8>)
            -> Self {
        let mut nla = Nlattr {
            nla_type,
            payload,
            nla_len: 0,
        };
        nla.nla_len = nla_len.unwrap_or(nla.size() as u16);
        nla
    }

    /// Create new netlink attribute with a payload from an object implementing `Nl`
    pub fn new_nl_payload<P>(nla_len: Option<u16>, nla_type: T, payload: P)
            -> Result<Self, SerError> where P: Nl {
        let mut mem = StreamWriteBuffer::new_growable(Some(payload.asize()));
        mem.set_size_hint(payload.size());
        payload.serialize(&mut mem)?;
        let align_diff = payload.asize() - payload.size();
        if align_diff != 0 {
            mem.write(&[0u8; libc::NLA_ALIGNTO as usize][0..align_diff])?;
        }
        let mut nla = Nlattr {
            nla_type,
            payload: mem.as_ref().to_vec(),
            nla_len: 0,
        };
        nla.nla_len = nla_len.unwrap_or(nla.size() as u16);
        Ok(nla)
    }

    /// Get handle for attribute parsing and traversal
    pub fn get_attr_handle<'a, P>(&'a self) -> AttrHandle<'a, P> where P: NlAttrType {
        AttrHandle::Bin(self.payload.as_slice())
    }
}

impl<T> Nl for Nlattr<T> where T: NlAttrType {
    fn serialize(&self, mem: &mut StreamWriteBuffer) -> Result<(), SerError> {
        self.nla_len.serialize(mem)?;
        self.nla_type.serialize(mem)?;
        self.payload.serialize(mem)?;
        let padding_len = alignto(self.nla_len as usize) - self.nla_len as usize;
        if padding_len > 0 {
            mem.write(&mut [0u8; 4][0..padding_len])?;
        }
        Ok(())
    }

    fn deserialize<B>(mem: &mut StreamReadBuffer<B>) -> Result<Self, DeError> where B: AsRef<[u8]> {
        let nla_len = u16::deserialize(mem)?;
        let nla_type = T::deserialize(mem)?;
        mem.set_size_hint(nla_len as usize - (nla_len.size() + nla_type.size()));
        let payload = Vec::<u8>::deserialize(mem)?;
        let padding_len = alignto(nla_len as usize) - nla_len as usize;
        if padding_len > 0 {
            let padding = &mut [0u8; libc::NLA_ALIGNTO as usize][0..padding_len];
            let _ = mem.read_exact(padding)?;
        }
        let nla = Nlattr {
            nla_len,
            nla_type,
            payload,
        };
        Ok(nla)
    }

    fn size(&self) -> usize {
        self.nla_len.size() + self.nla_type.size() + self.payload.size()
    }
}

/// Handle returned by `Genlmsghdr` for traversing nested attribute structures
pub enum AttrHandle<'a, P> where P: NlAttrType {
    /// Binary internal representation of attributes
    Bin(&'a [u8]),
    /// Rust representation of attributes
    Parsed(Vec<Nlattr<P>>),
}

impl<'a, P> AttrHandle<'a, P> where P: NlAttrType {
    /// Get length if attribute handle has been parsed
    pub fn len(&self) -> Option<usize> {
        match *self {
            AttrHandle::Parsed(ref v) => Some(v.len()),
            _ => None,
        }
    }

    /// If attributes are parsed, pass back iterator over attributes
    pub fn iter(&self) -> Option<slice::Iter<Nlattr<P>>> {
        match *self {
            AttrHandle::Parsed(ref v) => Some(v.iter()),
            _ => None,
        }
    }

    /// Parse a binary payload into nested attributes
    pub fn parse_nested_attributes(&mut self) -> Result<&mut AttrHandle<'a, P>, DeError> {
        let opt_v = match *self {
            AttrHandle::Bin(v) => {
                let mut len = v.asize();
                let mut attrs = Vec::new();
                let mut mem = StreamReadBuffer::new(v);
                while len > 0 {
                    let hdr = Nlattr::deserialize(&mut mem)?;
                    len -= hdr.asize();
                    attrs.push(hdr);
                }
                Some(attrs)
            },
            _ => None,
        };
        match opt_v {
            Some(v) => { *self = AttrHandle::Parsed(v); },
            None => (),
        };
        Ok(self)
    }

    /// Get the payload of an attribute as a handle for parsing nested attributes
    pub fn get_nested_attributes<S>(&mut self, payload: P) -> Result<AttrHandle<S>, DeError>
            where S: NlAttrType {
        let nested = self.parse_nested_attributes()?.get_attribute(payload);
        match nested {
            Some(a) => Ok(AttrHandle::Bin(a.payload.as_slice())),
            None => Err(DeError::new("Failed to find requested attribute")),
        }
    }

    /// Get nested attributes from a parsed handle
    pub fn get_attribute(&'a self, p: P) -> Option<&'a Nlattr<P>> {
        match *self {
            AttrHandle::Parsed(ref parsed) => {
                for item in parsed {
                    if item.nla_type == p {
                        return Some(&item);
                    }
                }
                None
            },
            _ => None,
        }
    }

    /// Mutably get nested attributes from a parsed handle
    pub fn get_attribute_mut(&'a mut self, p: P) -> Option<&'a mut Nlattr<P>> {
        match *self {
            AttrHandle::Parsed(ref mut parsed) => {
                for item in parsed {
                    if item.nla_type == p {
                        return Some(item);
                    }
                }
                None
            },
            _ => None,
        }
    }

    /// Parse binary payload as a type that implements `Nl` using `deserialize` with an option size
    /// hint
    pub fn get_payload<R>(&mut self, attr: P, size_hint: Option<usize>) -> Result<R, DeError>
            where R: Nl {
        match self.parse_nested_attributes()?.get_attribute(attr) {
            Some(ref a) => {
                let mut mem = StreamReadBuffer::new(&a.payload);
                if let Some(w) = size_hint {
                    mem.set_size_hint(w);
                }
                R::deserialize(&mut mem)
            },
            _ => Err(DeError::new("Failed to find specified attribute")),
        }
    }
}
<commit_msg>Fix padding bug with ::new_nl_payload()<commit_after>//! Due to netlink's loose treatment of types, parsing attributes can be hard to model in
//! Rust. `neli`'s current solution is the following:
//!
//! ```no_run
//! // This was received from the socket
//! let nlmsg = neli::nl::Nlmsghdr::new(None, neli::consts::GenlId::Ctrl, Vec::new(), None, None,
//!         neli::genl::Genlmsghdr::new::<u16>(neli::consts::CtrlCmd::Unspec, 2, Vec::new()).unwrap());
//!
//! // Get parsing handler for the attributes in this message where the next call
//! // to either get_nested_attributes() or get_payload_with() will expect a u16 type
//! // to be provided
//! let mut handle = nlmsg.nl_payload.get_attr_handle::<u16>();
//!
//! // Get the nested attribute where the Nlattr field of nla_type is equal to 1 and return
//! // a handler containing only this nested attribute internally
//! let mut next = handle.get_nested_attributes::<u16>(1).unwrap();
//!
//! // Get the nested attribute where the Nlattr field of nla_type is equal to 1 and return
//! // the payload of this attribute as a u32
//! let thirty_two_bit_integer = next.get_payload::<u32>(1, None).unwrap();
//! ```

use std::io::{Read,Write};
use std::slice;

use buffering::copy::{StreamReadBuffer,StreamWriteBuffer};
use libc;

use Nl;
use err::{SerError,DeError};
use consts::{alignto,NlAttrType};

impl<T> Nl for Vec<Nlattr<T>> where T: NlAttrType {
    fn serialize(&self, mem: &mut StreamWriteBuffer) -> Result<(), SerError> {
        for item in self.iter() {
            item.serialize(mem)?;
        }
        Ok(())
    }

    fn deserialize<B>(mem: &mut StreamReadBuffer<B>) -> Result<Self, DeError>
            where B: AsRef<[u8]> {
        let mut vec = Vec::new();
        let mut size_hint = mem.take_size_hint().unwrap_or(0);
        while size_hint > 0 || !mem.at_end() {
            let next = Nlattr::<T>::deserialize(mem)?;
            if size_hint > 0 {
                size_hint -= next.asize();
            }
            vec.push(next);
        }
        Ok(vec)
    }

    fn size(&self) -> usize {
        self.iter().fold(0, |acc, next| {
            acc + alignto(next.size())
        })
    }
}

/// Struct representing netlink attributes and payloads
#[derive(Debug,PartialEq)]
pub struct Nlattr<T> {
    /// Length of the attribute header and payload together
    pub nla_len: u16,
    /// Enum representing the type of the attribute payload
    pub nla_type: T,
    /// Payload of the attribute - either parsed or a binary buffer
    pub payload: Vec<u8>,
}

impl<T> Nlattr<T> where T: NlAttrType {
    /// Create new netlink attribute with a payload
    pub fn new_binary_payload(nla_len: Option<u16>, nla_type: T, payload: Vec<u8>)
            -> Self {
        let mut nla = Nlattr {
            nla_type,
            payload,
            nla_len: 0,
        };
        nla.nla_len = nla_len.unwrap_or(nla.size() as u16);
        nla
    }

    /// Create new netlink attribute with a payload from an object implementing `Nl`
    pub fn new_nl_payload<P>(nla_len: Option<u16>, nla_type: T, payload: P)
            -> Result<Self, SerError> where P: Nl {
        let mut mem = StreamWriteBuffer::new_growable(Some(payload.asize()));
        mem.set_size_hint(payload.size());
        payload.serialize(&mut mem)?;
        let mut nla = Nlattr {
            nla_type,
            payload: mem.as_ref().to_vec(),
            nla_len: 0,
        };
        nla.nla_len = nla_len.unwrap_or(nla.size() as u16);
        Ok(nla)
    }

    /// Get handle for attribute parsing and traversal
    pub fn get_attr_handle<'a, P>(&'a self) -> AttrHandle<'a, P> where P: NlAttrType {
        AttrHandle::Bin(self.payload.as_slice())
    }
}

impl<T> Nl for Nlattr<T> where T: NlAttrType {
    fn serialize(&self, mem: &mut StreamWriteBuffer) -> Result<(), SerError> {
        self.nla_len.serialize(mem)?;
        self.nla_type.serialize(mem)?;
        self.payload.serialize(mem)?;
        let padding_len = alignto(self.nla_len as usize) - self.nla_len as usize;
        if padding_len > 0 {
            mem.write(&mut [0u8; 4][0..padding_len])?;
        }
        Ok(())
    }

    fn deserialize<B>(mem: &mut StreamReadBuffer<B>) -> Result<Self, DeError> where B: AsRef<[u8]> {
        let nla_len = u16::deserialize(mem)?;
        let nla_type = T::deserialize(mem)?;
        mem.set_size_hint(nla_len as usize - (nla_len.size() + nla_type.size()));
        let payload = Vec::<u8>::deserialize(mem)?;
        let padding_len = alignto(nla_len as usize) - nla_len as usize;
        if padding_len > 0 {
            let padding = &mut [0u8; libc::NLA_ALIGNTO as usize][0..padding_len];
            let _ = mem.read_exact(padding)?;
        }
        let nla = Nlattr {
            nla_len,
            nla_type,
            payload,
        };
        Ok(nla)
    }

    fn size(&self) -> usize {
        self.nla_len.size() + self.nla_type.size() + self.payload.size()
    }
}

/// Handle returned by `Genlmsghdr` for traversing nested attribute structures
pub enum AttrHandle<'a, P> where P: NlAttrType {
    /// Binary internal representation of attributes
    Bin(&'a [u8]),
    /// Rust representation of attributes
    Parsed(Vec<Nlattr<P>>),
}

impl<'a, P> AttrHandle<'a, P> where P: NlAttrType {
    /// Get length if attribute handle has been parsed
    pub fn len(&self) -> Option<usize> {
        match *self {
            AttrHandle::Parsed(ref v) => Some(v.len()),
            _ => None,
        }
    }

    /// If attributes are parsed, pass back iterator over attributes
    pub fn iter(&self) -> Option<slice::Iter<Nlattr<P>>> {
        match *self {
            AttrHandle::Parsed(ref v) => Some(v.iter()),
            _ => None,
        }
    }

    /// Parse a binary payload into nested attributes
    pub fn parse_nested_attributes(&mut self) -> Result<&mut AttrHandle<'a, P>, DeError> {
        let opt_v = match *self {
            AttrHandle::Bin(v) => {
                let mut len = v.asize();
                let mut attrs = Vec::new();
                let mut mem = StreamReadBuffer::new(v);
                while len > 0 {
                    let hdr = Nlattr::deserialize(&mut mem)?;
                    len -= hdr.asize();
                    attrs.push(hdr);
                }
                Some(attrs)
            },
            _ => None,
        };
        match opt_v {
            Some(v) => { *self = AttrHandle::Parsed(v); },
            None => (),
        };
        Ok(self)
    }

    /// Get the payload of an attribute as a handle for parsing nested attributes
    pub fn get_nested_attributes<S>(&mut self, payload: P) -> Result<AttrHandle<S>, DeError>
            where S: NlAttrType {
        let nested = self.parse_nested_attributes()?.get_attribute(payload);
        match nested {
            Some(a) => Ok(AttrHandle::Bin(a.payload.as_slice())),
            None => Err(DeError::new("Failed to find requested attribute")),
        }
    }

    /// Get nested attributes from a parsed handle
    pub fn get_attribute(&'a self, p: P) -> Option<&'a Nlattr<P>> {
        match *self {
            AttrHandle::Parsed(ref parsed) => {
                for item in parsed {
                    if item.nla_type == p {
                        return Some(&item);
                    }
                }
                None
            },
            _ => None,
        }
    }

    /// Mutably get nested attributes from a parsed handle
    pub fn get_attribute_mut(&'a mut self, p: P) -> Option<&'a mut Nlattr<P>> {
        match *self {
            AttrHandle::Parsed(ref mut parsed) => {
                for item in parsed {
                    if item.nla_type == p {
                        return Some(item);
                    }
                }
                None
            },
            _ => None,
        }
    }

    /// Parse binary payload as a type that implements `Nl` using `deserialize` with an option size
    /// hint
    pub fn get_payload<R>(&mut self, attr: P, size_hint: Option<usize>) -> Result<R, DeError>
            where R: Nl {
        match self.parse_nested_attributes()?.get_attribute(attr) {
            Some(ref a) => {
                let mut mem = StreamReadBuffer::new(&a.payload);
                if let Some(w) = size_hint {
                    mem.set_size_hint(w);
                }
                R::deserialize(&mut mem)
            },
            _ => Err(DeError::new("Failed to find specified attribute")),
        }
    }
}
<|endoftext|>


<commit_before>//#![allow(unused)]

use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Condvar, Mutex, Arc};
use std::vec::Vec;
use std::collections::HashMap;
use std::cell::UnsafeCell;
use std::hash::{Hash, Hasher};
use std::mem::{align_of, size_of_val, transmute};
use std::slice::bytes::copy_memory;

use ::Result;

pub struct GlobalState { version : AtomicUsize }

/// Baseline implementation of GlobalState, currently do not hqve the aid of the compiler, so this
/// may have major issues.
/// TODO: make a proper implementation of the GlobalState trait
impl GlobalState {
    fn newLocal<'l, 'g>(&'g self) -> LocalState<'l, 'g> {
        LocalState {
            reads: Vec::new(),
            writes: HashMap::new(),
            global: self,
            snapshot: self.version.load(Ordering::SeqCst),
        }
    }

    pub fn retry(&self, l: &mut LocalState, mut func: F) -> A
    where F: FnMut(&mut LocalState) -> Result {
        let bx = Arc::new((Mutex::new(false), Condvar::new()));
        for &(addr, size) in &l.reads {
            let mut waiters = addr.addr.waiters.lock().unwrap();
            // this is actually unsafe...
            // maybe protect waiters with a lock
            waiters.push(bx.clone());
            //addr.waiters().push((&mtx, &cv));
        }
        let (ref mtx, ref cv) = *bx;
        let mut done = mtx.lock().unwrap();
        while !*done {
            done = cv.wait(done).unwrap();
        }
        self.run(func)
    }

    pub fn run(&self, mut func : F) -> A
        where F: FnMut(&mut LocalState) -> Result {
            let mut local = self.newLocal();
            match func(&mut local).spec_move() {
                Ok(r) => r,
                _ => self.run(func)
            }
    }

    pub fn or_else(&self, mut func1 : F, func2 : G) -> A
        where F: FnMut(&mut LocalState) -> Result,
              G: FnMut(&mut LocalState) -> Result {
            let mut local1 = self.newLocal();
            match func1(&mut local1).spec_move() {
                Ok(r) => r,
                //TODO: this may not work, compiler may not know that
                //local1, which borrows self, has relinquised ownership
                _ => self.run(func2)
            }
    }
}

pub struct LocalState<'v, 'g : 'v> {
    /// the norec paper has the reads stored as a list of <address, value> pairs. For us it
    /// would probably be better to have versioned TVars. That way we always have a fast
    /// comparison operation and avoid doing extra dynamic dispatch when validating reads.
    reads : Vec<(TVarAddr<'v, 'g>, usize)>,

    /// for writes we will probably have to cast unsafely to get this to work. TVars just hold
    /// arbitrary types and we only have one table.  XXX: gross
    writes : HashMap<TVarAddr<'v, 'g>, Box<[u8]>>,

    /// STM environment we are using
    /// TODO: how are we getting away with this not being a mutable reference?
    global : &'g GlobalState,

    /// last version at which our view of the global state was valid
    snapshot : usize
}

impl<'v, 'g : 'v> LocalState<'v, 'g> {

    /// Validate the current local state against the state of the world,
    /// Aborts if a TVar in our readset has been written, otherwise
    /// returns the version number to with we are consistent
    pub fn validate(&self) -> Result<usize> {
        loop {
            let time = self.global.version.load(Ordering::SeqCst);
            if (time & 1) == 0 {
                continue;
            }
            for &(addr, version) in &self.reads {
                if addr.version().load(Ordering::SeqCst) != version {
                    return Result::abort();
                }
            }
            return Result::ret(time);
        }
    }

    /// Acquire reference to value in TVar within the transaction
    pub fn read<'l, A>(&'l mut self, tvar : &'v TVar<'g, A>) -> Result<&'l A>
        where 'v : 'l
    {
        let addr: TVarAddr<'v, 'g> = unsafe { tvar.to_addr() } ;

        // Should be &&'l ?
        if let Some(v) = self.writes.get(&addr) {
            let r : && [u8] = &&**v;
            assert_eq!(r.len(), ::std::mem::size_of::());
            let r2 : && A = unsafe { transmute(r) };
            return Result::ret(r2)
        }

        if self.snapshot == self.global.version.load(Ordering::SeqCst) {
            self.reads.push((addr, tvar.version.load(Ordering::SeqCst)));
            Result::ret(unsafe {tvar.get_val()})
        } else {
            self.validate().bind( | v | {
                assert!(self.snapshot <= v);
                self.snapshot = v;
                self.reads.push((addr, tvar.version.load(Ordering::SeqCst)));
                Result::ret(unsafe {tvar.get_val()})
            })
        }
    }

    /// Add the TVar and value to our writeset, these are thread-local until the
    /// transaction commits
    pub fn write(&mut self, tvar : &'v mut TVar<'g, A>, val : A) -> Result<()> {
        let b : Box<[A]> = Box::new([val]);
        unsafe {
            self.writes.insert(tvar.to_addr(), transmute(b));
        }
        Result::ret(())
    }

    /// if (read−only transaction)
    ///     return
    /// while (!CAS(&global lock, snapshot, snapshot + 1))
    ///     snapshot = Validate()
    /// for each (addr, val) in writes
    ///     ∗addr = val
    /// global lock = snapshot + 2 // one more than CAS above
    pub fn commit(&mut self) -> Result<()> {
        fn commit_loop(l : &mut LocalState) -> Result<()> {
            if l.global
                .version
                .compare_and_swap(l.snapshot, l.snapshot + 1, Ordering::SeqCst) == l.snapshot {
                Result::ret(())
            } else {
                l.validate().bind(|v| {
                    l.snapshot = v;
                    commit_loop(l)
                })
            }
        }
        if self.writes.is_empty() {
            Result::ret(())
        } else {
            commit_loop(self).bind(| _ | {
                for (mut addr, value) in &self.writes {
                    let dst = unsafe { addr.aligned_mem() };
                    debug_assert_eq!(value.len(), dst.len());
                    copy_memory(value, dst);
                    addr.addr.version.fetch_add(1, Ordering::SeqCst);
                    //TODO: DCLP if this is too slow in the common case that waiters is empty
                    let mut waiters = addr.addr.waiters.lock().unwrap();
                    for bx in &*waiters {
                        let (ref mtx, ref cv) = **bx;
                        let mut done = mtx.lock().unwrap();
                        *done = true;
                        cv.notify_all();
                    }
                    waiters.clear();
                }
                self.global
                    .version
                    .compare_and_swap(self.snapshot + 1, self.snapshot + 2, Ordering::SeqCst);
                Result::ret(())
            })
        }
    }
}

/// Haskell-style container of mutable state within a transaction
/// TODO: impl TVar trait
pub struct TVar<'a, A: ?Sized> {
    version : AtomicUsize,
    waiters : Mutex<Vec<Arc<(Mutex<bool>, Condvar)>>>,
    global : &'a GlobalState,
    val : UnsafeCell,
}

impl<'a, A: ?Sized> TVar<'a, A> {
    unsafe fn get_val(&self) -> &A {
        &*self.val.get()
    }

    unsafe fn get_val_mut(&self) -> &mut A {
        &mut *self.val.get()
    }
}

impl<'a, A> TVar<'a, A> {
    unsafe fn to_addr<'b>(&'b self) -> TVarAddr<'b, 'a> {
        use std::raw::Slice;
        let fat_ptr = Slice::<u8> {
            data: transmute(self),
            len: size_of_val(self),
        };
        //let ptr : &*mut TVar<'a, [u8]> = transmute(self));
        TVarAddr {
            align: align_of::(),
            addr: transmute(fat_ptr),
        }
    }

    ///TODO: change trait API to use this signature
    fn read<'l, 'b> (&'b mut self, l: &'l mut LocalState<'b, 'a>) -> Result<&'l A> {
        l.read(self)
    }

}
impl<'a, A : Copy> TVar<'a, A> {
    ///TODO: change trait API to use this signature
    fn write<'l, 'b>(&'b mut self, l: &'l mut LocalState<'b, 'a>, arg : A) -> Result<()> {
        l.write(self, arg)
    }
}

#[derive(Copy, Clone)]
/// Lies... Lies
struct TVarAddr<'a, 'b : 'a> {
    align: usize,
    addr: &'a TVar<'b, [u8]>, //*mut
    //_phan: PhantomData<&'a TVar<'b, ()>>,
}

impl<'a, 'b : 'a> Hash for TVarAddr<'a, 'b> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.raw_addr().hash(state);
    }
}

impl<'a, 'b : 'a> Eq for TVarAddr<'a, 'b> {}

impl<'a, 'b : 'a> PartialEq for TVarAddr<'a, 'b> {
    fn eq(&self, other: &Self) -> bool {
        let c = self.raw_addr() == other.raw_addr();
        if c {
            debug_assert_eq!(self.raw_len(), other.raw_len());
            debug_assert_eq!(self.align, other.align);
        }
        c
    }
}

impl<'a, 'b : 'a> TVarAddr<'a, 'b> {
    fn raw_addr(self) -> usize {
        self.addr as *const _ as *const () as usize
    }

    fn raw_len(self) -> usize {
        let y = self.addr.val.get();
        unsafe { transmute::<_,&[u8]>(y).len() }
    }

    unsafe fn aligned_mem(self) -> &'a mut [u8] {
        let buf = self.addr.val.get();
        let p = buf as *mut () as usize;
        // Assumes alignment is power of 2
        let o = ((p + (self.align - 1)) & self.align) - p;
        &mut (*buf)[o..]
    }

    fn version(self) -> &'a AtomicUsize {
        &(*self.addr).version
    }

    fn waiters(self) -> &'a mut Vec<(&'b Mutex<bool>, &'b Condvar)> {
        panic!("nyi")
    }
}

pub fn align_down_mut<T>(sp: *mut T, n: usize) -> *mut T {
  let sp = (sp as usize) & !(n - 1);
  sp as *mut T
}
<commit_msg>cleanup<commit_after>//#![allow(unused)]

use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Condvar, Mutex, Arc};
use std::vec::Vec;
use std::collections::HashMap;
use std::cell::UnsafeCell;
use std::hash::{Hash, Hasher};
use std::mem::{align_of, size_of_val, transmute};
use std::slice::bytes::copy_memory;

use ::Result;

pub struct GlobalState { version : AtomicUsize }

/// Baseline implementation of GlobalState, currently do not hqve the aid of the compiler, so this
/// may have major issues.
/// TODO: make a proper implementation of the GlobalState trait
impl GlobalState {
    fn new_local<'l, 'g>(&'g self) -> LocalState<'l, 'g> {
        LocalState {
            reads: Vec::new(),
            writes: HashMap::new(),
            global: self,
            snapshot: self.version.load(Ordering::SeqCst),
        }
    }

    pub fn retry(&self, l: &mut LocalState, func: F) -> A
        where F: FnMut(&mut LocalState) -> Result
    {
        let bx = Arc::new((Mutex::new(false), Condvar::new()));
        for &(addr, _) in &l.reads {
            addr.addr.waiters.lock().unwrap().push(bx.clone());
        }
        let (ref mtx, ref cv) = *bx;
        let mut done = mtx.lock().unwrap();
        while !*done {
            done = cv.wait(done).unwrap();
        }
        self.run(func)
    }

    pub fn run(&self, mut func : F) -> A
        where F: FnMut(&mut LocalState) -> Result
    {
        let mut local = self.new_local();
        match func(&mut local).spec_move() {
            Ok(r) => r,
            _ => self.run(func)
        }
    }

    pub fn or_else(&self, mut func1 : F, func2 : G) -> A
        where F: FnMut(&mut LocalState) -> Result,
              G: FnMut(&mut LocalState) -> Result
    {
        let mut local1 = self.new_local();
        match func1(&mut local1).spec_move() {
            Ok(r) => r,
            //TODO: this may not work, compiler may not know that
            //local1, which borrows self, has relinquised ownership
            _ => self.run(func2)
        }
    }
}

pub struct LocalState<'v, 'g : 'v> {
    /// the norec paper has the reads stored as a list of <address, value> pairs. For us it
    /// would probably be better to have versioned TVars. That way we always have a fast
    /// comparison operation and avoid doing extra dynamic dispatch when validating reads.
    reads : Vec<(TVarAddr<'v, 'g>, usize)>,

    /// for writes we will probably have to cast unsafely to get this to work. TVars just hold
    /// arbitrary types and we only have one table.  XXX: gross
    writes : HashMap<TVarAddr<'v, 'g>, Box<[u8]>>,

    /// STM environment we are using
    /// TODO: how are we getting away with this not being a mutable reference?
    global : &'g GlobalState,

    /// last version at which our view of the global state was valid
    snapshot : usize
}

impl<'v, 'g : 'v> LocalState<'v, 'g> {

    /// Validate the current local state against the state of the world,
    /// Aborts if a TVar in our readset has been written, otherwise
    /// returns the version number to with we are consistent
    pub fn validate(&self) -> Result<usize> {
        loop {
            let time = self.global.version.load(Ordering::SeqCst);
            if (time & 1) == 0 {
                continue;
            }
            for &(addr, version) in &self.reads {
                if addr.version().load(Ordering::SeqCst) != version {
                    return Result::abort();
                }
            }
            return Result::ret(time);
        }
    }

    /// Acquire reference to value in TVar within the transaction
    pub fn read<'l, A>(&'l mut self, tvar : &'v TVar<'g, A>) -> Result<&'l A>
        where 'v : 'l
    {
        let addr: TVarAddr<'v, 'g> = unsafe { tvar.to_addr() } ;

        // Should be &&'l ?
        if let Some(v) = self.writes.get(&addr) {
            let r : && [u8] = &&**v;
            assert_eq!(r.len(), ::std::mem::size_of::());
            let r2 : && A = unsafe { transmute(r) };
            return Result::ret(r2)
        }

        if self.snapshot == self.global.version.load(Ordering::SeqCst) {
            self.reads.push((addr, tvar.version.load(Ordering::SeqCst)));
            Result::ret(unsafe {tvar.get_val()})
        } else {
            self.validate().bind( | v | {
                assert!(self.snapshot <= v);
                self.snapshot = v;
                self.reads.push((addr, tvar.version.load(Ordering::SeqCst)));
                Result::ret(unsafe {tvar.get_val()})
            })
        }
    }

    /// Add the TVar and value to our writeset, these are thread-local until the
    /// transaction commits
    pub fn write(&mut self, tvar : &'v mut TVar<'g, A>, val : A) -> Result<()> {
        let b : Box<[A]> = Box::new([val]);
        unsafe {
            self.writes.insert(tvar.to_addr(), transmute(b));
        }
        Result::ret(())
    }

    /// if (read−only transaction)
    ///     return
    /// while (!CAS(&global lock, snapshot, snapshot + 1))
    ///     snapshot = Validate()
    /// for each (addr, val) in writes
    ///     ∗addr = val
    /// global lock = snapshot + 2 // one more than CAS above
    pub fn commit(&mut self) -> Result<()> {
        fn commit_loop(l : &mut LocalState) -> Result<()> {
            if l.global
                .version
                .compare_and_swap(l.snapshot, l.snapshot + 1, Ordering::SeqCst) == l.snapshot {
                Result::ret(())
            } else {
                l.validate().bind(|v| {
                    l.snapshot = v;
                    commit_loop(l)
                })
            }
        }
        if self.writes.is_empty() {
            Result::ret(())
        } else {
            commit_loop(self).bind(| _ | {
                for (addr, value) in &self.writes {
                    let dst = unsafe { addr.aligned_mem() };
                    debug_assert_eq!(value.len(), dst.len());
                    copy_memory(value, dst);
                    addr.addr.version.fetch_add(1, Ordering::SeqCst);
                    //TODO: DCLP if this is too slow in the common case that waiters is empty
                    let mut waiters = addr.addr.waiters.lock().unwrap();
                    for bx in &*waiters {
                        let (ref mtx, ref cv) = **bx;
                        let mut done = mtx.lock().unwrap();
                        *done = true;
                        cv.notify_all();
                    }
                    waiters.clear();
                }
                self.global
                    .version
                    .compare_and_swap(self.snapshot + 1, self.snapshot + 2, Ordering::SeqCst);
                Result::ret(())
            })
        }
    }
}

/// Haskell-style container of mutable state within a transaction
/// TODO: impl TVar trait
pub struct TVar<'a, A: ?Sized> {
    version : AtomicUsize,
    waiters : Mutex<Vec<Arc<(Mutex<bool>, Condvar)>>>,
    global : &'a GlobalState, //TODO: remove this?
    val : UnsafeCell,
}

impl<'a, A: ?Sized> TVar<'a, A> {
    unsafe fn get_val(&self) -> &A {
        &*self.val.get()
    }

    unsafe fn get_val_mut(&self) -> &mut A {
        &mut *self.val.get()
    }
}

impl<'a, A> TVar<'a, A> {
    unsafe fn to_addr<'b>(&'b self) -> TVarAddr<'b, 'a> {
        use std::raw::Slice;
        let fat_ptr = Slice::<u8> {
            data: transmute(self),
            len: size_of_val(self),
        };
        //let ptr : &*mut TVar<'a, [u8]> = transmute(self));
        TVarAddr {
            align: align_of::(),
            addr: transmute(fat_ptr),
        }
    }

    ///TODO: change trait API to use this signature
    fn read<'l, 'b> (&'b mut self, l: &'l mut LocalState<'b, 'a>) -> Result<&'l A> {
        l.read(self)
    }

}
impl<'a, A : Copy> TVar<'a, A> {
    ///TODO: change trait API to use this signature
    fn write<'l, 'b>(&'b mut self, l: &'l mut LocalState<'b, 'a>, arg : A) -> Result<()> {
        l.write(self, arg)
    }
}

#[derive(Copy, Clone)]
/// Lies... Lies
struct TVarAddr<'a, 'b : 'a> {
    align: usize,
    addr: &'a TVar<'b, [u8]>, //*mut
    //_phan: PhantomData<&'a TVar<'b, ()>>,
}

impl<'a, 'b : 'a> Hash for TVarAddr<'a, 'b> {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.raw_addr().hash(state);
    }
}

impl<'a, 'b : 'a> Eq for TVarAddr<'a, 'b> {}

impl<'a, 'b : 'a> PartialEq for TVarAddr<'a, 'b> {
    fn eq(&self, other: &Self) -> bool {
        let c = self.raw_addr() == other.raw_addr();
        if c {
            debug_assert_eq!(self.raw_len(), other.raw_len());
            debug_assert_eq!(self.align, other.align);
        }
        c
    }
}

impl<'a, 'b : 'a> TVarAddr<'a, 'b> {
    fn raw_addr(self) -> usize {
        self.addr as *const _ as *const () as usize
    }

    fn raw_len(self) -> usize {
        let y = self.addr.val.get();
        unsafe { transmute::<_,&[u8]>(y).len() }
    }

    unsafe fn aligned_mem(self) -> &'a mut [u8] {
        let buf = self.addr.val.get();
        let p = buf as *mut () as usize;
        // Assumes alignment is power of 2
        let o = ((p + (self.align - 1)) & self.align) - p;
        &mut (*buf)[o..]
    }

    fn version(self) -> &'a AtomicUsize {
        &(*self.addr).version
    }
}

pub fn align_down_mut<T>(sp: *mut T, n: usize) -> *mut T {
  let sp = (sp as usize) & !(n - 1);
  sp as *mut T
}
<|endoftext|>


<commit_before>use crate::runtime::basic_scheduler;
use crate::task::JoinHandle;

use std::cell::Cell;
use std::future::Future;

#[derive(Clone, Copy)]
enum State {
    // default executor not defined
    Empty,

    // Basic scheduler (runs on the current-thread)
    Basic(*const basic_scheduler::SchedulerPriv),

    // default executor is a thread pool instance.
    #[cfg(feature = "rt-threaded")]
    ThreadPool(*const thread_pool::Spawner),
}

thread_local! {
    /// Thread-local tracking the current executor
    static EXECUTOR: Cell<State> = Cell::new(State::Empty)
}

// ===== global spawn fns =====

/// Spawns a future on the default executor.
pub(crate) fn spawn<T>(future: T) -> JoinHandle<T::Output>
where
    T: Future + Send + 'static,
    T::Output: Send + 'static,
{
    EXECUTOR.with(|current_executor| match current_executor.get() {
        #[cfg(feature = "rt-threaded")]
        State::ThreadPool(thread_pool_ptr) => {
            let thread_pool = unsafe { &*thread_pool_ptr };
            thread_pool.spawn(future)
        }
        State::Basic(basic_scheduler_ptr) => {
            let basic_scheduler = unsafe { &*basic_scheduler_ptr };

            // Safety: The `BasicScheduler` value set the thread-local (same
            // thread).
            unsafe { basic_scheduler.spawn(future) }
        }
        State::Empty => {
            // Explicit drop of `future` silences the warning that `future` is
            // not used when neither rt-* feature flags are enabled.
            drop(future);
            panic!("must be called from the context of Tokio runtime");
        }
    })
}

pub(super) fn with_basic_scheduler<F, R>(
    basic_scheduler: &basic_scheduler::SchedulerPriv,
    f: F,
) -> R
where
    F: FnOnce() -> R,
{
    with_state(
        State::Basic(basic_scheduler as *const basic_scheduler::SchedulerPriv),
        f,
    )
}

pub(super) fn basic_scheduler_is_current(basic_scheduler: &basic_scheduler::SchedulerPriv) -> bool {
    EXECUTOR.with(|current_executor| match current_executor.get() {
        State::Basic(ptr) => ptr == basic_scheduler as *const _,
        _ => false,
    })
}

cfg_rt_threaded! {
    use crate::runtime::thread_pool;

    pub(super) fn with_thread_pool<F, R>(thread_pool: &thread_pool::Spawner, f: F) -> R
    where
        F: FnOnce() -> R,
    {
        with_state(State::ThreadPool(thread_pool as *const _), f)
    }
}

fn with_state<F, R>(state: State, f: F) -> R
where
    F: FnOnce() -> R,
{
    EXECUTOR.with(|cell| {
        let was = cell.replace(State::Empty);

        // Ensure that the executor is removed from the thread-local context
        // when leaving the scope. This handles cases that involve panicking.
        struct Reset<'a>(&'a Cell<State>, State);

        impl Drop for Reset<'_> {
            fn drop(&mut self) {
                self.0.set(self.1);
            }
        }

        let _reset = Reset(cell, was);

        cell.set(state);

        f()
    })
}
<commit_msg>rt: specify that runtime should have task scheduler (#1839)<commit_after>use crate::runtime::basic_scheduler;
use crate::task::JoinHandle;

use std::cell::Cell;
use std::future::Future;

#[derive(Clone, Copy)]
enum State {
    // default executor not defined
    Empty,

    // Basic scheduler (runs on the current-thread)
    Basic(*const basic_scheduler::SchedulerPriv),

    // default executor is a thread pool instance.
    #[cfg(feature = "rt-threaded")]
    ThreadPool(*const thread_pool::Spawner),
}

thread_local! {
    /// Thread-local tracking the current executor
    static EXECUTOR: Cell<State> = Cell::new(State::Empty)
}

// ===== global spawn fns =====

/// Spawns a future on the default executor.
pub(crate) fn spawn<T>(future: T) -> JoinHandle<T::Output>
where
    T: Future + Send + 'static,
    T::Output: Send + 'static,
{
    EXECUTOR.with(|current_executor| match current_executor.get() {
        #[cfg(feature = "rt-threaded")]
        State::ThreadPool(thread_pool_ptr) => {
            let thread_pool = unsafe { &*thread_pool_ptr };
            thread_pool.spawn(future)
        }
        State::Basic(basic_scheduler_ptr) => {
            let basic_scheduler = unsafe { &*basic_scheduler_ptr };

            // Safety: The `BasicScheduler` value set the thread-local (same
            // thread).
            unsafe { basic_scheduler.spawn(future) }
        }
        State::Empty => {
            // Explicit drop of `future` silences the warning that `future` is
            // not used when neither rt-* feature flags are enabled.
            drop(future);
            panic!("must be called from the context of Tokio runtime configured with either `basic_scheduler` or `threaded_scheduler`");
        }
    })
}

pub(super) fn with_basic_scheduler<F, R>(
    basic_scheduler: &basic_scheduler::SchedulerPriv,
    f: F,
) -> R
where
    F: FnOnce() -> R,
{
    with_state(
        State::Basic(basic_scheduler as *const basic_scheduler::SchedulerPriv),
        f,
    )
}

pub(super) fn basic_scheduler_is_current(basic_scheduler: &basic_scheduler::SchedulerPriv) -> bool {
    EXECUTOR.with(|current_executor| match current_executor.get() {
        State::Basic(ptr) => ptr == basic_scheduler as *const _,
        _ => false,
    })
}

cfg_rt_threaded! {
    use crate::runtime::thread_pool;

    pub(super) fn with_thread_pool<F, R>(thread_pool: &thread_pool::Spawner, f: F) -> R
    where
        F: FnOnce() -> R,
    {
        with_state(State::ThreadPool(thread_pool as *const _), f)
    }
}

fn with_state<F, R>(state: State, f: F) -> R
where
    F: FnOnce() -> R,
{
    EXECUTOR.with(|cell| {
        let was = cell.replace(State::Empty);

        // Ensure that the executor is removed from the thread-local context
        // when leaving the scope. This handles cases that involve panicking.
        struct Reset<'a>(&'a Cell<State>, State);

        impl Drop for Reset<'_> {
            fn drop(&mut self) {
                self.0.set(self.1);
            }
        }

        let _reset = Reset(cell, was);

        cell.set(state);

        f()
    })
}
<|endoftext|>