<commit_before>use futures::channel::{mpsc, oneshot};
use futures::executor::block_on;
use futures::future::{self, poll_fn, FutureExt};
use futures::sink::SinkExt;
use futures::stream::StreamExt;
use futures::task::{Context, Poll};
use futures::{
    join, pending, pin_mut, poll, select, select_biased, stream, stream_select, try_join,
};
use std::mem;

#[test]
fn poll_and_pending() {
    let pending_once = async { pending!() };
    block_on(async {
        pin_mut!(pending_once);
        assert_eq!(Poll::Pending, poll!(&mut pending_once));
        assert_eq!(Poll::Ready(()), poll!(&mut pending_once));
    });
}

#[test]
fn join() {
    let (tx1, rx1) = oneshot::channel::<i32>();
    let (tx2, rx2) = oneshot::channel::<i32>();

    let fut = async {
        let res = join!(rx1, rx2);
        assert_eq!((Ok(1), Ok(2)), res);
    };

    block_on(async {
        pin_mut!(fut);
        assert_eq!(Poll::Pending, poll!(&mut fut));
        tx1.send(1).unwrap();
        assert_eq!(Poll::Pending, poll!(&mut fut));
        tx2.send(2).unwrap();
        assert_eq!(Poll::Ready(()), poll!(&mut fut));
    });
}

#[test]
fn select() {
    let (tx1, rx1) = oneshot::channel::<i32>();
    let (_tx2, rx2) = oneshot::channel::<i32>();
    tx1.send(1).unwrap();
    let mut ran = false;
    block_on(async {
        select! {
            res = rx1.fuse() => {
                assert_eq!(Ok(1), res);
                ran = true;
            },
            _ = rx2.fuse() => unreachable!(),
        }
    });
    assert!(ran);
}

#[test]
fn select_biased() {
    let (tx1, rx1) = oneshot::channel::<i32>();
    let (_tx2, rx2) = oneshot::channel::<i32>();
    tx1.send(1).unwrap();
    let mut ran = false;
    block_on(async {
        select_biased! {
            res = rx1.fuse() => {
                assert_eq!(Ok(1), res);
                ran = true;
            },
            _ = rx2.fuse() => unreachable!(),
        }
    });
    assert!(ran);
}

#[test]
fn select_streams() {
    let (mut tx1, rx1) = mpsc::channel::<i32>(1);
    let (mut tx2, rx2) = mpsc::channel::<i32>(1);
    let mut rx1 = rx1.fuse();
    let mut rx2 = rx2.fuse();
    let mut ran = false;
    let mut total = 0;
    block_on(async {
        let mut tx1_opt;
        let mut tx2_opt;
        select! {
            _ = rx1.next() => panic!(),
            _ = rx2.next() => panic!(),
            default => {
                tx1.send(2).await.unwrap();
                tx2.send(3).await.unwrap();
                tx1_opt = Some(tx1);
                tx2_opt = Some(tx2);
            }
            complete => panic!(),
        }
        loop {
            select! {
                // runs first and again after default
                x = rx1.next() => if let Some(x) = x { total += x; },
                // runs second and again after default
                x = rx2.next()  => if let Some(x) = x { total += x; },
                // runs third
                default => {
                    assert_eq!(total, 5);
                    ran = true;
                    drop(tx1_opt.take().unwrap());
                    drop(tx2_opt.take().unwrap());
                },
                // runs last
                complete => break,
            };
        }
    });
    assert!(ran);
}

#[test]
fn select_can_move_uncompleted_futures() {
    let (tx1, rx1) = oneshot::channel::<i32>();
    let (tx2, rx2) = oneshot::channel::<i32>();
    tx1.send(1).unwrap();
    tx2.send(2).unwrap();
    let mut ran = false;
    let mut rx1 = rx1.fuse();
    let mut rx2 = rx2.fuse();
    block_on(async {
        select! {
            res = rx1 => {
                assert_eq!(Ok(1), res);
                assert_eq!(Ok(2), rx2.await);
                ran = true;
            },
            res = rx2 => {
                assert_eq!(Ok(2), res);
                assert_eq!(Ok(1), rx1.await);
                ran = true;
            },
        }
    });
    assert!(ran);
}

#[test]
fn select_nested() {
    let mut outer_fut = future::ready(1);
    let mut inner_fut = future::ready(2);
    let res = block_on(async {
        select! {
            x = outer_fut => {
                select! {
                    y = inner_fut => x + y,
                }
            }
        }
    });
    assert_eq!(res, 3);
}

#[cfg_attr(not(target_pointer_width = "64"), ignore)]
#[test]
fn select_size() {
    let fut = async {
        let mut ready = future::ready(0i32);
        select! {
            _ = ready => {},
        }
    };
    assert_eq!(mem::size_of_val(&fut), 24);

    let fut = async {
        let mut ready1 = future::ready(0i32);
        let mut ready2 = future::ready(0i32);
        select! {
            _ = ready1 => {},
            _ = ready2 => {},
        }
    };
    assert_eq!(mem::size_of_val(&fut), 40);
}

#[test]
fn select_on_non_unpin_expressions() {
    // The returned Future is !Unpin
    let make_non_unpin_fut = || async { 5 };

    let res = block_on(async {
        let select_res;
        select! {
            value_1 = make_non_unpin_fut().fuse() => select_res = value_1,
            value_2 = make_non_unpin_fut().fuse() => select_res = value_2,
        };
        select_res
    });
    assert_eq!(res, 5);
}

#[test]
fn select_on_non_unpin_expressions_with_default() {
    // The returned Future is !Unpin
    let make_non_unpin_fut = || async { 5 };

    let res = block_on(async {
        let select_res;
        select! {
            value_1 = make_non_unpin_fut().fuse() => select_res = value_1,
            value_2 = make_non_unpin_fut().fuse() => select_res = value_2,
            default => select_res = 7,
        };
        select_res
    });
    assert_eq!(res, 5);
}

#[cfg_attr(not(target_pointer_width = "64"), ignore)]
#[test]
fn select_on_non_unpin_size() {
    // The returned Future is !Unpin
    let make_non_unpin_fut = || async { 5 };

    let fut = async {
        let select_res;
        select! {
            value_1 = make_non_unpin_fut().fuse() => select_res = value_1,
            value_2 = make_non_unpin_fut().fuse() => select_res = value_2,
        };
        select_res
    };

    assert_eq!(32, mem::size_of_val(&fut));
}

#[test]
fn select_can_be_used_as_expression() {
    block_on(async {
        let res = select! {
            x = future::ready(7) => x,
            y = future::ready(3) => y + 1,
        };
        assert!(res == 7 || res == 4);
    });
}

#[test]
fn select_with_default_can_be_used_as_expression() {
    fn poll_always_pending<T>(_cx: &mut Context<'_>) -> Poll<T> {
        Poll::Pending
    }

    block_on(async {
        let res = select! {
            x = poll_fn(poll_always_pending::<i32>).fuse() => x,
            y = poll_fn(poll_always_pending::<i32>).fuse() => y + 1,
            default => 99,
        };
        assert_eq!(res, 99);
    });
}

#[test]
fn select_with_complete_can_be_used_as_expression() {
    block_on(async {
        let res = select! {
            x = future::pending::<i32>() => x,
            y = future::pending::<i32>() => y + 1,
            default => 99,
            complete => 237,
        };
        assert_eq!(res, 237);
    });
}

#[test]
#[allow(unused_assignments)]
fn select_on_mutable_borrowing_future_with_same_borrow_in_block() {
    async fn require_mutable(_: &mut i32) {}
    async fn async_noop() {}

    block_on(async {
        let mut value = 234;
        select! {
            _ = require_mutable(&mut value).fuse() => { },
            _ = async_noop().fuse() => {
                value += 5;
            },
        }
    });
}

#[test]
#[allow(unused_assignments)]
fn select_on_mutable_borrowing_future_with_same_borrow_in_block_and_default() {
    async fn require_mutable(_: &mut i32) {}
    async fn async_noop() {}

    block_on(async {
        let mut value = 234;
        select! {
            _ = require_mutable(&mut value).fuse() => { },
            _ = async_noop().fuse() => {
                value += 5;
            },
            default => {
                value += 27;
            },
        }
    });
}

#[test]
#[allow(unused_assignments)]
fn stream_select() {
    // stream_select! macro
    block_on(async {
        let endless_ints = |i| stream::iter(vec![i].into_iter().cycle());

        let mut endless_ones = stream_select!(endless_ints(1i32), stream::pending());
        assert_eq!(endless_ones.next().await, Some(1));
        assert_eq!(endless_ones.next().await, Some(1));

        let mut finite_list =
            stream_select!(stream::iter(vec![1].into_iter()), stream::iter(vec![1].into_iter()));
        assert_eq!(finite_list.next().await, Some(1));
        assert_eq!(finite_list.next().await, Some(1));
        assert_eq!(finite_list.next().await, None);

        let endless_mixed = stream_select!(endless_ints(1i32), endless_ints(2), endless_ints(3));
        // Take 1000, and assert a somewhat even distribution of values.
        // The fairness is randomized, but over 1000 samples we should be pretty close to even.
        // This test may be a bit flaky. Feel free to adjust the margins as you see fit.
        let mut count = 0;
        let results = endless_mixed
            .take_while(move |_| {
                count += 1;
                let ret = count < 1000;
                async move { ret }
            })
            .collect::<Vec<_>>()
            .await;
        assert!(results.iter().filter(|x| **x == 1).count() >= 299);
        assert!(results.iter().filter(|x| **x == 2).count() >= 299);
        assert!(results.iter().filter(|x| **x == 3).count() >= 299);
    });
}

#[test]
fn join_size() {
    let fut = async {
        let ready = future::ready(0i32);
        join!(ready)
    };
    assert_eq!(mem::size_of_val(&fut), 16);

    let fut = async {
        let ready1 = future::ready(0i32);
        let ready2 = future::ready(0i32);
        join!(ready1, ready2)
    };
    assert_eq!(mem::size_of_val(&fut), 28);
}

#[test]
fn try_join_size() {
    let fut = async {
        let ready = future::ready(Ok::<i32, i32>(0));
        try_join!(ready)
    };
    assert_eq!(mem::size_of_val(&fut), 16);

    let fut = async {
        let ready1 = future::ready(Ok::<i32, i32>(0));
        let ready2 = future::ready(Ok::<i32, i32>(0));
        try_join!(ready1, ready2)
    };
    assert_eq!(mem::size_of_val(&fut), 28);
}

#[test]
fn join_doesnt_require_unpin() {
    let _ = async { join!(async {}, async {}) };
}

#[test]
fn try_join_doesnt_require_unpin() {
    let _ = async { try_join!(async { Ok::<(), ()>(()) }, async { Ok::<(), ()>(()) },) };
}
<commit_msg>Ignore buggy clippy::collapsible_match lint (#2482)<commit_after>#![allow(clippy::collapsible_match)] // https://github.com/rust-lang/rust-clippy/issues/7591

use futures::channel::{mpsc, oneshot};
use futures::executor::block_on;
use futures::future::{self, poll_fn, FutureExt};
use futures::sink::SinkExt;
use futures::stream::StreamExt;
use futures::task::{Context, Poll};
use futures::{
    join, pending, pin_mut, poll, select, select_biased, stream, stream_select, try_join,
};
use std::mem;

#[test]
fn poll_and_pending() {
    let pending_once = async { pending!() };
    block_on(async {
        pin_mut!(pending_once);
        assert_eq!(Poll::Pending, poll!(&mut pending_once));
        assert_eq!(Poll::Ready(()), poll!(&mut pending_once));
    });
}

#[test]
fn join() {
    let (tx1, rx1) = oneshot::channel::<i32>();
    let (tx2, rx2) = oneshot::channel::<i32>();

    let fut = async {
        let res = join!(rx1, rx2);
        assert_eq!((Ok(1), Ok(2)), res);
    };

    block_on(async {
        pin_mut!(fut);
        assert_eq!(Poll::Pending, poll!(&mut fut));
        tx1.send(1).unwrap();
        assert_eq!(Poll::Pending, poll!(&mut fut));
        tx2.send(2).unwrap();
        assert_eq!(Poll::Ready(()), poll!(&mut fut));
    });
}

#[test]
fn select() {
    let (tx1, rx1) = oneshot::channel::<i32>();
    let (_tx2, rx2) = oneshot::channel::<i32>();
    tx1.send(1).unwrap();
    let mut ran = false;
    block_on(async {
        select! {
            res = rx1.fuse() => {
                assert_eq!(Ok(1), res);
                ran = true;
            },
            _ = rx2.fuse() => unreachable!(),
        }
    });
    assert!(ran);
}

#[test]
fn select_biased() {
    let (tx1, rx1) = oneshot::channel::<i32>();
    let (_tx2, rx2) = oneshot::channel::<i32>();
    tx1.send(1).unwrap();
    let mut ran = false;
    block_on(async {
        select_biased! {
            res = rx1.fuse() => {
                assert_eq!(Ok(1), res);
                ran = true;
            },
            _ = rx2.fuse() => unreachable!(),
        }
    });
    assert!(ran);
}

#[test]
fn select_streams() {
    let (mut tx1, rx1) = mpsc::channel::<i32>(1);
    let (mut tx2, rx2) = mpsc::channel::<i32>(1);
    let mut rx1 = rx1.fuse();
    let mut rx2 = rx2.fuse();
    let mut ran = false;
    let mut total = 0;
    block_on(async {
        let mut tx1_opt;
        let mut tx2_opt;
        select! {
            _ = rx1.next() => panic!(),
            _ = rx2.next() => panic!(),
            default => {
                tx1.send(2).await.unwrap();
                tx2.send(3).await.unwrap();
                tx1_opt = Some(tx1);
                tx2_opt = Some(tx2);
            }
            complete => panic!(),
        }
        loop {
            select! {
                // runs first and again after default
                x = rx1.next() => if let Some(x) = x { total += x; },
                // runs second and again after default
                x = rx2.next()  => if let Some(x) = x { total += x; },
                // runs third
                default => {
                    assert_eq!(total, 5);
                    ran = true;
                    drop(tx1_opt.take().unwrap());
                    drop(tx2_opt.take().unwrap());
                },
                // runs last
                complete => break,
            };
        }
    });
    assert!(ran);
}

#[test]
fn select_can_move_uncompleted_futures() {
    let (tx1, rx1) = oneshot::channel::<i32>();
    let (tx2, rx2) = oneshot::channel::<i32>();
    tx1.send(1).unwrap();
    tx2.send(2).unwrap();
    let mut ran = false;
    let mut rx1 = rx1.fuse();
    let mut rx2 = rx2.fuse();
    block_on(async {
        select! {
            res = rx1 => {
                assert_eq!(Ok(1), res);
                assert_eq!(Ok(2), rx2.await);
                ran = true;
            },
            res = rx2 => {
                assert_eq!(Ok(2), res);
                assert_eq!(Ok(1), rx1.await);
                ran = true;
            },
        }
    });
    assert!(ran);
}

#[test]
fn select_nested() {
    let mut outer_fut = future::ready(1);
    let mut inner_fut = future::ready(2);
    let res = block_on(async {
        select! {
            x = outer_fut => {
                select! {
                    y = inner_fut => x + y,
                }
            }
        }
    });
    assert_eq!(res, 3);
}

#[cfg_attr(not(target_pointer_width = "64"), ignore)]
#[test]
fn select_size() {
    let fut = async {
        let mut ready = future::ready(0i32);
        select! {
            _ = ready => {},
        }
    };
    assert_eq!(mem::size_of_val(&fut), 24);

    let fut = async {
        let mut ready1 = future::ready(0i32);
        let mut ready2 = future::ready(0i32);
        select! {
            _ = ready1 => {},
            _ = ready2 => {},
        }
    };
    assert_eq!(mem::size_of_val(&fut), 40);
}

#[test]
fn select_on_non_unpin_expressions() {
    // The returned Future is !Unpin
    let make_non_unpin_fut = || async { 5 };

    let res = block_on(async {
        let select_res;
        select! {
            value_1 = make_non_unpin_fut().fuse() => select_res = value_1,
            value_2 = make_non_unpin_fut().fuse() => select_res = value_2,
        };
        select_res
    });
    assert_eq!(res, 5);
}

#[test]
fn select_on_non_unpin_expressions_with_default() {
    // The returned Future is !Unpin
    let make_non_unpin_fut = || async { 5 };

    let res = block_on(async {
        let select_res;
        select! {
            value_1 = make_non_unpin_fut().fuse() => select_res = value_1,
            value_2 = make_non_unpin_fut().fuse() => select_res = value_2,
            default => select_res = 7,
        };
        select_res
    });
    assert_eq!(res, 5);
}

#[cfg_attr(not(target_pointer_width = "64"), ignore)]
#[test]
fn select_on_non_unpin_size() {
    // The returned Future is !Unpin
    let make_non_unpin_fut = || async { 5 };

    let fut = async {
        let select_res;
        select! {
            value_1 = make_non_unpin_fut().fuse() => select_res = value_1,
            value_2 = make_non_unpin_fut().fuse() => select_res = value_2,
        };
        select_res
    };

    assert_eq!(32, mem::size_of_val(&fut));
}

#[test]
fn select_can_be_used_as_expression() {
    block_on(async {
        let res = select! {
            x = future::ready(7) => x,
            y = future::ready(3) => y + 1,
        };
        assert!(res == 7 || res == 4);
    });
}

#[test]
fn select_with_default_can_be_used_as_expression() {
    fn poll_always_pending<T>(_cx: &mut Context<'_>) -> Poll<T> {
        Poll::Pending
    }

    block_on(async {
        let res = select! {
            x = poll_fn(poll_always_pending::<i32>).fuse() => x,
            y = poll_fn(poll_always_pending::<i32>).fuse() => y + 1,
            default => 99,
        };
        assert_eq!(res, 99);
    });
}

#[test]
fn select_with_complete_can_be_used_as_expression() {
    block_on(async {
        let res = select! {
            x = future::pending::<i32>() => x,
            y = future::pending::<i32>() => y + 1,
            default => 99,
            complete => 237,
        };
        assert_eq!(res, 237);
    });
}

#[test]
#[allow(unused_assignments)]
fn select_on_mutable_borrowing_future_with_same_borrow_in_block() {
    async fn require_mutable(_: &mut i32) {}
    async fn async_noop() {}

    block_on(async {
        let mut value = 234;
        select! {
            _ = require_mutable(&mut value).fuse() => { },
            _ = async_noop().fuse() => {
                value += 5;
            },
        }
    });
}

#[test]
#[allow(unused_assignments)]
fn select_on_mutable_borrowing_future_with_same_borrow_in_block_and_default() {
    async fn require_mutable(_: &mut i32) {}
    async fn async_noop() {}

    block_on(async {
        let mut value = 234;
        select! {
            _ = require_mutable(&mut value).fuse() => { },
            _ = async_noop().fuse() => {
                value += 5;
            },
            default => {
                value += 27;
            },
        }
    });
}

#[test]
#[allow(unused_assignments)]
fn stream_select() {
    // stream_select! macro
    block_on(async {
        let endless_ints = |i| stream::iter(vec![i].into_iter().cycle());

        let mut endless_ones = stream_select!(endless_ints(1i32), stream::pending());
        assert_eq!(endless_ones.next().await, Some(1));
        assert_eq!(endless_ones.next().await, Some(1));

        let mut finite_list =
            stream_select!(stream::iter(vec![1].into_iter()), stream::iter(vec![1].into_iter()));
        assert_eq!(finite_list.next().await, Some(1));
        assert_eq!(finite_list.next().await, Some(1));
        assert_eq!(finite_list.next().await, None);

        let endless_mixed = stream_select!(endless_ints(1i32), endless_ints(2), endless_ints(3));
        // Take 1000, and assert a somewhat even distribution of values.
        // The fairness is randomized, but over 1000 samples we should be pretty close to even.
        // This test may be a bit flaky. Feel free to adjust the margins as you see fit.
        let mut count = 0;
        let results = endless_mixed
            .take_while(move |_| {
                count += 1;
                let ret = count < 1000;
                async move { ret }
            })
            .collect::<Vec<_>>()
            .await;
        assert!(results.iter().filter(|x| **x == 1).count() >= 299);
        assert!(results.iter().filter(|x| **x == 2).count() >= 299);
        assert!(results.iter().filter(|x| **x == 3).count() >= 299);
    });
}

#[test]
fn join_size() {
    let fut = async {
        let ready = future::ready(0i32);
        join!(ready)
    };
    assert_eq!(mem::size_of_val(&fut), 16);

    let fut = async {
        let ready1 = future::ready(0i32);
        let ready2 = future::ready(0i32);
        join!(ready1, ready2)
    };
    assert_eq!(mem::size_of_val(&fut), 28);
}

#[test]
fn try_join_size() {
    let fut = async {
        let ready = future::ready(Ok::<i32, i32>(0));
        try_join!(ready)
    };
    assert_eq!(mem::size_of_val(&fut), 16);

    let fut = async {
        let ready1 = future::ready(Ok::<i32, i32>(0));
        let ready2 = future::ready(Ok::<i32, i32>(0));
        try_join!(ready1, ready2)
    };
    assert_eq!(mem::size_of_val(&fut), 28);
}

#[test]
fn join_doesnt_require_unpin() {
    let _ = async { join!(async {}, async {}) };
}

#[test]
fn try_join_doesnt_require_unpin() {
    let _ = async { try_join!(async { Ok::<(), ()>(()) }, async { Ok::<(), ()>(()) },) };
}
<|endoftext|>


<commit_before>use master_smasher::drawable::{Asset, Drawable};
use master_smasher::shape::{Circle, Intersect, Shape};
use super::collidable::Collidable;
use super::planet::Planet;

use glm;

use std::cmp;

pub struct LaunchedMeteor {
    asset: Asset,
    body: Circle,
    velocity: glm::DVec2,
    max_coords: glm::UVec2,
}

impl LaunchedMeteor {
    pub fn new(asset: Asset, max_coords: glm::UVec2, velocity: glm::DVec2) -> Self {
        let center = glm::to_dvec2(asset.center());
        let dims = glm::to_ivec2(asset.dims());
        let radius = cmp::min(dims.x, dims.y) as f64 / 2.;

        let body = Circle {
            center: center,
            radius: radius,
        };

        LaunchedMeteor {
            asset: asset,
            body: body,
            velocity: velocity,
            max_coords: max_coords,
        }
    }

    pub fn update(&mut self, planets: &[Planet]) {
        self.pull(planets);
        self.displace();
    }

    pub fn drawables(&self) -> Vec<Drawable> {
        vec![Drawable::Asset(&self.asset)]
    }

    pub fn collides<S, C>(&self, collidable: &C) -> bool
        where S: Shape,
              C: Collidable<S, Circle>,
              Circle: Intersect<S>
    {
        collidable.collides(&self.body)
    }

    pub fn center(&self) -> glm::DVec2 {
        self.body.center
    }

    fn pull(&mut self, planets: &[Planet]) {
        for planet in planets {
            let acceleration = planet.pull_vector(self.body.center, self.body.radius);
            self.velocity = self.velocity + acceleration / 50.;
        }
    }

    fn displace(&mut self) {
        let max_coords = glm::to_dvec2(self.max_coords);
        self.body.center = self.body.center + self.velocity;
        self.body.center = (self.body.center + max_coords) % max_coords;
        self.asset.center_on(glm::to_ivec2(self.body.center));
    }
}
<commit_msg>refactored launched meteor<commit_after>use master_smasher::drawable::{Asset, Drawable};
use master_smasher::shape::{Circle, Intersect, Shape};
use super::collidable::Collidable;
use super::planet::Planet;

use glm;

use std::cmp;

pub struct LaunchedMeteor {
    asset: Asset,
    body: Circle,
    velocity: glm::DVec2,
    max_coords: glm::UVec2,
}

impl LaunchedMeteor {
    pub fn new(asset: Asset, max_coords: glm::UVec2, velocity: glm::DVec2) -> Self {
        let center = glm::to_dvec2(asset.center());
        let dims = glm::to_ivec2(asset.dims());
        let radius = cmp::min(dims.x, dims.y) as f64 / 2.;
        let body = Circle {
            center: center,
            radius: radius,
        };

        LaunchedMeteor {
            asset: asset,
            body: body,
            velocity: velocity,
            max_coords: max_coords,
        }
    }

    pub fn update(&mut self, planets: &[Planet]) {
        self.velocity = self.velocity + self.acceleration(planets);
        self.displace();
    }

    pub fn drawables(&self) -> Vec<Drawable> {
        vec![Drawable::Asset(&self.asset)]
    }

    pub fn collides<S, C>(&self, collidable: &C) -> bool
        where S: Shape,
              C: Collidable<S, Circle>,
              Circle: Intersect<S>
    {
        collidable.collides(&self.body)
    }

    pub fn center(&self) -> glm::DVec2 {
        self.body.center
    }

    fn acceleration(&self, planets: &[Planet]) -> glm::DVec2 {
        planets.iter()
            .map(|p| p.pull_vector(self.body.center, self.body.radius))
            .fold(glm::dvec2(0., 0.), |c, a| c + a) / 50.
    }

    fn displace(&mut self) {
        let max_coords = glm::to_dvec2(self.max_coords);
        self.body.center = self.body.center + self.velocity;
        self.body.center = (self.body.center + max_coords) % max_coords;
        self.asset.center_on(glm::to_ivec2(self.body.center));
    }
}
<|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 https://mozilla.org/MPL/2.0/. */

use crate::canvas_data::{
    Backend, CanvasPaintState, Color, CompositionOp, DrawOptions, ExtendMode, Filter,
    GenericDrawTarget, GenericPathBuilder, GradientStop, GradientStops, Path, Pattern,
    SourceSurface, StrokeOptions, SurfaceFormat,
};
use crate::canvas_paint_thread::AntialiasMode;
use canvas_traits::canvas::*;
use cssparser::RGBA;
use euclid::default::{Point2D, Rect, Size2D, Transform2D, Vector2D};
use std::marker::PhantomData;

pub struct RaqoteBackend;

impl Backend for RaqoteBackend {
    fn get_composition_op(&self, _opts: &DrawOptions) -> CompositionOp {
        unimplemented!()
    }

    fn need_to_draw_shadow(&self, _color: &Color) -> bool {
        unimplemented!()
    }

    fn size_from_pattern(&self, _rect: &Rect<f32>, _pattern: &Pattern) -> Option<Size2D<f32>> {
        unimplemented!()
    }

    fn set_shadow_color<'a>(&mut self, _color: RGBA, _state: &mut CanvasPaintState<'a>) {
        unimplemented!()
    }

    fn set_fill_style<'a>(
        &mut self,
        _style: FillOrStrokeStyle,
        _state: &mut CanvasPaintState<'a>,
        _drawtarget: &dyn GenericDrawTarget,
    ) {
        unimplemented!()
    }

    fn set_stroke_style<'a>(
        &mut self,
        _style: FillOrStrokeStyle,
        _state: &mut CanvasPaintState<'a>,
        _drawtarget: &dyn GenericDrawTarget,
    ) {
        unimplemented!()
    }

    fn set_global_composition<'a>(
        &mut self,
        _op: CompositionOrBlending,
        _state: &mut CanvasPaintState<'a>,
    ) {
        unimplemented!()
    }

    fn create_drawtarget(&self, size: Size2D<u64>) -> Box<dyn GenericDrawTarget> {
        Box::new(raqote::DrawTarget::new(
            size.width as i32,
            size.height as i32,
        ))
    }

    fn recreate_paint_state<'a>(&self, _state: &CanvasPaintState<'a>) -> CanvasPaintState<'a> {
        CanvasPaintState::new(AntialiasMode::Default)
    }
}

impl<'a> CanvasPaintState<'a> {
    pub fn new(_antialias: AntialiasMode) -> CanvasPaintState<'a> {
        CanvasPaintState {
            draw_options: DrawOptions::Raqote(raqote::DrawOptions::new()),
            fill_style: Pattern::Raqote(()),
            stroke_style: Pattern::Raqote(()),
            stroke_opts: StrokeOptions::Raqote(Default::default(), PhantomData),
            transform: Transform2D::identity(),
            shadow_offset_x: 0.0,
            shadow_offset_y: 0.0,
            shadow_blur: 0.0,
            shadow_color: Color::Raqote(()),
        }
    }
}

impl Pattern {
    pub fn is_zero_size_gradient(&self) -> bool {
        match *self {
            Pattern::Raqote(()) => unimplemented!(),
        }
    }
}

impl<'a> StrokeOptions<'a> {
    pub fn set_line_width(&mut self, _val: f32) {
        match self {
            StrokeOptions::Raqote(options, _) => options.width = _val,
        }
    }
    pub fn set_miter_limit(&mut self, _val: f32) {
        match self {
            StrokeOptions::Raqote(options, _) => options.miter_limit = _val,
        }
    }
    pub fn set_line_join(&mut self, _val: LineJoinStyle) {
        match self {
            StrokeOptions::Raqote(options, _) => options.join = _val.to_raqote_style(),
        }
    }
    pub fn set_line_cap(&mut self, _val: LineCapStyle) {
        match self {
            StrokeOptions::Raqote(options, _) => options.cap = _val.to_raqote_style(),
        }
    }
}

impl DrawOptions {
    pub fn set_alpha(&mut self, _val: f32) {
        match self {
            DrawOptions::Raqote(draw_options) => draw_options.alpha = _val,
        }
    }
}

impl Path {
    pub fn transformed_copy_to_builder(
        &self,
        _transform: &Transform2D<f32>,
    ) -> Box<dyn GenericPathBuilder> {
        unimplemented!()
    }

    pub fn contains_point(&self, _x: f64, _y: f64, _path_transform: &Transform2D<f32>) -> bool {
        unimplemented!()
    }

    pub fn copy_to_builder(&self) -> Box<dyn GenericPathBuilder> {
        unimplemented!()
    }
}

impl GenericDrawTarget for raqote::DrawTarget {
    fn clear_rect(&self, _rect: &Rect<f32>) {
        unimplemented!()
    }

    fn copy_surface(
        &self,
        _surface: SourceSurface,
        _source: Rect<i32>,
        _destination: Point2D<i32>,
    ) {
        unimplemented!()
    }

    fn create_gradient_stops(
        &self,
        _gradient_stops: Vec<GradientStop>,
        _extend_mode: ExtendMode,
    ) -> GradientStops {
        unimplemented!()
    }

    fn create_path_builder(&self) -> Box<dyn GenericPathBuilder> {
        unimplemented!()
    }

    fn create_similar_draw_target(
        &self,
        _size: &Size2D<i32>,
        _format: SurfaceFormat,
    ) -> Box<dyn GenericDrawTarget> {
        unimplemented!()
    }
    fn create_source_surface_from_data(
        &self,
        _data: &[u8],
        _size: Size2D<i32>,
        _stride: i32,
    ) -> Option<SourceSurface> {
        unimplemented!()
    }
    fn draw_surface(
        &self,
        _surface: SourceSurface,
        _dest: Rect<f64>,
        _source: Rect<f64>,
        _filter: Filter,
        _draw_options: &DrawOptions,
    ) {
        unimplemented!()
    }
    fn draw_surface_with_shadow(
        &self,
        _surface: SourceSurface,
        _dest: &Point2D<f32>,
        _color: &Color,
        _offset: &Vector2D<f32>,
        _sigma: f32,
        _operator: CompositionOp,
    ) {
        unimplemented!()
    }
    fn fill(&self, _path: &Path, _pattern: Pattern, _draw_options: &DrawOptions) {
        unimplemented!()
    }
    fn fill_rect(&self, _rect: &Rect<f32>, _pattern: Pattern, _draw_options: Option<&DrawOptions>) {
        unimplemented!()
    }
    fn get_format(&self) -> SurfaceFormat {
        unimplemented!()
    }
    fn get_size(&self) -> Size2D<i32> {
        unimplemented!()
    }
    fn get_transform(&self) -> Transform2D<f32> {
        unimplemented!()
    }
    fn pop_clip(&self) {
        unimplemented!()
    }
    fn push_clip(&self, _path: &Path) {
        unimplemented!()
    }
    fn set_transform(&self, _matrix: &Transform2D<f32>) {
        unimplemented!()
    }
    fn snapshot(&self) -> SourceSurface {
        unimplemented!()
    }
    fn stroke(
        &self,
        _path: &Path,
        _pattern: Pattern,
        _stroke_options: &StrokeOptions,
        _draw_options: &DrawOptions,
    ) {
        unimplemented!()
    }
    fn stroke_line(
        &self,
        _start: Point2D<f32>,
        _end: Point2D<f32>,
        _pattern: Pattern,
        _stroke_options: &StrokeOptions,
        _draw_options: &DrawOptions,
    ) {
        unimplemented!()
    }
    fn stroke_rect(
        &self,
        _rect: &Rect<f32>,
        _pattern: Pattern,
        _stroke_options: &StrokeOptions<'_>,
        _draw_options: &DrawOptions,
    ) {
        unimplemented!()
    }

    fn snapshot_data(&self, _f: &dyn Fn(&[u8]) -> Vec<u8>) -> Vec<u8> {
        unimplemented!()
    }

    fn snapshot_data_owned(&self) -> Vec<u8> {
        unimplemented!()
    }
}

impl GenericPathBuilder for raqote::PathBuilder {
    fn arc(
        &mut self,
        origin: Point2D<f32>,
        radius: f32,
        start_angle: f32,
        end_angle: f32,
        anticlockwise: bool,
    ) {
        unimplemented!();
    }
    fn bezier_curve_to(
        &mut self,
        control_point1: &Point2D<f32>,
        control_point2: &Point2D<f32>,
        control_point3: &Point2D<f32>,
    ) {
        unimplemented!();
    }
    fn close(&mut self) {
        unimplemented!();
    }
    fn ellipse(
        &mut self,
        origin: Point2D<f32>,
        radius_x: f32,
        radius_y: f32,
        rotation_angle: f32,
        start_angle: f32,
        end_angle: f32,
        anticlockwise: bool,
    ) {
        unimplemented!();
    }
    fn get_current_point(&mut self) -> Point2D<f32> {
        unimplemented!();
    }
    fn line_to(&mut self, point: Point2D<f32>) {
        unimplemented!();
    }
    fn move_to(&mut self, point: Point2D<f32>) {
        unimplemented!();
    }
    fn quadratic_curve_to(&mut self, control_point: &Point2D<f32>, end_point: &Point2D<f32>) {
        unimplemented!();
    }
    fn finish(&mut self) -> Path {
        unimplemented!();
    }
}

pub trait ToRaqoteStyle {
    type Target;

    fn to_raqote_style(self) -> Self::Target;
}

impl ToRaqoteStyle for LineJoinStyle {
    type Target = raqote::LineJoin;

    fn to_raqote_style(self) -> raqote::LineJoin {
        match self {
            LineJoinStyle::Round => raqote::LineJoin::Round,
            LineJoinStyle::Bevel => raqote::LineJoin::Bevel,
            LineJoinStyle::Miter => raqote::LineJoin::Miter,
        }
    }
}

impl ToRaqoteStyle for LineCapStyle {
    type Target = raqote::LineCap;

    fn to_raqote_style(self) -> raqote::LineCap {
        match self {
            LineCapStyle::Butt => raqote::LineCap::Butt,
            LineCapStyle::Round => raqote::LineCap::Round,
            LineCapStyle::Square => raqote::LineCap::Square,
        }
    }
}
<commit_msg>Implement provided raqote::PathBuilder's methods for GenericPathBuilder<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 https://mozilla.org/MPL/2.0/. */

use crate::canvas_data::{
    Backend, CanvasPaintState, Color, CompositionOp, DrawOptions, ExtendMode, Filter,
    GenericDrawTarget, GenericPathBuilder, GradientStop, GradientStops, Path, Pattern,
    SourceSurface, StrokeOptions, SurfaceFormat,
};
use crate::canvas_paint_thread::AntialiasMode;
use canvas_traits::canvas::*;
use cssparser::RGBA;
use euclid::default::{Point2D, Rect, Size2D, Transform2D, Vector2D};
use std::marker::PhantomData;

pub struct RaqoteBackend;

impl Backend for RaqoteBackend {
    fn get_composition_op(&self, _opts: &DrawOptions) -> CompositionOp {
        unimplemented!()
    }

    fn need_to_draw_shadow(&self, _color: &Color) -> bool {
        unimplemented!()
    }

    fn size_from_pattern(&self, _rect: &Rect<f32>, _pattern: &Pattern) -> Option<Size2D<f32>> {
        unimplemented!()
    }

    fn set_shadow_color<'a>(&mut self, _color: RGBA, _state: &mut CanvasPaintState<'a>) {
        unimplemented!()
    }

    fn set_fill_style<'a>(
        &mut self,
        _style: FillOrStrokeStyle,
        _state: &mut CanvasPaintState<'a>,
        _drawtarget: &dyn GenericDrawTarget,
    ) {
        unimplemented!()
    }

    fn set_stroke_style<'a>(
        &mut self,
        _style: FillOrStrokeStyle,
        _state: &mut CanvasPaintState<'a>,
        _drawtarget: &dyn GenericDrawTarget,
    ) {
        unimplemented!()
    }

    fn set_global_composition<'a>(
        &mut self,
        _op: CompositionOrBlending,
        _state: &mut CanvasPaintState<'a>,
    ) {
        unimplemented!()
    }

    fn create_drawtarget(&self, size: Size2D<u64>) -> Box<dyn GenericDrawTarget> {
        Box::new(raqote::DrawTarget::new(
            size.width as i32,
            size.height as i32,
        ))
    }

    fn recreate_paint_state<'a>(&self, _state: &CanvasPaintState<'a>) -> CanvasPaintState<'a> {
        CanvasPaintState::new(AntialiasMode::Default)
    }
}

impl<'a> CanvasPaintState<'a> {
    pub fn new(_antialias: AntialiasMode) -> CanvasPaintState<'a> {
        CanvasPaintState {
            draw_options: DrawOptions::Raqote(raqote::DrawOptions::new()),
            fill_style: Pattern::Raqote(()),
            stroke_style: Pattern::Raqote(()),
            stroke_opts: StrokeOptions::Raqote(Default::default(), PhantomData),
            transform: Transform2D::identity(),
            shadow_offset_x: 0.0,
            shadow_offset_y: 0.0,
            shadow_blur: 0.0,
            shadow_color: Color::Raqote(()),
        }
    }
}

impl Pattern {
    pub fn is_zero_size_gradient(&self) -> bool {
        match *self {
            Pattern::Raqote(()) => unimplemented!(),
        }
    }
}

impl<'a> StrokeOptions<'a> {
    pub fn set_line_width(&mut self, _val: f32) {
        match self {
            StrokeOptions::Raqote(options, _) => options.width = _val,
        }
    }
    pub fn set_miter_limit(&mut self, _val: f32) {
        match self {
            StrokeOptions::Raqote(options, _) => options.miter_limit = _val,
        }
    }
    pub fn set_line_join(&mut self, _val: LineJoinStyle) {
        match self {
            StrokeOptions::Raqote(options, _) => options.join = _val.to_raqote_style(),
        }
    }
    pub fn set_line_cap(&mut self, _val: LineCapStyle) {
        match self {
            StrokeOptions::Raqote(options, _) => options.cap = _val.to_raqote_style(),
        }
    }
}

impl DrawOptions {
    pub fn set_alpha(&mut self, _val: f32) {
        match self {
            DrawOptions::Raqote(draw_options) => draw_options.alpha = _val,
        }
    }
}

impl Path {
    pub fn transformed_copy_to_builder(
        &self,
        _transform: &Transform2D<f32>,
    ) -> Box<dyn GenericPathBuilder> {
        unimplemented!()
    }

    pub fn contains_point(&self, _x: f64, _y: f64, _path_transform: &Transform2D<f32>) -> bool {
        unimplemented!()
    }

    pub fn copy_to_builder(&self) -> Box<dyn GenericPathBuilder> {
        unimplemented!()
    }
}

impl GenericDrawTarget for raqote::DrawTarget {
    fn clear_rect(&self, _rect: &Rect<f32>) {
        unimplemented!()
    }

    fn copy_surface(
        &self,
        _surface: SourceSurface,
        _source: Rect<i32>,
        _destination: Point2D<i32>,
    ) {
        unimplemented!()
    }

    fn create_gradient_stops(
        &self,
        _gradient_stops: Vec<GradientStop>,
        _extend_mode: ExtendMode,
    ) -> GradientStops {
        unimplemented!()
    }

    fn create_path_builder(&self) -> Box<dyn GenericPathBuilder> {
        unimplemented!()
    }

    fn create_similar_draw_target(
        &self,
        _size: &Size2D<i32>,
        _format: SurfaceFormat,
    ) -> Box<dyn GenericDrawTarget> {
        unimplemented!()
    }
    fn create_source_surface_from_data(
        &self,
        _data: &[u8],
        _size: Size2D<i32>,
        _stride: i32,
    ) -> Option<SourceSurface> {
        unimplemented!()
    }
    fn draw_surface(
        &self,
        _surface: SourceSurface,
        _dest: Rect<f64>,
        _source: Rect<f64>,
        _filter: Filter,
        _draw_options: &DrawOptions,
    ) {
        unimplemented!()
    }
    fn draw_surface_with_shadow(
        &self,
        _surface: SourceSurface,
        _dest: &Point2D<f32>,
        _color: &Color,
        _offset: &Vector2D<f32>,
        _sigma: f32,
        _operator: CompositionOp,
    ) {
        unimplemented!()
    }
    fn fill(&self, _path: &Path, _pattern: Pattern, _draw_options: &DrawOptions) {
        unimplemented!()
    }
    fn fill_rect(&self, _rect: &Rect<f32>, _pattern: Pattern, _draw_options: Option<&DrawOptions>) {
        unimplemented!()
    }
    fn get_format(&self) -> SurfaceFormat {
        unimplemented!()
    }
    fn get_size(&self) -> Size2D<i32> {
        unimplemented!()
    }
    fn get_transform(&self) -> Transform2D<f32> {
        unimplemented!()
    }
    fn pop_clip(&self) {
        unimplemented!()
    }
    fn push_clip(&self, _path: &Path) {
        unimplemented!()
    }
    fn set_transform(&self, _matrix: &Transform2D<f32>) {
        unimplemented!()
    }
    fn snapshot(&self) -> SourceSurface {
        unimplemented!()
    }
    fn stroke(
        &self,
        _path: &Path,
        _pattern: Pattern,
        _stroke_options: &StrokeOptions,
        _draw_options: &DrawOptions,
    ) {
        unimplemented!()
    }
    fn stroke_line(
        &self,
        _start: Point2D<f32>,
        _end: Point2D<f32>,
        _pattern: Pattern,
        _stroke_options: &StrokeOptions,
        _draw_options: &DrawOptions,
    ) {
        unimplemented!()
    }
    fn stroke_rect(
        &self,
        _rect: &Rect<f32>,
        _pattern: Pattern,
        _stroke_options: &StrokeOptions<'_>,
        _draw_options: &DrawOptions,
    ) {
        unimplemented!()
    }

    fn snapshot_data(&self, _f: &dyn Fn(&[u8]) -> Vec<u8>) -> Vec<u8> {
        unimplemented!()
    }

    fn snapshot_data_owned(&self) -> Vec<u8> {
        unimplemented!()
    }
}

impl GenericPathBuilder for raqote::PathBuilder {
    fn arc(
        &mut self,
        origin: Point2D<f32>,
        radius: f32,
        start_angle: f32,
        end_angle: f32,
        anticlockwise: bool,
    ) {
        self.arc(origin.x, origin.y, radius, start_angle, end_angle);
    }
    fn bezier_curve_to(
        &mut self,
        control_point1: &Point2D<f32>,
        control_point2: &Point2D<f32>,
        control_point3: &Point2D<f32>,
    ) {
        self.cubic_to(
            control_point1.x,
            control_point1.y,
            control_point2.x,
            control_point2.y,
            control_point3.x,
            control_point3.y,
        );
    }
    fn close(&mut self) {
        self.close();
    }
    fn ellipse(
        &mut self,
        origin: Point2D<f32>,
        radius_x: f32,
        radius_y: f32,
        rotation_angle: f32,
        start_angle: f32,
        end_angle: f32,
        anticlockwise: bool,
    ) {
        unimplemented!();
    }
    fn get_current_point(&mut self) -> Point2D<f32> {
        unimplemented!();
    }
    fn line_to(&mut self, point: Point2D<f32>) {
        self.line_to(point.x, point.y);
    }
    fn move_to(&mut self, point: Point2D<f32>) {
        self.move_to(point.x, point.y);
    }
    fn quadratic_curve_to(&mut self, control_point: &Point2D<f32>, end_point: &Point2D<f32>) {
        self.quad_to(control_point.x, control_point.y, end_point.x, end_point.y);
    }
    fn finish(&mut self) -> Path {
        self.finish()
    }
}

pub trait ToRaqoteStyle {
    type Target;

    fn to_raqote_style(self) -> Self::Target;
}

impl ToRaqoteStyle for LineJoinStyle {
    type Target = raqote::LineJoin;

    fn to_raqote_style(self) -> raqote::LineJoin {
        match self {
            LineJoinStyle::Round => raqote::LineJoin::Round,
            LineJoinStyle::Bevel => raqote::LineJoin::Bevel,
            LineJoinStyle::Miter => raqote::LineJoin::Miter,
        }
    }
}

impl ToRaqoteStyle for LineCapStyle {
    type Target = raqote::LineCap;

    fn to_raqote_style(self) -> raqote::LineCap {
        match self {
            LineCapStyle::Butt => raqote::LineCap::Butt,
            LineCapStyle::Round => raqote::LineCap::Round,
            LineCapStyle::Square => raqote::LineCap::Square,
        }
    }
}
<|endoftext|>


<commit_before>use std::hashmap::HashMap;
use super::*;

pub fn builtins() -> HashMap<Ident, @Value> {
    let mut h = HashMap::new();

    macro_rules! rust(
        (macro, $name:ident) => (
            @ExternMacro(RustFn(|params, env| $name(params, env)))
        );
        (fn, $name:ident) => (
            @ExternFn(RustFn(|params, env| $name(params, env)))
        );
    );

    // special forms
    h.insert(~"def", rust!(macro, builtin_def));
    h.insert(~"if",  rust!(macro, builtin_if));
    h.insert(~"do", rust!(macro, builtin_do));
    h.insert(~"fn", rust!(macro, builtin_fn));
    h.insert(~"macro", rust!(macro, builtin_macro));
    // Return an expression without evaluating it
    h.insert(~"quote", @Macro(~[~"a"], @Symbol(~"a")));
    h.insert(~"quasiquote", rust!(macro, builtin_quasiquote));

    // builtin functions
    h.insert(~"eval", rust!(fn, builtin_eval));
    h.insert(~"parse", rust!(fn, builtin_parse));
    h.insert(~"list", rust!(fn, builtin_list));
    h.insert(~"print", rust!(fn, builtin_print));

    h
}

/// Define a new symbol in the environment
fn builtin_def(params: &[@Value], env: @mut Rusp) -> EvalResult {
    match params {
        [@Symbol(ref id), .. rest] => {
            match rest {
                [] => {
                    env.define(id.clone(), @List(~[]));
                    Ok(@List(~[]))
                }
                [ref v] => {
                    env.eval(*v).chain(|res| env.define(id.clone(), res))
                }
                _ => Err(~"`def` expects 1 or 2 arguments")
            }
        }
        _ => Err(~"first argument to `def` should be an identifier")
    }
}

/// Evaluate an S-expression in the current environment
fn builtin_eval(params: &[@Value], env: @mut Rusp) -> EvalResult {
    match params {
        [ref p] => env.eval(*p),
        _ => Err(~"`eval` expects 1 argument")
    }
}

/// Parse S-expressions from a string
fn builtin_parse(params: &[@Value], _: @mut Rusp) -> EvalResult {
    match params {
        [@Str(ref s)] => match parse(*s) {
            Ok(vals) => Ok(@List(vals)),
            Err(parser::ParseFailure { description, _  }) => Err(description)
        },
        _ => Err(~"`parse` expects 1 argument")
    }
}

/// Conditional expression
fn builtin_if(params: &[@Value], env: @mut Rusp) -> EvalResult {
    match params {
        [ref pred, ref conseq, ref alt] => {
            do env.eval(*pred).chain |val| {
                match *val {
                    Bool(true) => env.eval(*conseq),
                    Bool(false) => env.eval(*alt),
                    _ => Err(fmt!("Expected boolean expression, found: %s", val.to_str())),
                }
            }
        }
        _ => Err(~"`if` expects 3 arguments"), // TODO
    }
}

/// Evaluate each expression in turn, returning the value of the last expression
fn builtin_do(params: &[@Value], env: @mut Rusp) -> EvalResult {
    match params {
        [..fst, ref lst] => {
            for fst.each |val| {
                match env.eval(*val) {
                    Ok(@List(ref l)) if l.is_empty() => (),
                    Ok(v) => return Err(fmt!("Expected unit expression, found: %s", v.to_str())),
                    Err(e) => return Err(e),
                }
            }
            env.eval(*lst)
        }
        _ => Err(~""), // TODO
    }
}

/// Return the arguments as a list
fn builtin_list(params: &[@Value], _env: @mut Rusp) -> EvalResult {
    Ok(@List(params.to_owned()))
}

/// Print to stdout
fn builtin_print(params: &[@Value], _env: @mut Rusp) -> EvalResult {
    let elements = params.map(|v| v.to_str());
    println(str::connect(elements, " "));
    Ok(@List(~[]))
}

/// Evaluate to an anonymous function
fn builtin_fn(params: &[@Value], _: @mut Rusp) -> EvalResult {
    match params {
        [@List(ref symbols), ref val] => {
            let mut idents = ~[];
            for symbols.each |symbol| {
                match **symbol {
                    Symbol(ref ident) => idents.push(ident.clone()),
                    _ => return Err(fmt!("Expected symbol identifier, found: \
                                          %s", symbol.to_str())),
                }
            };
            Ok(@Fn(idents, *val))
        }
        _ => Err(~"`fn` expects 2 arguments"), // TODO
    }
}

/// Evaluate to an anonymous macro
fn builtin_macro(params: &[@Value], _: @mut Rusp) -> EvalResult {
    match params {
        [@List(ref symbols), ref val] => {
            let mut idents = ~[];
            for symbols.each |symbol| {
                match **symbol {
                    Symbol(ref ident) => idents.push(ident.clone()),
                    _ => return Err(fmt!("Expected symbol identifier, found: \
                                          %s", symbol.to_str())),
                }
            };
            Ok(@Macro(idents, *val))
        }
        _ => Err(~"`fn` expects 2 arguments"), // TODO
    }
}

/// Quasiquotation, to allow substitutions inside a quoted structure, e.g.
/// `(def a 1) (quasiquote (a (unquote (list a a a))))`
/// expands to (a (1 1 1))
fn builtin_quasiquote(params: &[@Value], env: @mut Rusp) -> EvalResult {
    return match params {
        [ref p] => unquote(*p, env),
        _ => Err(~"`quasiquote` expects 1 argument")
    };

    // traverse the tree, checking for `(unquote ..)`
    fn unquote(v: @Value, env: @mut Rusp) -> EvalResult {
        match *v {
            List([@Symbol(~"unquote"), .. rest]) => {
                match rest {
                    [ref p] => env.eval(*p),
                    _ => Err(~"`unquote` expects 1 argument")
                }
            }
            List(ref vals) => {
                let mut new = ~[];

                for vals.each |v| {
                    match unquote(*v, env) {
                        Ok(v) => new.push(v),
                        Err(e) => return Err(e)
                    }
                }
                Ok(@List(new))
            }
            Fn(ref args, ref body) => {
                match unquote(*body, env) {
                    Ok(b) => Ok(@Fn(args.clone(), b)),
                    Err(e) => Err(e)
                }
            }
            Macro(ref args, ref body) => {
                match unquote(*body, env) {
                    Ok(b) => Ok(@Macro(args.clone(), b)),
                    Err(e) => Err(e)
                }
            }
            _ => Ok(v)
        }
    }
}<commit_msg>Add basic arithmetic ops and type predicates<commit_after>use std::hashmap::HashMap;
use super::*;

pub fn builtins() -> HashMap<Ident, @Value> {
    let mut h = HashMap::new();

    macro_rules! rust(
        (macro, $name:ident) => (
            @ExternMacro(RustFn(|params, env| $name(params, env)))
        );
        (fn, $name:ident) => (
            @ExternFn(RustFn(|params, env| $name(params, env)))
        );
    );

    // special forms
    h.insert(~"def",                    rust!(macro, builtin_def));
    h.insert(~"if",                     rust!(macro, builtin_if));
    h.insert(~"do",                     rust!(macro, builtin_do));
    h.insert(~"fn",                     rust!(macro, builtin_fn));
    h.insert(~"macro",                  rust!(macro, builtin_macro));
    h.insert(~"quote",                  @Macro(~[~"a"], @Symbol(~"a")));
    h.insert(~"quasiquote",             rust!(macro, builtin_quasiquote));

    // builtin functions

    h.insert(~"eval",                   rust!(fn, builtin_eval));
    h.insert(~"parse",                  rust!(fn, builtin_parse));
    h.insert(~"list",                   rust!(fn, builtin_list));
    h.insert(~"print",                  rust!(fn, builtin_print));

    h.insert(~"bool?",                  rust!(fn, builtin_is_bool));
    h.insert(~"int?",                   rust!(fn, builtin_is_int));
    h.insert(~"float?",                 rust!(fn, builtin_is_float));
    h.insert(~"string?",                rust!(fn, builtin_is_string));
    h.insert(~"list?",                  rust!(fn, builtin_is_list));
    h.insert(~"symbol?",                rust!(fn, builtin_is_symbol));
    h.insert(~"fn?",                    rust!(fn, builtin_is_fn));
    h.insert(~"macro?",                 rust!(fn, builtin_is_macro));
    h.insert(~"extern-fn?",             rust!(fn, builtin_is_extern_fn));
    h.insert(~"extern-macro?",          rust!(fn, builtin_is_extern_macro));

    h.insert(~"+",                      rust!(fn, builtin_add));
    h.insert(~"-",                      rust!(fn, builtin_sub));
    h.insert(~"*",                      rust!(fn, builtin_mul));
    h.insert(~"/",                      rust!(fn, builtin_div));
    h.insert(~"%",                      rust!(fn, builtin_rem));

    h
}

/// Define a new symbol in the environment
fn builtin_def(params: &[@Value], env: @mut Rusp) -> EvalResult {
    match params {
        [@Symbol(ref id), .. rest] => {
            match rest {
                [] => {
                    env.define(id.clone(), @List(~[]));
                    Ok(@List(~[]))
                }
                [ref v] => {
                    env.eval(*v).chain(|res| env.define(id.clone(), res))
                }
                _ => Err(~"`def` expects 1 or 2 arguments")
            }
        }
        _ => Err(~"first argument to `def` should be an identifier")
    }
}

/// Evaluate an S-expression in the current environment
fn builtin_eval(params: &[@Value], env: @mut Rusp) -> EvalResult {
    match params {
        [ref p] => env.eval(*p),
        _ => Err(~"`eval` expects 1 argument")
    }
}

/// Parse S-expressions from a string
fn builtin_parse(params: &[@Value], _: @mut Rusp) -> EvalResult {
    match params {
        [@Str(ref s)] => match parse(*s) {
            Ok(vals) => Ok(@List(vals)),
            Err(parser::ParseFailure { description, _  }) => Err(description)
        },
        _ => Err(~"`parse` expects 1 argument")
    }
}

/// Conditional expression
fn builtin_if(params: &[@Value], env: @mut Rusp) -> EvalResult {
    match params {
        [ref pred, ref conseq, ref alt] => {
            do env.eval(*pred).chain |val| {
                match *val {
                    Bool(true) => env.eval(*conseq),
                    Bool(false) => env.eval(*alt),
                    _ => Err(fmt!("Expected boolean expression, found: %s", val.to_str())),
                }
            }
        }
        _ => Err(~"`if` expects 3 arguments"), // TODO
    }
}

/// Evaluate each expression in turn, returning the value of the last expression
fn builtin_do(params: &[@Value], env: @mut Rusp) -> EvalResult {
    match params {
        [..fst, ref lst] => {
            for fst.each |val| {
                match env.eval(*val) {
                    Ok(@List(ref l)) if l.is_empty() => (),
                    Ok(v) => return Err(fmt!("Expected unit expression, found: %s", v.to_str())),
                    Err(e) => return Err(e),
                }
            }
            env.eval(*lst)
        }
        _ => Err(~""), // TODO
    }
}

/// Return the arguments as a list
fn builtin_list(params: &[@Value], _: @mut Rusp) -> EvalResult {
    Ok(@List(params.to_owned()))
}

/// Print to stdout
fn builtin_print(params: &[@Value], _: @mut Rusp) -> EvalResult {
    let elements = params.map(|v| v.to_str());
    println(str::connect(elements, " "));
    Ok(@List(~[]))
}

/// Evaluate to an anonymous function
fn builtin_fn(params: &[@Value], _: @mut Rusp) -> EvalResult {
    match params {
        [@List(ref symbols), ref val] => {
            let mut idents = ~[];
            for symbols.each |symbol| {
                match **symbol {
                    Symbol(ref ident) => idents.push(ident.clone()),
                    _ => return Err(fmt!("Expected symbol identifier, found: \
                                          %s", symbol.to_str())),
                }
            };
            Ok(@Fn(idents, *val))
        }
        _ => Err(~"`fn` expects 2 arguments"), // TODO
    }
}

/// Evaluate to an anonymous macro
fn builtin_macro(params: &[@Value], _: @mut Rusp) -> EvalResult {
    match params {
        [@List(ref symbols), ref val] => {
            let mut idents = ~[];
            for symbols.each |symbol| {
                match **symbol {
                    Symbol(ref ident) => idents.push(ident.clone()),
                    _ => return Err(fmt!("Expected symbol identifier, found: \
                                          %s", symbol.to_str())),
                }
            };
            Ok(@Macro(idents, *val))
        }
        _ => Err(~"`fn` expects 2 arguments"), // TODO
    }
}

/// Quasiquotation, to allow substitutions inside a quoted structure, e.g.
/// `(def a 1) (quasiquote (a (unquote (list a a a))))`
/// expands to (a (1 1 1))
fn builtin_quasiquote(params: &[@Value], env: @mut Rusp) -> EvalResult {
    return match params {
        [ref p] => unquote(*p, env),
        _ => Err(~"`quasiquote` expects 1 argument")
    };

    // traverse the tree, checking for `(unquote ..)`
    fn unquote(v: @Value, env: @mut Rusp) -> EvalResult {
        match *v {
            List([@Symbol(~"unquote"), .. rest]) => {
                match rest {
                    [ref p] => env.eval(*p),
                    _ => Err(~"`unquote` expects 1 argument")
                }
            }
            List(ref vals) => {
                let mut new = ~[];

                for vals.each |v| {
                    match unquote(*v, env) {
                        Ok(v) => new.push(v),
                        Err(e) => return Err(e)
                    }
                }
                Ok(@List(new))
            }
            Fn(ref args, ref body) => {
                match unquote(*body, env) {
                    Ok(b) => Ok(@Fn(args.clone(), b)),
                    Err(e) => Err(e)
                }
            }
            Macro(ref args, ref body) => {
                match unquote(*body, env) {
                    Ok(b) => Ok(@Macro(args.clone(), b)),
                    Err(e) => Err(e)
                }
            }
            _ => Ok(v)
        }
    }
}

macro_rules! type_pred(
    ($name:ident, $pattern:pat) => (
        fn $name(params: &[@Value], _: @mut Rusp) -> EvalResult {
            match do params.map |&val| {
                match *val {
                    $pattern => @Bool(true),
                    _ => @Bool(false),
                }
            } {
                [ref result] => Ok(*result),
                results => Ok(@List(results)),
            }
        }
    )
)

type_pred!(builtin_is_bool, Bool(*))
type_pred!(builtin_is_int, Int(*))
type_pred!(builtin_is_float, Float(*))
type_pred!(builtin_is_string, Str(*))
type_pred!(builtin_is_list, List(*))
type_pred!(builtin_is_symbol, Symbol(*))
type_pred!(builtin_is_fn, Fn(*))
type_pred!(builtin_is_macro, Macro(*))
type_pred!(builtin_is_extern_fn, ExternFn(*))
type_pred!(builtin_is_extern_macro, ExternMacro(*))

macro_rules! arithmetic_op(
    ($name:ident, $symbol:expr, $method:ident) => (
        fn $name(params: &[@Value], env: @mut Rusp) -> EvalResult {
            if params.len() < 2 {
                return Err(fmt!("`%s` expects at least 2 arguments", $symbol));
            }
            let mut result = *params.head();
            for params.tail().each |&val| {
                match (result, env.eval(val)) {
                    // Basic operations between values of the same type
                    (@Int(prev), Ok(@Int(i))) => result = @Int(prev.$method(&i)),
                    (@Float(prev), Ok(@Float(f))) => result = @Float(prev.$method(&f)),
                    // Handle numeric promotions
                    (@Int(prev), Ok(@Float(f))) => result = @Float((prev as float).$method(&f)),
                    (@Float(prev), Ok(@Int(i))) => result = @Float(prev.$method(&(i as float))),
                    // Type errors
                    (@Float(_), Ok(ref v)) => return Err(fmt!("Expected float but found: %s", v.to_str())),
                    (@Int(_), Ok(ref v)) => return Err(fmt!("Expected integer but found: %s", v.to_str())),
                    (ref prev, Ok(_)) => return Err(fmt!("Expected number but found: %s", prev.to_str())),
                    (_, Err(err)) => return Err(err),
                }
            }
            Ok(result)
        }
    )
)

arithmetic_op!(builtin_add, "+", add)
arithmetic_op!(builtin_sub, "-", sub)
arithmetic_op!(builtin_mul, "*", mul)
arithmetic_op!(builtin_div, "/", div)
arithmetic_op!(builtin_rem, "%", rem)

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

    macro_rules! test_ok(
        ($src:expr, $expected:expr) => (
            assert_eq!(Rusp::new().eval(
                @Parser::new($src).parse().get()
            ).get().to_str(), $expected);
        )
    )

    macro_rules! test_err(
        ($src:expr) => (
            assert!(Rusp::new().eval(
                @Parser::new($src).parse().get()
            ).is_err());
        )
    )

    #[test]
    fn test_type_preds() {
        test_ok!("(bool? true)", ~"true");
        test_ok!("(bool? 1)", ~"false");
        test_ok!("(int? 1)", ~"true");
        test_ok!("(int? 1.0)", ~"false");
        test_ok!("(float? 1.0)", ~"true");
        test_ok!("(float? \"hi\")", ~"false");
        test_ok!("(string? \"hi\")", ~"true");
        test_ok!("(string? (list 1 2))", ~"false");
        test_ok!("(list? (list 1 2))", ~"true");
        test_ok!("(list? (list))", ~"true");
        test_ok!("(list? 1.0)", ~"false");
        test_ok!("(symbol? (quote x))", ~"true");
        test_ok!("(symbol? (fn () 1))", ~"false");
        test_ok!("(fn? (fn () 1))", ~"true");
        test_ok!("(fn? (macro () 1))", ~"false");
        test_ok!("(macro? (macro () 1))", ~"true");
        test_ok!("(macro? false)", ~"false");
    }

    #[test]
    fn test_arithmetic() {
        test_ok!("(+ 1 2)", ~"3");
        test_ok!("(+ 1 2 4)", ~"7");
        test_ok!("(+ 1.5 3 4)", ~"8.5");
        test_ok!("(+ 3 1.67)", ~"4.67");
        test_ok!("(- 3 0.5)", ~"2.5");
        test_ok!("(- 3 1.5 (+ 2 4))", ~"-4.5");

        test_err!("(+)");
        test_err!("(-)");
        test_err!("(*)");
        test_err!("(/)");
        test_err!("(%)");

        test_err!("(+ 1)");
        test_err!("(- 1)");
        test_err!("(* 1)");
        test_err!("(/ 1)");
        test_err!("(% 1)");

        test_err!("(+ 1 \"hi\")");
        test_err!("(- 1 \"hi\")");
        test_err!("(* 1 \"hi\")");
        test_err!("(/ 1 \"hi\")");
        test_err!("(% 1 \"hi\")");

        test_err!("(+ \"hi\" 1)");
        test_err!("(- \"hi\" 1)");
        test_err!("(* \"hi\" 1)");
        test_err!("(/ \"hi\" 1)");
        test_err!("(% \"hi\" 1)");
    }
}<|endoftext|>


<commit_before>// ignore-tidy-undocumented-unsafe

use crate::cmp;
use crate::fmt;
use crate::mem;
use crate::num::NonZeroUsize;
use crate::ptr::NonNull;

const fn size_align<T>() -> (usize, usize) {
    (mem::size_of::<T>(), mem::align_of::<T>())
}

/// Layout of a block of memory.
///
/// An instance of `Layout` describes a particular layout of memory.
/// You build a `Layout` up as an input to give to an allocator.
///
/// All layouts have an associated size and a power-of-two alignment.
///
/// (Note that layouts are *not* required to have non-zero size,
/// even though `GlobalAlloc` requires that all memory requests
/// be non-zero in size. A caller must either ensure that conditions
/// like this are met, use specific allocators with looser
/// requirements, or use the more lenient `AllocRef` interface.)
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[lang = "alloc_layout"]
pub struct Layout {
    // size of the requested block of memory, measured in bytes.
    size_: usize,

    // alignment of the requested block of memory, measured in bytes.
    // we ensure that this is always a power-of-two, because API's
    // like `posix_memalign` require it and it is a reasonable
    // constraint to impose on Layout constructors.
    //
    // (However, we do not analogously require `align >= sizeof(void*)`,
    //  even though that is *also* a requirement of `posix_memalign`.)
    align_: NonZeroUsize,
}

impl Layout {
    /// Constructs a `Layout` from a given `size` and `align`,
    /// or returns `LayoutErr` if any of the following conditions
    /// are not met:
    ///
    /// * `align` must not be zero,
    ///
    /// * `align` must be a power of two,
    ///
    /// * `size`, when rounded up to the nearest multiple of `align`,
    ///    must not overflow (i.e., the rounded value must be less than
    ///    or equal to `usize::MAX`).
    #[stable(feature = "alloc_layout", since = "1.28.0")]
    #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
    #[inline]
    pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutErr> {
        if !align.is_power_of_two() {
            return Err(LayoutErr { private: () });
        }

        // (power-of-two implies align != 0.)

        // Rounded up size is:
        //   size_rounded_up = (size + align - 1) & !(align - 1);
        //
        // We know from above that align != 0. If adding (align - 1)
        // does not overflow, then rounding up will be fine.
        //
        // Conversely, &-masking with !(align - 1) will subtract off
        // only low-order-bits. Thus if overflow occurs with the sum,
        // the &-mask cannot subtract enough to undo that overflow.
        //
        // Above implies that checking for summation overflow is both
        // necessary and sufficient.
        if size > usize::MAX - (align - 1) {
            return Err(LayoutErr { private: () });
        }

        unsafe { Ok(Layout::from_size_align_unchecked(size, align)) }
    }

    /// Creates a layout, bypassing all checks.
    ///
    /// # Safety
    ///
    /// This function is unsafe as it does not verify the preconditions from
    /// [`Layout::from_size_align`](#method.from_size_align).
    #[stable(feature = "alloc_layout", since = "1.28.0")]
    #[rustc_const_stable(feature = "alloc_layout", since = "1.28.0")]
    #[inline]
    pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
        Layout { size_: size, align_: NonZeroUsize::new_unchecked(align) }
    }

    /// The minimum size in bytes for a memory block of this layout.
    #[stable(feature = "alloc_layout", since = "1.28.0")]
    #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
    #[inline]
    pub const fn size(&self) -> usize {
        self.size_
    }

    /// The minimum byte alignment for a memory block of this layout.
    #[stable(feature = "alloc_layout", since = "1.28.0")]
    #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
    #[inline]
    pub const fn align(&self) -> usize {
        self.align_.get()
    }

    /// Constructs a `Layout` suitable for holding a value of type `T`.
    #[stable(feature = "alloc_layout", since = "1.28.0")]
    #[rustc_const_stable(feature = "alloc_layout_const_new", since = "1.42.0")]
    #[inline]
    pub const fn new<T>() -> Self {
        let (size, align) = size_align::<T>();
        // Note that the align is guaranteed by rustc to be a power of two and
        // the size+align combo is guaranteed to fit in our address space. As a
        // result use the unchecked constructor here to avoid inserting code
        // that panics if it isn't optimized well enough.
        unsafe { Layout::from_size_align_unchecked(size, align) }
    }

    /// Produces layout describing a record that could be used to
    /// allocate backing structure for `T` (which could be a trait
    /// or other unsized type like a slice).
    #[stable(feature = "alloc_layout", since = "1.28.0")]
    #[inline]
    pub fn for_value<T: ?Sized>(t: &T) -> Self {
        let (size, align) = (mem::size_of_val(t), mem::align_of_val(t));
        // See rationale in `new` for why this is using an unsafe variant below
        debug_assert!(Layout::from_size_align(size, align).is_ok());
        unsafe { Layout::from_size_align_unchecked(size, align) }
    }

    /// Creates a `NonNull` that is dangling, but well-aligned for this Layout.
    ///
    /// Note that the pointer value may potentially represent a valid pointer,
    /// which means this must not be used as a "not yet initialized"
    /// sentinel value. Types that lazily allocate must track initialization by
    /// some other means.
    #[unstable(feature = "alloc_layout_extra", issue = "55724")]
    #[inline]
    pub const fn dangling(&self) -> NonNull<u8> {
        // align is non-zero and a power of two
        unsafe { NonNull::new_unchecked(self.align() as *mut u8) }
    }

    /// Creates a layout describing the record that can hold a value
    /// of the same layout as `self`, but that also is aligned to
    /// alignment `align` (measured in bytes).
    ///
    /// If `self` already meets the prescribed alignment, then returns
    /// `self`.
    ///
    /// Note that this method does not add any padding to the overall
    /// size, regardless of whether the returned layout has a different
    /// alignment. In other words, if `K` has size 16, `K.align_to(32)`
    /// will *still* have size 16.
    ///
    /// Returns an error if the combination of `self.size()` and the given
    /// `align` violates the conditions listed in
    /// [`Layout::from_size_align`](#method.from_size_align).
    #[unstable(feature = "alloc_layout_extra", issue = "55724")]
    #[inline]
    pub fn align_to(&self, align: usize) -> Result<Self, LayoutErr> {
        Layout::from_size_align(self.size(), cmp::max(self.align(), align))
    }

    /// Returns the amount of padding we must insert after `self`
    /// to ensure that the following address will satisfy `align`
    /// (measured in bytes).
    ///
    /// e.g., if `self.size()` is 9, then `self.padding_needed_for(4)`
    /// returns 3, because that is the minimum number of bytes of
    /// padding required to get a 4-aligned address (assuming that the
    /// corresponding memory block starts at a 4-aligned address).
    ///
    /// The return value of this function has no meaning if `align` is
    /// not a power-of-two.
    ///
    /// Note that the utility of the returned value requires `align`
    /// to be less than or equal to the alignment of the starting
    /// address for the whole allocated block of memory. One way to
    /// satisfy this constraint is to ensure `align <= self.align()`.
    #[unstable(feature = "alloc_layout_extra", issue = "55724")]
    #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
    #[inline]
    pub const fn padding_needed_for(&self, align: usize) -> usize {
        let len = self.size();

        // Rounded up value is:
        //   len_rounded_up = (len + align - 1) & !(align - 1);
        // and then we return the padding difference: `len_rounded_up - len`.
        //
        // We use modular arithmetic throughout:
        //
        // 1. align is guaranteed to be > 0, so align - 1 is always
        //    valid.
        //
        // 2. `len + align - 1` can overflow by at most `align - 1`,
        //    so the &-mask with `!(align - 1)` will ensure that in the
        //    case of overflow, `len_rounded_up` will itself be 0.
        //    Thus the returned padding, when added to `len`, yields 0,
        //    which trivially satisfies the alignment `align`.
        //
        // (Of course, attempts to allocate blocks of memory whose
        // size and padding overflow in the above manner should cause
        // the allocator to yield an error anyway.)

        let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);
        len_rounded_up.wrapping_sub(len)
    }

    /// Creates a layout by rounding the size of this layout up to a multiple
    /// of the layout's alignment.
    ///
    /// This is equivalent to adding the result of `padding_needed_for`
    /// to the layout's current size.
    #[unstable(feature = "alloc_layout_extra", issue = "55724")]
    #[inline]
    pub fn pad_to_align(&self) -> Layout {
        let pad = self.padding_needed_for(self.align());
        // This cannot overflow. Quoting from the invariant of Layout:
        // > `size`, when rounded up to the nearest multiple of `align`,
        // > must not overflow (i.e., the rounded value must be less than
        // > `usize::MAX`)
        let new_size = self.size() + pad;

        Layout::from_size_align(new_size, self.align()).unwrap()
    }

    /// Creates a layout describing the record for `n` instances of
    /// `self`, with a suitable amount of padding between each to
    /// ensure that each instance is given its requested size and
    /// alignment. On success, returns `(k, offs)` where `k` is the
    /// layout of the array and `offs` is the distance between the start
    /// of each element in the array.
    ///
    /// On arithmetic overflow, returns `LayoutErr`.
    #[unstable(feature = "alloc_layout_extra", issue = "55724")]
    #[inline]
    pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> {
        // This cannot overflow. Quoting from the invariant of Layout:
        // > `size`, when rounded up to the nearest multiple of `align`,
        // > must not overflow (i.e., the rounded value must be less than
        // > `usize::MAX`)
        let padded_size = self.size() + self.padding_needed_for(self.align());
        let alloc_size = padded_size.checked_mul(n).ok_or(LayoutErr { private: () })?;

        unsafe {
            // self.align is already known to be valid and alloc_size has been
            // padded already.
            Ok((Layout::from_size_align_unchecked(alloc_size, self.align()), padded_size))
        }
    }

    /// Creates a layout describing the record for `self` followed by
    /// `next`, including any necessary padding to ensure that `next`
    /// will be properly aligned. Note that the resulting layout will
    /// satisfy the alignment properties of both `self` and `next`.
    ///
    /// The resulting layout will be the same as that of a C struct containing
    /// two fields with the layouts of `self` and `next`, in that order.
    ///
    /// Returns `Some((k, offset))`, where `k` is layout of the concatenated
    /// record and `offset` is the relative location, in bytes, of the
    /// start of the `next` embedded within the concatenated record
    /// (assuming that the record itself starts at offset 0).
    ///
    /// On arithmetic overflow, returns `LayoutErr`.
    #[unstable(feature = "alloc_layout_extra", issue = "55724")]
    #[inline]
    pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutErr> {
        let new_align = cmp::max(self.align(), next.align());
        let pad = self.padding_needed_for(next.align());

        let offset = self.size().checked_add(pad).ok_or(LayoutErr { private: () })?;
        let new_size = offset.checked_add(next.size()).ok_or(LayoutErr { private: () })?;

        let layout = Layout::from_size_align(new_size, new_align)?;
        Ok((layout, offset))
    }

    /// Creates a layout describing the record for `n` instances of
    /// `self`, with no padding between each instance.
    ///
    /// Note that, unlike `repeat`, `repeat_packed` does not guarantee
    /// that the repeated instances of `self` will be properly
    /// aligned, even if a given instance of `self` is properly
    /// aligned. In other words, if the layout returned by
    /// `repeat_packed` is used to allocate an array, it is not
    /// guaranteed that all elements in the array will be properly
    /// aligned.
    ///
    /// On arithmetic overflow, returns `LayoutErr`.
    #[unstable(feature = "alloc_layout_extra", issue = "55724")]
    #[inline]
    pub fn repeat_packed(&self, n: usize) -> Result<Self, LayoutErr> {
        let size = self.size().checked_mul(n).ok_or(LayoutErr { private: () })?;
        Layout::from_size_align(size, self.align())
    }

    /// Creates a layout describing the record for `self` followed by
    /// `next` with no additional padding between the two. Since no
    /// padding is inserted, the alignment of `next` is irrelevant,
    /// and is not incorporated *at all* into the resulting layout.
    ///
    /// On arithmetic overflow, returns `LayoutErr`.
    #[unstable(feature = "alloc_layout_extra", issue = "55724")]
    #[inline]
    pub fn extend_packed(&self, next: Self) -> Result<Self, LayoutErr> {
        let new_size = self.size().checked_add(next.size()).ok_or(LayoutErr { private: () })?;
        Layout::from_size_align(new_size, self.align())
    }

    /// Creates a layout describing the record for a `[T; n]`.
    ///
    /// On arithmetic overflow, returns `LayoutErr`.
    #[unstable(feature = "alloc_layout_extra", issue = "55724")]
    #[inline]
    pub fn array<T>(n: usize) -> Result<Self, LayoutErr> {
        Layout::new::<T>().repeat(n).map(|(k, offs)| {
            debug_assert!(offs == mem::size_of::<T>());
            k
        })
    }
}

/// The parameters given to `Layout::from_size_align`
/// or some other `Layout` constructor
/// do not satisfy its documented constraints.
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct LayoutErr {
    private: (),
}

// (we need this for downstream impl of trait Error)
#[stable(feature = "alloc_layout", since = "1.28.0")]
impl fmt::Display for LayoutErr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("invalid parameters to Layout::from_size_align")
    }
}
<commit_msg>Stabilize some of alloc_layout_extras<commit_after>// ignore-tidy-undocumented-unsafe

use crate::cmp;
use crate::fmt;
use crate::mem;
use crate::num::NonZeroUsize;
use crate::ptr::NonNull;

const fn size_align<T>() -> (usize, usize) {
    (mem::size_of::<T>(), mem::align_of::<T>())
}

/// Layout of a block of memory.
///
/// An instance of `Layout` describes a particular layout of memory.
/// You build a `Layout` up as an input to give to an allocator.
///
/// All layouts have an associated size and a power-of-two alignment.
///
/// (Note that layouts are *not* required to have non-zero size,
/// even though `GlobalAlloc` requires that all memory requests
/// be non-zero in size. A caller must either ensure that conditions
/// like this are met, use specific allocators with looser
/// requirements, or use the more lenient `AllocRef` interface.)
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[lang = "alloc_layout"]
pub struct Layout {
    // size of the requested block of memory, measured in bytes.
    size_: usize,

    // alignment of the requested block of memory, measured in bytes.
    // we ensure that this is always a power-of-two, because API's
    // like `posix_memalign` require it and it is a reasonable
    // constraint to impose on Layout constructors.
    //
    // (However, we do not analogously require `align >= sizeof(void*)`,
    //  even though that is *also* a requirement of `posix_memalign`.)
    align_: NonZeroUsize,
}

impl Layout {
    /// Constructs a `Layout` from a given `size` and `align`,
    /// or returns `LayoutErr` if any of the following conditions
    /// are not met:
    ///
    /// * `align` must not be zero,
    ///
    /// * `align` must be a power of two,
    ///
    /// * `size`, when rounded up to the nearest multiple of `align`,
    ///    must not overflow (i.e., the rounded value must be less than
    ///    or equal to `usize::MAX`).
    #[stable(feature = "alloc_layout", since = "1.28.0")]
    #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
    #[inline]
    pub const fn from_size_align(size: usize, align: usize) -> Result<Self, LayoutErr> {
        if !align.is_power_of_two() {
            return Err(LayoutErr { private: () });
        }

        // (power-of-two implies align != 0.)

        // Rounded up size is:
        //   size_rounded_up = (size + align - 1) & !(align - 1);
        //
        // We know from above that align != 0. If adding (align - 1)
        // does not overflow, then rounding up will be fine.
        //
        // Conversely, &-masking with !(align - 1) will subtract off
        // only low-order-bits. Thus if overflow occurs with the sum,
        // the &-mask cannot subtract enough to undo that overflow.
        //
        // Above implies that checking for summation overflow is both
        // necessary and sufficient.
        if size > usize::MAX - (align - 1) {
            return Err(LayoutErr { private: () });
        }

        unsafe { Ok(Layout::from_size_align_unchecked(size, align)) }
    }

    /// Creates a layout, bypassing all checks.
    ///
    /// # Safety
    ///
    /// This function is unsafe as it does not verify the preconditions from
    /// [`Layout::from_size_align`](#method.from_size_align).
    #[stable(feature = "alloc_layout", since = "1.28.0")]
    #[rustc_const_stable(feature = "alloc_layout", since = "1.28.0")]
    #[inline]
    pub const unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self {
        Layout { size_: size, align_: NonZeroUsize::new_unchecked(align) }
    }

    /// The minimum size in bytes for a memory block of this layout.
    #[stable(feature = "alloc_layout", since = "1.28.0")]
    #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
    #[inline]
    pub const fn size(&self) -> usize {
        self.size_
    }

    /// The minimum byte alignment for a memory block of this layout.
    #[stable(feature = "alloc_layout", since = "1.28.0")]
    #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
    #[inline]
    pub const fn align(&self) -> usize {
        self.align_.get()
    }

    /// Constructs a `Layout` suitable for holding a value of type `T`.
    #[stable(feature = "alloc_layout", since = "1.28.0")]
    #[rustc_const_stable(feature = "alloc_layout_const_new", since = "1.42.0")]
    #[inline]
    pub const fn new<T>() -> Self {
        let (size, align) = size_align::<T>();
        // Note that the align is guaranteed by rustc to be a power of two and
        // the size+align combo is guaranteed to fit in our address space. As a
        // result use the unchecked constructor here to avoid inserting code
        // that panics if it isn't optimized well enough.
        unsafe { Layout::from_size_align_unchecked(size, align) }
    }

    /// Produces layout describing a record that could be used to
    /// allocate backing structure for `T` (which could be a trait
    /// or other unsized type like a slice).
    #[stable(feature = "alloc_layout", since = "1.28.0")]
    #[inline]
    pub fn for_value<T: ?Sized>(t: &T) -> Self {
        let (size, align) = (mem::size_of_val(t), mem::align_of_val(t));
        // See rationale in `new` for why this is using an unsafe variant below
        debug_assert!(Layout::from_size_align(size, align).is_ok());
        unsafe { Layout::from_size_align_unchecked(size, align) }
    }

    /// Creates a `NonNull` that is dangling, but well-aligned for this Layout.
    ///
    /// Note that the pointer value may potentially represent a valid pointer,
    /// which means this must not be used as a "not yet initialized"
    /// sentinel value. Types that lazily allocate must track initialization by
    /// some other means.
    #[unstable(feature = "alloc_layout_extra", issue = "55724")]
    #[inline]
    pub const fn dangling(&self) -> NonNull<u8> {
        // align is non-zero and a power of two
        unsafe { NonNull::new_unchecked(self.align() as *mut u8) }
    }

    /// Creates a layout describing the record that can hold a value
    /// of the same layout as `self`, but that also is aligned to
    /// alignment `align` (measured in bytes).
    ///
    /// If `self` already meets the prescribed alignment, then returns
    /// `self`.
    ///
    /// Note that this method does not add any padding to the overall
    /// size, regardless of whether the returned layout has a different
    /// alignment. In other words, if `K` has size 16, `K.align_to(32)`
    /// will *still* have size 16.
    ///
    /// Returns an error if the combination of `self.size()` and the given
    /// `align` violates the conditions listed in
    /// [`Layout::from_size_align`](#method.from_size_align).
    #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
    #[inline]
    pub fn align_to(&self, align: usize) -> Result<Self, LayoutErr> {
        Layout::from_size_align(self.size(), cmp::max(self.align(), align))
    }

    /// Returns the amount of padding we must insert after `self`
    /// to ensure that the following address will satisfy `align`
    /// (measured in bytes).
    ///
    /// e.g., if `self.size()` is 9, then `self.padding_needed_for(4)`
    /// returns 3, because that is the minimum number of bytes of
    /// padding required to get a 4-aligned address (assuming that the
    /// corresponding memory block starts at a 4-aligned address).
    ///
    /// The return value of this function has no meaning if `align` is
    /// not a power-of-two.
    ///
    /// Note that the utility of the returned value requires `align`
    /// to be less than or equal to the alignment of the starting
    /// address for the whole allocated block of memory. One way to
    /// satisfy this constraint is to ensure `align <= self.align()`.
    #[unstable(feature = "alloc_layout_extra", issue = "55724")]
    #[rustc_const_unstable(feature = "const_alloc_layout", issue = "67521")]
    #[inline]
    pub const fn padding_needed_for(&self, align: usize) -> usize {
        let len = self.size();

        // Rounded up value is:
        //   len_rounded_up = (len + align - 1) & !(align - 1);
        // and then we return the padding difference: `len_rounded_up - len`.
        //
        // We use modular arithmetic throughout:
        //
        // 1. align is guaranteed to be > 0, so align - 1 is always
        //    valid.
        //
        // 2. `len + align - 1` can overflow by at most `align - 1`,
        //    so the &-mask with `!(align - 1)` will ensure that in the
        //    case of overflow, `len_rounded_up` will itself be 0.
        //    Thus the returned padding, when added to `len`, yields 0,
        //    which trivially satisfies the alignment `align`.
        //
        // (Of course, attempts to allocate blocks of memory whose
        // size and padding overflow in the above manner should cause
        // the allocator to yield an error anyway.)

        let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);
        len_rounded_up.wrapping_sub(len)
    }

    /// Creates a layout by rounding the size of this layout up to a multiple
    /// of the layout's alignment.
    ///
    /// This is equivalent to adding the result of `padding_needed_for`
    /// to the layout's current size.
    #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
    #[inline]
    pub fn pad_to_align(&self) -> Layout {
        let pad = self.padding_needed_for(self.align());
        // This cannot overflow. Quoting from the invariant of Layout:
        // > `size`, when rounded up to the nearest multiple of `align`,
        // > must not overflow (i.e., the rounded value must be less than
        // > `usize::MAX`)
        let new_size = self.size() + pad;

        Layout::from_size_align(new_size, self.align()).unwrap()
    }

    /// Creates a layout describing the record for `n` instances of
    /// `self`, with a suitable amount of padding between each to
    /// ensure that each instance is given its requested size and
    /// alignment. On success, returns `(k, offs)` where `k` is the
    /// layout of the array and `offs` is the distance between the start
    /// of each element in the array.
    ///
    /// On arithmetic overflow, returns `LayoutErr`.
    #[unstable(feature = "alloc_layout_extra", issue = "55724")]
    #[inline]
    pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> {
        // This cannot overflow. Quoting from the invariant of Layout:
        // > `size`, when rounded up to the nearest multiple of `align`,
        // > must not overflow (i.e., the rounded value must be less than
        // > `usize::MAX`)
        let padded_size = self.size() + self.padding_needed_for(self.align());
        let alloc_size = padded_size.checked_mul(n).ok_or(LayoutErr { private: () })?;

        unsafe {
            // self.align is already known to be valid and alloc_size has been
            // padded already.
            Ok((Layout::from_size_align_unchecked(alloc_size, self.align()), padded_size))
        }
    }

    /// Creates a layout describing the record for `self` followed by
    /// `next`, including any necessary padding to ensure that `next`
    /// will be properly aligned, but no trailing padding. Note that
    /// the resulting layout will satisfy the alignment properties of
    /// both `self` and `next`, in order to ensure field alignment.
    ///
    /// Returns `Ok((k, offset))`, where `k` is layout of the concatenated
    /// record and `offset` is the relative location, in bytes, of the
    /// start of the `next` embedded within the concatenated record
    /// (assuming that the record itself starts at offset 0).
    ///
    /// On arithmetic overflow, returns `LayoutErr`.
    #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
    #[inline]
    pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutErr> {
        let new_align = cmp::max(self.align(), next.align());
        let pad = self.padding_needed_for(next.align());

        let offset = self.size().checked_add(pad).ok_or(LayoutErr { private: () })?;
        let new_size = offset.checked_add(next.size()).ok_or(LayoutErr { private: () })?;

        let layout = Layout::from_size_align(new_size, new_align)?;
        Ok((layout, offset))
    }

    /// Creates a layout describing the record for `n` instances of
    /// `self`, with no padding between each instance.
    ///
    /// Note that, unlike `repeat`, `repeat_packed` does not guarantee
    /// that the repeated instances of `self` will be properly
    /// aligned, even if a given instance of `self` is properly
    /// aligned. In other words, if the layout returned by
    /// `repeat_packed` is used to allocate an array, it is not
    /// guaranteed that all elements in the array will be properly
    /// aligned.
    ///
    /// On arithmetic overflow, returns `LayoutErr`.
    #[unstable(feature = "alloc_layout_extra", issue = "55724")]
    #[inline]
    pub fn repeat_packed(&self, n: usize) -> Result<Self, LayoutErr> {
        let size = self.size().checked_mul(n).ok_or(LayoutErr { private: () })?;
        Layout::from_size_align(size, self.align())
    }

    /// Creates a layout describing the record for `self` followed by
    /// `next` with no additional padding between the two. Since no
    /// padding is inserted, the alignment of `next` is irrelevant,
    /// and is not incorporated *at all* into the resulting layout.
    ///
    /// On arithmetic overflow, returns `LayoutErr`.
    #[unstable(feature = "alloc_layout_extra", issue = "55724")]
    #[inline]
    pub fn extend_packed(&self, next: Self) -> Result<Self, LayoutErr> {
        let new_size = self.size().checked_add(next.size()).ok_or(LayoutErr { private: () })?;
        Layout::from_size_align(new_size, self.align())
    }

    /// Creates a layout describing the record for a `[T; n]`.
    ///
    /// On arithmetic overflow, returns `LayoutErr`.
    #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")]
    #[inline]
    pub fn array<T>(n: usize) -> Result<Self, LayoutErr> {
        let (layout, offset) = Layout::new::<T>().repeat(n)?;
        debug_assert_eq!(offset, mem::size_of::<T>());
        Ok(layout.pad_to_align())
    }
}

/// The parameters given to `Layout::from_size_align`
/// or some other `Layout` constructor
/// do not satisfy its documented constraints.
#[stable(feature = "alloc_layout", since = "1.28.0")]
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct LayoutErr {
    private: (),
}

// (we need this for downstream impl of trait Error)
#[stable(feature = "alloc_layout", since = "1.28.0")]
impl fmt::Display for LayoutErr {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("invalid parameters to Layout::from_size_align")
    }
}
<|endoftext|>