<commit_before>#![recursion_limit="128"]

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

#[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() {
    use futures::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);
}

#[test]
fn select_size() {
    let fut = async {
        let mut ready = future::ready(0i32);
        select! {
            _ = ready => {},
        }
    };
    assert_eq!(::std::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!(::std::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);
}

#[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!(48, std::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);
    });
}

async fn require_mutable(_: &mut i32) {}
async fn async_noop() {}

#[test]
fn select_on_mutable_borrowing_future_with_same_borrow_in_block() {
    block_on(async {
        let mut value = 234;
        select! {
            x = require_mutable(&mut value).fuse() => { },
            y = async_noop().fuse() => {
                value += 5;
            },
        }
    });
}

#[test]
fn select_on_mutable_borrowing_future_with_same_borrow_in_block_and_default() {
    block_on(async {
        let mut value = 234;
        select! {
            x = require_mutable(&mut value).fuse() => { },
            y = async_noop().fuse() => {
                value += 5;
            },
            default => {
                value += 27;
            },
        }
    });
}

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

    let fut = async {
        let ready1 = future::ready(0i32);
        let ready2 = future::ready(0i32);
        join!(ready1, ready2)
    };
    assert_eq!(::std::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!(::std::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!(::std::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>futures: tests/async_await_macros.rs: Guard against failures w/o features<commit_after>#![recursion_limit="128"]

#[cfg(all(feature = "async-await", feature = "std", feature = "executor"))]
#[test]
fn poll_and_pending() {
    use futures::{pending, pin_mut, poll};
    use futures::executor::block_on;
    use futures::task::Poll;

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

#[cfg(all(feature = "async-await", feature = "std", feature = "executor"))]
#[test]
fn join() {
    use futures::{pin_mut, poll, join};
    use futures::channel::oneshot;
    use futures::executor::block_on;
    use futures::task::Poll;

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

#[cfg(all(feature = "async-await", feature = "std", feature = "executor"))]
#[test]
fn select() {
    use futures::select;
    use futures::channel::oneshot;
    use futures::executor::block_on;
    use futures::future::FutureExt;

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

#[cfg(all(feature = "alloc", feature = "executor", feature = "async-await"))]
#[test]
fn select_biased() {
    use futures::channel::oneshot;
    use futures::executor::block_on;
    use futures::future::FutureExt;
    use futures::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);
}

#[cfg(all(feature = "async-await", feature = "std", feature = "executor"))]
#[test]
fn select_streams() {
    use futures::select;
    use futures::channel::mpsc;
    use futures::executor::block_on;
    use futures::sink::SinkExt;
    use futures::stream::StreamExt;

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

#[cfg(all(feature = "async-await", feature = "std", feature = "executor"))]
#[test]
fn select_can_move_uncompleted_futures() {
    use futures::select;
    use futures::channel::oneshot;
    use futures::executor::block_on;
    use futures::future::FutureExt;

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

#[cfg(all(feature = "async-await", feature = "std", feature = "executor"))]
#[test]
fn select_nested() {
    use futures::select;
    use futures::executor::block_on;
    use futures::future;

    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(all(feature = "async-await", feature = "std"))]
#[test]
fn select_size() {
    use futures::select;
    use futures::future;

    let fut = async {
        let mut ready = future::ready(0i32);
        select! {
            _ = ready => {},
        }
    };
    assert_eq!(::std::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!(::std::mem::size_of_val(&fut), 40);
}

#[cfg(all(feature = "async-await", feature = "std", feature = "executor"))]
#[test]
fn select_on_non_unpin_expressions() {
    use futures::select;
    use futures::executor::block_on;
    use futures::future::FutureExt;

    // 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);
}

#[cfg(all(feature = "async-await", feature = "std", feature = "executor"))]
#[test]
fn select_on_non_unpin_expressions_with_default() {
    use futures::select;
    use futures::executor::block_on;
    use futures::future::FutureExt;

    // 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(all(feature = "async-await", feature = "std"))]
#[test]
fn select_on_non_unpin_size() {
    use futures::select;
    use futures::future::FutureExt;

    // 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!(48, std::mem::size_of_val(&fut));
}

#[cfg(all(feature = "async-await", feature = "std", feature = "executor"))]
#[test]
fn select_can_be_used_as_expression() {
    use futures::select;
    use futures::executor::block_on;
    use futures::future;

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

#[cfg(all(feature = "async-await", feature = "std", feature = "executor"))]
#[test]
fn select_with_default_can_be_used_as_expression() {
    use futures::select;
    use futures::executor::block_on;
    use futures::future::{FutureExt, poll_fn};
    use futures::task::{Context, Poll};

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

#[cfg(all(feature = "async-await", feature = "std", feature = "executor"))]
#[test]
fn select_with_complete_can_be_used_as_expression() {
    use futures::select;
    use futures::executor::block_on;
    use futures::future;

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

#[cfg(all(feature = "async-await", feature = "std", feature = "executor"))]
#[test]
fn select_on_mutable_borrowing_future_with_same_borrow_in_block() {
    use futures::select;
    use futures::executor::block_on;
    use futures::future::FutureExt;

    async fn require_mutable(_: &mut i32) {}
    async fn async_noop() {}

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

#[cfg(all(feature = "async-await", feature = "std", feature = "executor"))]
#[test]
fn select_on_mutable_borrowing_future_with_same_borrow_in_block_and_default() {
    use futures::select;
    use futures::executor::block_on;
    use futures::future::FutureExt;

    async fn require_mutable(_: &mut i32) {}
    async fn async_noop() {}

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

#[cfg(feature = "async-await")]
#[test]
fn join_size() {
    use futures::join;
    use futures::future;

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

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

#[cfg(feature = "async-await")]
#[test]
fn try_join_size() {
    use futures::try_join;
    use futures::future;

    let fut = async {
        let ready = future::ready(Ok::<i32, i32>(0));
        try_join!(ready)
    };
    assert_eq!(::std::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!(::std::mem::size_of_val(&fut), 28);
}

#[cfg(feature = "async-await")]
#[test]
fn join_doesnt_require_unpin() {
    use futures::join;

    let _ = async {
        join!(async {}, async {})
    };
}

#[cfg(feature = "async-await")]
#[test]
fn try_join_doesnt_require_unpin() {
    use futures::try_join;

    let _ = async {
        try_join!(
            async { Ok::<(), ()>(()) },
            async { Ok::<(), ()>(()) },
        )
    };
}
<|endoftext|>


<commit_before>//! Data types and utility function for units:
//! Implement a poor man's unit type system for now...
//!
//! Maybe we can have s.th. like this (F#) for Rust:
//!
//! https://en.wikibooks.org/wiki/F_Sharp_Programming/Units_of_Measure
//!
//! Alternatively, see here:
//!
//! https://www.reddit.com/r/rust/comments/37qut9/typesafe_userdefined_units_of_measure_for_rust/
//!
//! https://blog.mozilla.org/research/2014/06/23/static-checking-of-units-in-servo/

use std::ops::Add;
use std::ops::Sub;
use std::ops::Mul;
use std::ops::Div;
use std::cmp::PartialEq;

/// This macro initializes a new unit
macro_rules! init_unit {
    ($unit:ident) => {
        #[derive(Debug,Clone,Copy)]
        pub struct $unit(pub f64);

        impl PartialEq for $unit {
            fn eq(self: &$unit, &$unit(rhs): &$unit) -> bool {
                let $unit(lhs) = *self;
                lhs == rhs
            }
        }

        impl Add for $unit {
            type Output = $unit;

            fn add(self: $unit, $unit(rhs): $unit) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs + rhs)
            }
        }

        impl Sub for $unit {
            type Output = $unit;

            fn sub(self: $unit, $unit(rhs): $unit) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs - rhs)
            }
        }

        impl Mul<f64> for $unit {
            type Output = $unit;

            fn mul(self: $unit, rhs: f64) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs * rhs)
            }
        }

        impl Mul<$unit> for f64 {
            type Output = $unit;

            fn mul(self: f64, $unit(rhs): $unit) -> $unit {
                $unit(self * rhs)
            }
        }

        impl Div<f64> for $unit {
            type Output = $unit;

            fn div(self: $unit, rhs: f64) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs / rhs)
            }
        }

        impl Div<$unit> for $unit {
            type Output = f64;

            fn div(self: $unit, $unit(rhs): $unit) -> f64 {
                let $unit(lhs) = self;
                lhs / rhs
            }
        }
    }
}

/// This macro implements multiplication and division for a given unit
macro_rules! mul_div_unit {
    // $unit1 * $unit2 = $unit3
    // $unit2 * $unit1 = $unit3
    // $unit1 = $unit3 / $unit2
    // $unit2 = $unit3 / $unit1
    ($unit1:ident, $unit2:ident, $unit3:ident) => {
        impl Mul<$unit2> for $unit1 {
            type Output = $unit3;

            fn mul(self: $unit1, $unit2(rhs): $unit2) -> $unit3 {
                let $unit1(lhs) = self;
                $unit3(lhs * rhs)
            }
        }

        impl Mul<$unit1> for $unit2 {
            type Output = $unit3;

            fn mul(self: $unit2, $unit1(rhs): $unit1) -> $unit3 {
                let $unit2(lhs) = self;
                $unit3(lhs * rhs)
            }
        }

        impl Div<$unit2> for $unit3 {
            type Output = $unit1;

            fn div(self: $unit3, $unit2(rhs): $unit2) -> $unit1 {
                let $unit3(lhs) = self;
                $unit1(lhs / rhs)
            }
        }

        impl Div<$unit1> for $unit3 {
            type Output = $unit2;

            fn div(self: $unit3, $unit1(rhs): $unit1) -> $unit2 {
                let $unit3(lhs) = self;
                $unit2(lhs / rhs)
            }
        }
    };

    // $unit1 * $unit1 = $unit2
    // $unit1 = $unit2 / $unit1
    ($unit1:ident, $unit2:ident) => {
        impl Mul<$unit1> for $unit1 {
            type Output = $unit2;

            fn mul(self: $unit1, $unit1(rhs): $unit1) -> $unit2 {
                let $unit1(lhs) = self;
                $unit2(lhs * rhs)
            }
        }

        impl Div<$unit1> for $unit2 {
            type Output = $unit1;

            fn div(self: $unit2, $unit1(rhs): $unit1) -> $unit1 {
                let $unit2(lhs) = self;
                $unit1(lhs / rhs)
            }
        }
    }
}

/// This macro implements the inverse of the given unit
macro_rules! inverse_unit {
    ($unit1:ident, $unit2:ident) => {
        // A * B = 1
        impl Mul<$unit2> for $unit1 {
            type Output = f64;

            fn mul(self: $unit1, $unit2(rhs): $unit2) -> f64 {
                let $unit1(lhs) = self;
                lhs * rhs
            }
        }

        // B * A = 1
        impl Mul<$unit1> for $unit2 {
            type Output = f64;

            fn mul(self: $unit2, $unit1(rhs): $unit1) -> f64 {
                let $unit2(lhs) = self;
                lhs * rhs
            }
        }

        // 1 / A = B
        impl Div<$unit1> for f64 {
            type Output = $unit2;

            fn div(self: f64, $unit1(rhs): $unit1) -> $unit2 {
                $unit2(self / rhs)
            }
        }

        // 1 / B = A
        impl Div<$unit2> for f64 {
            type Output = $unit1;

            fn div(self: f64, $unit2(rhs): $unit2) -> $unit1 {
                $unit1(self / rhs)
            }
        }
    }
}

/// This macro implements a new unit and the inverse unit
macro_rules! init_unit_and_inverse {
    ($unit1:ident, $per_unit1:ident) => {
        init_unit!($unit1);
        init_unit!($per_unit1);
        inverse_unit!($unit1, $per_unit1);
    }
}

/// This macro implements unit^2, unit^3, 1/unit^2 and 1/unit^3
macro_rules! power3_unit {
    ($unit1:ident, $unit2:ident, $unit3:ident, $per_unit1:ident, $per_unit2:ident, $per_unit3:ident) => {
        mul_div_unit!($unit1, $unit2);
        mul_div_unit!($unit1, $unit2, $unit3);

        mul_div_unit!($per_unit1, $per_unit2);
        mul_div_unit!($per_unit1, $per_unit2, $per_unit3);

        mul_div_unit!($unit1, $per_unit2, $per_unit1);
        mul_div_unit!($unit1, $per_unit3, $per_unit2);

        mul_div_unit!($unit2, $per_unit1, $unit1);
        mul_div_unit!($unit2, $per_unit3, $per_unit1);

        mul_div_unit!($unit3, $per_unit1, $unit2);
        mul_div_unit!($unit3, $per_unit2, $unit1);
    }
}

/// This macro combines two units and some permutation / inverse
macro_rules! combine_unit {
    ($unit1:ident, $per_unit1:ident, $unit2:ident, $per_unit2:ident, $unit1_unit2:ident, $unit1_per_unit2:ident, $unit2_per_unit1:ident, $per_unit1_unit2:ident) => {
        mul_div_unit!($unit1, $unit2, $unit1_unit2);
        mul_div_unit!($unit1, $per_unit2, $unit1_per_unit2);

        mul_div_unit!($unit1_per_unit2, $unit2, $unit1);
        mul_div_unit!($unit1_per_unit2, $per_unit1, $per_unit2);

        mul_div_unit!($unit2_per_unit1, $unit1, $unit2);
        mul_div_unit!($unit2_per_unit1, $per_unit2, $per_unit1);

        mul_div_unit!($unit2, $per_unit1, $unit2_per_unit1);
        mul_div_unit!($per_unit1, $per_unit2, $per_unit1_unit2);

        mul_div_unit!($unit1_unit2, $per_unit1, $unit2);
        mul_div_unit!($unit1_unit2, $per_unit2, $unit1);

        mul_div_unit!($per_unit1_unit2, $unit1, $per_unit2);
        mul_div_unit!($per_unit1_unit2, $unit2, $per_unit1);
    }
}

init_unit_and_inverse!(Meter, PerMeter);
init_unit_and_inverse!(Meter2, PerMeter2);
init_unit_and_inverse!(Meter3, PerMeter3);
power3_unit!(Meter, Meter2, Meter3, PerMeter, PerMeter2, PerMeter3);

init_unit_and_inverse!(Second, PerSecond);
init_unit_and_inverse!(Second2, PerSecond2);
init_unit_and_inverse!(Second3, PerSecond3);
power3_unit!(Second, Second2, Second3, PerSecond, PerSecond2, PerSecond3);

init_unit_and_inverse!(MeterPerSecond, SecondPerMeter);
init_unit_and_inverse!(MeterPerSecond2, Second2PerMeter);
init_unit_and_inverse!(Meter2PerSecond, SecondPerMeter2);
init_unit_and_inverse!(Meter2PerSecond2, Second2PerMeter2);
init_unit_and_inverse!(MeterSecond, PerMeterSecond);
init_unit_and_inverse!(Meter2Second, PerMeter2Second);
init_unit_and_inverse!(MeterSecond2, PerMeterSecond2);
init_unit_and_inverse!(Meter2Second2, PerMeter2Second2);

combine_unit!(Meter, PerMeter, Second, PerSecond, MeterSecond, MeterPerSecond, SecondPerMeter, PerMeterSecond);
combine_unit!(Meter2, PerMeter2, Second, PerSecond, Meter2Second, Meter2PerSecond, SecondPerMeter2, PerMeter2Second);
combine_unit!(Meter, PerMeter, Second2, PerSecond2, MeterSecond2, MeterPerSecond2, Second2PerMeter, PerMeterSecond2);
combine_unit!(Meter2, PerMeter2, Second2, PerSecond2, Meter2Second2, Meter2PerSecond2, Second2PerMeter2, PerMeter2Second2);

mul_div_unit!(PerSecond2, Meter2Second, Meter2PerSecond);

init_unit_and_inverse!(Kilogram, PerKilogram);

 // momentum, impulse
init_unit_and_inverse!(KilogramMeterPerSecond, SecondPerKilogramMeter);

mul_div_unit!(Kilogram, MeterPerSecond, KilogramMeterPerSecond);

init_unit_and_inverse!(Newton, PerNewton);

mul_div_unit!(Kilogram, MeterPerSecond2, Newton);
mul_div_unit!(Newton, Second, KilogramMeterPerSecond);

init_unit_and_inverse!(Pascal, PerPascal);

mul_div_unit!(Pascal, Meter2, Newton);

init_unit_and_inverse!(Joule, PerJoule);

mul_div_unit!(Joule, Meter, Newton);

init_unit_and_inverse!(Watt, PerWatt);

mul_div_unit!(Watt, Second, Joule);

init_unit_and_inverse!(DegC, PerDegC);

init_unit_and_inverse!(Kelvin, PerKelvin);

init_unit_and_inverse!(Kelvin2, PerKelvin2);

mul_div_unit!(Kelvin, Kelvin2);

init_unit_and_inverse!(KelvinPerSecond, SecondPerKelvin);

mul_div_unit!(KelvinPerSecond, Second, Kelvin);

init_unit_and_inverse!(DegCPerSecond, SecondPerDegC);

mul_div_unit!(DegCPerSecond, Second, DegC);

init_unit!(JouleDegCPerSecond);

mul_div_unit!(DegCPerSecond, Joule, JouleDegCPerSecond);

init_unit!(JouleKelvinPerSecond);

mul_div_unit!(KelvinPerSecond, Joule, JouleKelvinPerSecond);

init_unit_and_inverse!(Mol, PerMol);

init_unit_and_inverse!(JoulePerKelvin, KelvinPerJoule);

init_unit_and_inverse!(JoulePerMol, MolPerJoule);

init_unit_and_inverse!(JoulePerKelvinMol, KelvinMolPerJoule);

init_unit_and_inverse!(JouleKelvinPerMol, MolPerJouleKelvin);

mul_div_unit!(JoulePerKelvinMol, Kelvin2, JouleKelvinPerMol);

init_unit_and_inverse!(SecondPerMol, MolPerSecond);

init_unit_and_inverse!(JouleKelvinPerMolSecond, MolSecondPerJouleKelvin);

mul_div_unit!(SecondPerMol, JouleKelvinPerSecond, JouleKelvinPerMol);

mul_div_unit!(Mol, SecondPerMol, Second);

mul_div_unit!(Mol, JoulePerKelvinMol, JoulePerKelvin);

mul_div_unit!(Kelvin, JoulePerKelvin, Joule);

mul_div_unit!(JoulePerMol, KelvinPerSecond, JouleKelvinPerMolSecond);

mul_div_unit!(Kelvin,  JoulePerKelvinMol, JoulePerMol);

mul_div_unit!(Second, JouleKelvinPerMolSecond, JouleKelvinPerMol);
<commit_msg>add documenation comments for macro<commit_after>//! Data types and utility function for units:
//! Implement a poor man's unit type system for now...
//!
//! Maybe we can have s.th. like this (F#) for Rust:
//!
//! https://en.wikibooks.org/wiki/F_Sharp_Programming/Units_of_Measure
//!
//! Alternatively, see here:
//!
//! https://www.reddit.com/r/rust/comments/37qut9/typesafe_userdefined_units_of_measure_for_rust/
//!
//! https://blog.mozilla.org/research/2014/06/23/static-checking-of-units-in-servo/

use std::ops::Add;
use std::ops::Sub;
use std::ops::Mul;
use std::ops::Div;
use std::cmp::PartialEq;

/// This macro initializes a new unit
///
/// #Example:
///
/// ```
/// init_unit!(Meter);
/// ```
#[macro_export] macro_rules! init_unit {
    ($unit:ident) => {
        #[derive(Debug,Clone,Copy)]
        pub struct $unit(pub f64);

        impl PartialEq for $unit {
            fn eq(self: &$unit, &$unit(rhs): &$unit) -> bool {
                let $unit(lhs) = *self;
                lhs == rhs
            }
        }

        impl Add for $unit {
            type Output = $unit;

            fn add(self: $unit, $unit(rhs): $unit) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs + rhs)
            }
        }

        impl Sub for $unit {
            type Output = $unit;

            fn sub(self: $unit, $unit(rhs): $unit) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs - rhs)
            }
        }

        impl Mul<f64> for $unit {
            type Output = $unit;

            fn mul(self: $unit, rhs: f64) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs * rhs)
            }
        }

        impl Mul<$unit> for f64 {
            type Output = $unit;

            fn mul(self: f64, $unit(rhs): $unit) -> $unit {
                $unit(self * rhs)
            }
        }

        impl Div<f64> for $unit {
            type Output = $unit;

            fn div(self: $unit, rhs: f64) -> $unit {
                let $unit(lhs) = self;
                $unit(lhs / rhs)
            }
        }

        impl Div<$unit> for $unit {
            type Output = f64;

            fn div(self: $unit, $unit(rhs): $unit) -> f64 {
                let $unit(lhs) = self;
                lhs / rhs
            }
        }
    }
}

/// This macro implements multiplication and division for a given unit
///
/// #Example:
///
/// ```
/// mul_div_unit!(Joule, Meter, Newton);
/// ```
#[macro_export] macro_rules! mul_div_unit {
    // $unit1 * $unit2 = $unit3
    // $unit2 * $unit1 = $unit3
    // $unit1 = $unit3 / $unit2
    // $unit2 = $unit3 / $unit1
    ($unit1:ident, $unit2:ident, $unit3:ident) => {
        impl Mul<$unit2> for $unit1 {
            type Output = $unit3;

            fn mul(self: $unit1, $unit2(rhs): $unit2) -> $unit3 {
                let $unit1(lhs) = self;
                $unit3(lhs * rhs)
            }
        }

        impl Mul<$unit1> for $unit2 {
            type Output = $unit3;

            fn mul(self: $unit2, $unit1(rhs): $unit1) -> $unit3 {
                let $unit2(lhs) = self;
                $unit3(lhs * rhs)
            }
        }

        impl Div<$unit2> for $unit3 {
            type Output = $unit1;

            fn div(self: $unit3, $unit2(rhs): $unit2) -> $unit1 {
                let $unit3(lhs) = self;
                $unit1(lhs / rhs)
            }
        }

        impl Div<$unit1> for $unit3 {
            type Output = $unit2;

            fn div(self: $unit3, $unit1(rhs): $unit1) -> $unit2 {
                let $unit3(lhs) = self;
                $unit2(lhs / rhs)
            }
        }
    };

    // $unit1 * $unit1 = $unit2
    // $unit1 = $unit2 / $unit1
    ($unit1:ident, $unit2:ident) => {
        impl Mul<$unit1> for $unit1 {
            type Output = $unit2;

            fn mul(self: $unit1, $unit1(rhs): $unit1) -> $unit2 {
                let $unit1(lhs) = self;
                $unit2(lhs * rhs)
            }
        }

        impl Div<$unit1> for $unit2 {
            type Output = $unit1;

            fn div(self: $unit2, $unit1(rhs): $unit1) -> $unit1 {
                let $unit2(lhs) = self;
                $unit1(lhs / rhs)
            }
        }
    }
}

/// This macro implements the inverse of the given unit
///
/// #Example:
///
/// ```
/// inverse_unit!(Meter, PerMeter);
/// ```
#[macro_export] macro_rules! inverse_unit {
    ($unit1:ident, $unit2:ident) => {
        // A * B = 1
        impl Mul<$unit2> for $unit1 {
            type Output = f64;

            fn mul(self: $unit1, $unit2(rhs): $unit2) -> f64 {
                let $unit1(lhs) = self;
                lhs * rhs
            }
        }

        // B * A = 1
        impl Mul<$unit1> for $unit2 {
            type Output = f64;

            fn mul(self: $unit2, $unit1(rhs): $unit1) -> f64 {
                let $unit2(lhs) = self;
                lhs * rhs
            }
        }

        // 1 / A = B
        impl Div<$unit1> for f64 {
            type Output = $unit2;

            fn div(self: f64, $unit1(rhs): $unit1) -> $unit2 {
                $unit2(self / rhs)
            }
        }

        // 1 / B = A
        impl Div<$unit2> for f64 {
            type Output = $unit1;

            fn div(self: f64, $unit2(rhs): $unit2) -> $unit1 {
                $unit1(self / rhs)
            }
        }
    }
}

/// This macro implements a new unit and the inverse unit
///
/// #Example:
///
/// ```
/// init_unit_and_inverse!(Meter, PerMeter);
/// ```
#[macro_export] macro_rules! init_unit_and_inverse {
    ($unit1:ident, $per_unit1:ident) => {
        init_unit!($unit1);
        init_unit!($per_unit1);
        inverse_unit!($unit1, $per_unit1);
    }
}

/// This macro implements unit^1, unit^2, unit^3, 1/unit^1, 1/unit^2 and 1/unit^3
///
/// #Example:
///
/// ```
/// power3_unit!(Second, Second2, Second3, PerSecond, PerSecond2, PerSecond3);
/// ```
#[macro_export] macro_rules! power3_unit {
    ($unit1:ident, $unit2:ident, $unit3:ident, $per_unit1:ident, $per_unit2:ident, $per_unit3:ident) => {
        mul_div_unit!($unit1, $unit2);
        mul_div_unit!($unit1, $unit2, $unit3);

        mul_div_unit!($per_unit1, $per_unit2);
        mul_div_unit!($per_unit1, $per_unit2, $per_unit3);

        mul_div_unit!($unit1, $per_unit2, $per_unit1);
        mul_div_unit!($unit1, $per_unit3, $per_unit2);

        mul_div_unit!($unit2, $per_unit1, $unit1);
        mul_div_unit!($unit2, $per_unit3, $per_unit1);

        mul_div_unit!($unit3, $per_unit1, $unit2);
        mul_div_unit!($unit3, $per_unit2, $unit1);
    }
}

/// This macro combines two units and some permutation / inverse
///
/// #Example:
///
/// ```
/// combine_unit!(Meter, PerMeter, Second, PerSecond, MeterSecond, MeterPerSecond, SecondPerMeter, PerMeterSecond);
/// ```
#[macro_export] macro_rules! combine_unit {
    ($unit1:ident, $per_unit1:ident, $unit2:ident, $per_unit2:ident, $unit1_unit2:ident, $unit1_per_unit2:ident, $unit2_per_unit1:ident, $per_unit1_unit2:ident) => {
        mul_div_unit!($unit1, $unit2, $unit1_unit2);
        mul_div_unit!($unit1, $per_unit2, $unit1_per_unit2);

        mul_div_unit!($unit1_per_unit2, $unit2, $unit1);
        mul_div_unit!($unit1_per_unit2, $per_unit1, $per_unit2);

        mul_div_unit!($unit2_per_unit1, $unit1, $unit2);
        mul_div_unit!($unit2_per_unit1, $per_unit2, $per_unit1);

        mul_div_unit!($unit2, $per_unit1, $unit2_per_unit1);
        mul_div_unit!($per_unit1, $per_unit2, $per_unit1_unit2);

        mul_div_unit!($unit1_unit2, $per_unit1, $unit2);
        mul_div_unit!($unit1_unit2, $per_unit2, $unit1);

        mul_div_unit!($per_unit1_unit2, $unit1, $per_unit2);
        mul_div_unit!($per_unit1_unit2, $unit2, $per_unit1);
    }
}

init_unit_and_inverse!(Meter, PerMeter);
init_unit_and_inverse!(Meter2, PerMeter2);
init_unit_and_inverse!(Meter3, PerMeter3);
power3_unit!(Meter, Meter2, Meter3, PerMeter, PerMeter2, PerMeter3);

init_unit_and_inverse!(Second, PerSecond);
init_unit_and_inverse!(Second2, PerSecond2);
init_unit_and_inverse!(Second3, PerSecond3);
power3_unit!(Second, Second2, Second3, PerSecond, PerSecond2, PerSecond3);

init_unit_and_inverse!(MeterPerSecond, SecondPerMeter);
init_unit_and_inverse!(MeterPerSecond2, Second2PerMeter);
init_unit_and_inverse!(Meter2PerSecond, SecondPerMeter2);
init_unit_and_inverse!(Meter2PerSecond2, Second2PerMeter2);
init_unit_and_inverse!(MeterSecond, PerMeterSecond);
init_unit_and_inverse!(Meter2Second, PerMeter2Second);
init_unit_and_inverse!(MeterSecond2, PerMeterSecond2);
init_unit_and_inverse!(Meter2Second2, PerMeter2Second2);

combine_unit!(Meter, PerMeter, Second, PerSecond, MeterSecond, MeterPerSecond, SecondPerMeter, PerMeterSecond);
combine_unit!(Meter2, PerMeter2, Second, PerSecond, Meter2Second, Meter2PerSecond, SecondPerMeter2, PerMeter2Second);
combine_unit!(Meter, PerMeter, Second2, PerSecond2, MeterSecond2, MeterPerSecond2, Second2PerMeter, PerMeterSecond2);
combine_unit!(Meter2, PerMeter2, Second2, PerSecond2, Meter2Second2, Meter2PerSecond2, Second2PerMeter2, PerMeter2Second2);

mul_div_unit!(PerSecond2, Meter2Second, Meter2PerSecond);

init_unit_and_inverse!(Kilogram, PerKilogram);

 // momentum, impulse
init_unit_and_inverse!(KilogramMeterPerSecond, SecondPerKilogramMeter);

mul_div_unit!(Kilogram, MeterPerSecond, KilogramMeterPerSecond);

init_unit_and_inverse!(Newton, PerNewton);

mul_div_unit!(Kilogram, MeterPerSecond2, Newton);
mul_div_unit!(Newton, Second, KilogramMeterPerSecond);

init_unit_and_inverse!(Pascal, PerPascal);

mul_div_unit!(Pascal, Meter2, Newton);

init_unit_and_inverse!(Joule, PerJoule);

mul_div_unit!(Joule, Meter, Newton);

init_unit_and_inverse!(Watt, PerWatt);

mul_div_unit!(Watt, Second, Joule);

init_unit_and_inverse!(DegC, PerDegC);

init_unit_and_inverse!(Kelvin, PerKelvin);

init_unit_and_inverse!(Kelvin2, PerKelvin2);

mul_div_unit!(Kelvin, Kelvin2);

init_unit_and_inverse!(KelvinPerSecond, SecondPerKelvin);

mul_div_unit!(KelvinPerSecond, Second, Kelvin);

init_unit_and_inverse!(DegCPerSecond, SecondPerDegC);

mul_div_unit!(DegCPerSecond, Second, DegC);

init_unit!(JouleDegCPerSecond);

mul_div_unit!(DegCPerSecond, Joule, JouleDegCPerSecond);

init_unit!(JouleKelvinPerSecond);

mul_div_unit!(KelvinPerSecond, Joule, JouleKelvinPerSecond);

init_unit_and_inverse!(Mol, PerMol);

init_unit_and_inverse!(JoulePerKelvin, KelvinPerJoule);

init_unit_and_inverse!(JoulePerMol, MolPerJoule);

init_unit_and_inverse!(JoulePerKelvinMol, KelvinMolPerJoule);

init_unit_and_inverse!(JouleKelvinPerMol, MolPerJouleKelvin);

mul_div_unit!(JoulePerKelvinMol, Kelvin2, JouleKelvinPerMol);

init_unit_and_inverse!(SecondPerMol, MolPerSecond);

init_unit_and_inverse!(JouleKelvinPerMolSecond, MolSecondPerJouleKelvin);

mul_div_unit!(SecondPerMol, JouleKelvinPerSecond, JouleKelvinPerMol);

mul_div_unit!(Mol, SecondPerMol, Second);

mul_div_unit!(Mol, JoulePerKelvinMol, JoulePerKelvin);

mul_div_unit!(Kelvin, JoulePerKelvin, Joule);

mul_div_unit!(JoulePerMol, KelvinPerSecond, JouleKelvinPerMolSecond);

mul_div_unit!(Kelvin,  JoulePerKelvinMol, JoulePerMol);

mul_div_unit!(Second, JouleKelvinPerMolSecond, JouleKelvinPerMol);

// TODO: add more units...
<|endoftext|>


<commit_before>use std::{convert::TryFrom, mem::MaybeUninit};

use crate::pagecache::{constants::PAGE_CONSOLIDATION_THRESHOLD, CacheInfo};

#[derive(Debug, Clone, Copy)]
pub(crate) struct StackVec {
    items: [MaybeUninit<CacheInfo>; PAGE_CONSOLIDATION_THRESHOLD],
    len: u8,
}

impl Default for StackVec {
    fn default() -> StackVec {
        StackVec {
            items: [MaybeUninit::uninit(); PAGE_CONSOLIDATION_THRESHOLD],
            len: 0,
        }
    }
}

impl std::ops::Deref for StackVec {
    type Target = [CacheInfo];

    fn deref(&self) -> &[CacheInfo] {
        #[allow(unsafe_code)]
        unsafe {
            let ptr: *const CacheInfo = self.items.as_ptr() as *const CacheInfo;
            std::slice::from_raw_parts(ptr, self.len as usize)
        }
    }
}

impl std::ops::DerefMut for StackVec {
    fn deref_mut(&mut self) -> &mut [CacheInfo] {
        #[allow(unsafe_code)]
        unsafe {
            let ptr: *mut CacheInfo = self.items.as_mut_ptr() as *mut CacheInfo;
            std::slice::from_raw_parts_mut(ptr, self.len as usize)
        }
    }
}

impl StackVec {
    pub(crate) const fn is_empty(&self) -> bool {
        self.len == 0
    }
}

impl StackVec {
    pub(crate) fn single(item: CacheInfo) -> StackVec {
        let mut sv = Self::default();
        sv.push(item);
        sv
    }

    pub(crate) fn extend_from_slice(&mut self, other: &[CacheInfo]) {
        assert!(
            self.len as usize + other.len() <= PAGE_CONSOLIDATION_THRESHOLD,
            "tried to extend_from_slice into StackVec past max capacity"
        );

        #[allow(unsafe_code)]
        unsafe {
            let src = other.as_ptr();
            let dst = self.items.as_mut_ptr().add(self.len as usize)
                as *mut CacheInfo;
            std::ptr::copy(src, dst, other.len());
        }

        self.len += u8::try_from(other.len()).unwrap();
    }

    pub(crate) fn _insert(&mut self, idx: usize, item: CacheInfo) {
        assert_ne!(
            self.len as usize, PAGE_CONSOLIDATION_THRESHOLD,
            "tried to insert into StackVec already at max capacity"
        );

        assert!(idx <= self.len());

        if idx != self.len as usize {
            let items = self.len as usize - idx;

            #[allow(unsafe_code)]
            unsafe {
                let src = self.items.as_ptr().add(idx);
                let dst = self.items.as_mut_ptr().add(idx + 1);
                std::ptr::copy(src, dst, items);
            }
        }

        self.len += 1;
        self.items[idx] = MaybeUninit::new(item);
    }

    pub(crate) fn push(&mut self, item: CacheInfo) {
        assert_ne!(
            self.len as usize, PAGE_CONSOLIDATION_THRESHOLD,
            "tried to push into StackVec already at max capacity"
        );
        self.items[self.len as usize] = MaybeUninit::new(item);
        self.len += 1;
    }

    pub(crate) fn _pop(&mut self) -> Option<CacheInfo> {
        if self.len > 0 {
            self.len -= 1;

            #[allow(unsafe_code)]
            unsafe {
                Some(self.items[self.len as usize].as_ptr().read())
            }
        } else {
            None
        }
    }
}

#[cfg(test)]
mod qc {
    use quickcheck::{Arbitrary, Gen};
    use rand::Rng;

    use super::{CacheInfo, StackVec, PAGE_CONSOLIDATION_THRESHOLD};

    #[derive(Clone, Debug)]
    enum Op {
        Extend(Vec<CacheInfo>),
        Insert(usize, CacheInfo),
        Push(CacheInfo),
        Pop,
    }

    impl Arbitrary for Op {
        fn arbitrary<G: Gen>(g: &mut G) -> Op {
            match g.gen_range(0, 4) {
                0 => {
                    let len = g.gen_range(0, PAGE_CONSOLIDATION_THRESHOLD);
                    let items = vec![CacheInfo::arbitrary(g); len];
                    Op::Extend(items)
                }
                1 => Op::Insert(
                    g.gen_range(0, PAGE_CONSOLIDATION_THRESHOLD),
                    CacheInfo::arbitrary(g),
                ),
                2 => Op::Push(CacheInfo::arbitrary(g)),
                3 => Op::Pop,
                _ => unreachable!(),
            }
        }
    }

    quickcheck::quickcheck! {
        fn qc_stackvec(ops: Vec<Op>) -> bool {
            let mut sv = StackVec::default();
            let mut v = vec![];

            for op in ops {
                match op {
                    Op::Extend(items) => {
                        if items.len() + v.len() < PAGE_CONSOLIDATION_THRESHOLD {
                            sv.extend_from_slice(&*items);
                            v.extend_from_slice(&items);
                        }
                    }
                    Op::Insert(at, item) => {
                        if at <= v.len() && v.len() < PAGE_CONSOLIDATION_THRESHOLD {
                            sv._insert(at, item);
                            v.insert(at, item);
                        }
                    }
                    Op::Push(item) => {
                        if v.len() < PAGE_CONSOLIDATION_THRESHOLD {
                            sv.push(item);
                            v.push(item);
                        }
                    }
                    Op::Pop => {
                        assert_eq!(sv._pop(), v.pop());
                    }
                }
                assert_eq!(&*sv, &*v);
            }

            true
        }
    }
}
<commit_msg>Clippy feedback<commit_after>use std::{convert::TryFrom, mem::MaybeUninit};

use crate::pagecache::{constants::PAGE_CONSOLIDATION_THRESHOLD, CacheInfo};

#[derive(Debug, Clone, Copy)]
pub(crate) struct StackVec {
    items: [MaybeUninit<CacheInfo>; PAGE_CONSOLIDATION_THRESHOLD],
    len: u8,
}

impl Default for StackVec {
    fn default() -> StackVec {
        StackVec {
            items: [MaybeUninit::uninit(); PAGE_CONSOLIDATION_THRESHOLD],
            len: 0,
        }
    }
}

impl std::ops::Deref for StackVec {
    type Target = [CacheInfo];

    fn deref(&self) -> &[CacheInfo] {
        #[allow(unsafe_code)]
        unsafe {
            let ptr: *const CacheInfo = self.items.as_ptr() as *const CacheInfo;
            std::slice::from_raw_parts(ptr, self.len as usize)
        }
    }
}

impl std::ops::DerefMut for StackVec {
    fn deref_mut(&mut self) -> &mut [CacheInfo] {
        #[allow(unsafe_code)]
        unsafe {
            let ptr: *mut CacheInfo = self.items.as_mut_ptr() as *mut CacheInfo;
            std::slice::from_raw_parts_mut(ptr, self.len as usize)
        }
    }
}

impl StackVec {
    pub(crate) const fn is_empty(&self) -> bool {
        self.len == 0
    }

    pub(crate) fn single(item: CacheInfo) -> StackVec {
        let mut sv = Self::default();
        sv.push(item);
        sv
    }

    pub(crate) fn extend_from_slice(&mut self, other: &[CacheInfo]) {
        assert!(
            self.len as usize + other.len() <= PAGE_CONSOLIDATION_THRESHOLD,
            "tried to extend_from_slice into StackVec past max capacity"
        );

        #[allow(unsafe_code)]
        unsafe {
            let src = other.as_ptr();
            let dst = self.items.as_mut_ptr().add(self.len as usize)
                as *mut CacheInfo;
            std::ptr::copy(src, dst, other.len());
        }

        self.len += u8::try_from(other.len()).unwrap();
    }

    pub(crate) fn _insert(&mut self, idx: usize, item: CacheInfo) {
        assert_ne!(
            self.len as usize, PAGE_CONSOLIDATION_THRESHOLD,
            "tried to insert into StackVec already at max capacity"
        );

        assert!(idx <= self.len());

        if idx != self.len as usize {
            let items = self.len as usize - idx;

            #[allow(unsafe_code)]
            unsafe {
                let src = self.items.as_ptr().add(idx);
                let dst = self.items.as_mut_ptr().add(idx + 1);
                std::ptr::copy(src, dst, items);
            }
        }

        self.len += 1;
        self.items[idx] = MaybeUninit::new(item);
    }

    pub(crate) fn push(&mut self, item: CacheInfo) {
        assert_ne!(
            self.len as usize, PAGE_CONSOLIDATION_THRESHOLD,
            "tried to push into StackVec already at max capacity"
        );
        self.items[self.len as usize] = MaybeUninit::new(item);
        self.len += 1;
    }

    pub(crate) fn _pop(&mut self) -> Option<CacheInfo> {
        if self.len > 0 {
            self.len -= 1;

            #[allow(unsafe_code)]
            unsafe {
                Some(self.items[self.len as usize].as_ptr().read())
            }
        } else {
            None
        }
    }
}

#[cfg(test)]
mod qc {
    use quickcheck::{Arbitrary, Gen};
    use rand::Rng;

    use super::{CacheInfo, StackVec, PAGE_CONSOLIDATION_THRESHOLD};

    #[derive(Clone, Debug)]
    enum Op {
        Extend(Vec<CacheInfo>),
        Insert(usize, CacheInfo),
        Push(CacheInfo),
        Pop,
    }

    impl Arbitrary for Op {
        fn arbitrary<G: Gen>(g: &mut G) -> Op {
            match g.gen_range(0, 4) {
                0 => {
                    let len = g.gen_range(0, PAGE_CONSOLIDATION_THRESHOLD);
                    let items = vec![CacheInfo::arbitrary(g); len];
                    Op::Extend(items)
                }
                1 => Op::Insert(
                    g.gen_range(0, PAGE_CONSOLIDATION_THRESHOLD),
                    CacheInfo::arbitrary(g),
                ),
                2 => Op::Push(CacheInfo::arbitrary(g)),
                3 => Op::Pop,
                _ => unreachable!(),
            }
        }
    }

    quickcheck::quickcheck! {
        fn qc_stackvec(ops: Vec<Op>) -> bool {
            let mut sv = StackVec::default();
            let mut v = vec![];

            for op in ops {
                match op {
                    Op::Extend(items) => {
                        if items.len() + v.len() < PAGE_CONSOLIDATION_THRESHOLD {
                            sv.extend_from_slice(&*items);
                            v.extend_from_slice(&items);
                        }
                    }
                    Op::Insert(at, item) => {
                        if at <= v.len() && v.len() < PAGE_CONSOLIDATION_THRESHOLD {
                            sv._insert(at, item);
                            v.insert(at, item);
                        }
                    }
                    Op::Push(item) => {
                        if v.len() < PAGE_CONSOLIDATION_THRESHOLD {
                            sv.push(item);
                            v.push(item);
                        }
                    }
                    Op::Pop => {
                        assert_eq!(sv._pop(), v.pop());
                    }
                }
                assert_eq!(&*sv, &*v);
            }

            true
        }
    }
}
<|endoftext|>


<commit_before>use std::sync::{Arc, RwLock};
use std::vec::IntoIter;

use radix_trie::Trie;

use crate::completion::Completer;
use crate::config::{Config, EditMode};
use crate::edit::init_state;
use crate::highlight::Highlighter;
use crate::hint::Hinter;
use crate::keymap::{Cmd, InputState};
use crate::keys::{KeyCode as K, KeyEvent, KeyEvent as E, Modifiers as M};
use crate::tty::Sink;
use crate::validate::Validator;
use crate::{apply_backspace_direct, readline_direct, Context, Editor, Helper, Result};

mod common;
mod emacs;
mod history;
mod vi_cmd;
mod vi_insert;

fn init_editor(mode: EditMode, keys: &[KeyEvent]) -> Editor<()> {
    let config = Config::builder().edit_mode(mode).build();
    let mut editor = Editor::<()>::with_config(config);
    editor.term.keys.extend(keys.iter().cloned());
    editor
}

struct SimpleCompleter;
impl Completer for SimpleCompleter {
    type Candidate = String;

    fn complete(
        &self,
        line: &str,
        _pos: usize,
        _ctx: &Context<'_>,
    ) -> Result<(usize, Vec<String>)> {
        Ok((0, vec![line.to_owned() + "t"]))
    }
}
impl Hinter for SimpleCompleter {
    type Hint = String;

    fn hint(&self, _line: &str, _pos: usize, _ctx: &Context<'_>) -> Option<Self::Hint> {
        None
    }
}

impl Helper for SimpleCompleter {}
impl Highlighter for SimpleCompleter {}
impl Validator for SimpleCompleter {}

#[test]
fn complete_line() {
    let mut out = Sink::new();
    let history = crate::history::History::new();
    let helper = Some(SimpleCompleter);
    let mut s = init_state(&mut out, "rus", 3, helper.as_ref(), &history);
    let config = Config::default();
    let mut input_state = InputState::new(&config, Arc::new(RwLock::new(Trie::new())));
    let keys = vec![E::ENTER];
    let mut rdr: IntoIter<KeyEvent> = keys.into_iter();
    let cmd = super::complete_line(&mut rdr, &mut s, &mut input_state, &Config::default()).unwrap();
    assert_eq!(
        Some(Cmd::AcceptOrInsertLine {
            accept_in_the_middle: true
        }),
        cmd
    );
    assert_eq!("rust", s.line.as_str());
    assert_eq!(4, s.line.pos());
}

// `keys`: keys to press
// `expected_line`: line after enter key
fn assert_line(mode: EditMode, keys: &[KeyEvent], expected_line: &str) {
    let mut editor = init_editor(mode, keys);
    let actual_line = editor.readline(">>").unwrap();
    assert_eq!(expected_line, actual_line);
}

// `initial`: line status before `keys` pressed: strings before and after cursor
// `keys`: keys to press
// `expected_line`: line after enter key
fn assert_line_with_initial(
    mode: EditMode,
    initial: (&str, &str),
    keys: &[KeyEvent],
    expected_line: &str,
) {
    let mut editor = init_editor(mode, keys);
    let actual_line = editor.readline_with_initial(">>", initial).unwrap();
    assert_eq!(expected_line, actual_line);
}

// `initial`: line status before `keys` pressed: strings before and after cursor
// `keys`: keys to press
// `expected`: line status before enter key: strings before and after cursor
fn assert_cursor(mode: EditMode, initial: (&str, &str), keys: &[KeyEvent], expected: (&str, &str)) {
    let mut editor = init_editor(mode, keys);
    let actual_line = editor.readline_with_initial("", initial).unwrap();
    assert_eq!(expected.0.to_owned() + expected.1, actual_line);
    assert_eq!(expected.0.len(), editor.term.cursor);
}

// `entries`: history entries before `keys` pressed
// `keys`: keys to press
// `expected`: line status before enter key: strings before and after cursor
fn assert_history(
    mode: EditMode,
    entries: &[&str],
    keys: &[KeyEvent],
    prompt: &str,
    expected: (&str, &str),
) {
    let mut editor = init_editor(mode, keys);
    for entry in entries {
        editor.history.add(*entry);
    }
    let actual_line = editor.readline(prompt).unwrap();
    assert_eq!(expected.0.to_owned() + expected.1, actual_line);
    if prompt.is_empty() {
        assert_eq!(expected.0.len(), editor.term.cursor);
    }
}

#[test]
fn unknown_esc_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_line(*mode, &[E(K::UnknownEscSeq, M::NONE), E::ENTER], "");
    }
}

#[test]
fn test_send() {
    fn assert_send<T: Send>() {}
    assert_send::<Editor<()>>();
}

#[test]
fn test_sync() {
    fn assert_sync<T: Sync>() {}
    assert_sync::<Editor<()>>();
}

#[test]
fn test_apply_backspace_direct() {
    assert_eq!(
        &apply_backspace_direct("Hel\u{0008}\u{0008}el\u{0008}llo ☹\u{0008}☺"),
        "Hello ☺"
    );
}

#[test]
fn test_readline_direct() {
    use std::io::Cursor;

    let mut write_buf = vec![];
    let output = readline_direct(
        Cursor::new("([)\n\u{0008}\n])".as_bytes()),
        Cursor::new(&mut write_buf),
        &Some(crate::validate::MatchingBracketValidator::new()),
    );

    assert_eq!(
        &write_buf,
        b"Mismatched brackets: '[' is not properly closed"
    );
    assert_eq!(&output.unwrap(), "([\n])");
}
<commit_msg>Test Incomplete case with different line endings in readline_direct<commit_after>use std::sync::{Arc, RwLock};
use std::vec::IntoIter;

use radix_trie::Trie;

use crate::completion::Completer;
use crate::config::{Config, EditMode};
use crate::edit::init_state;
use crate::highlight::Highlighter;
use crate::hint::Hinter;
use crate::keymap::{Cmd, InputState};
use crate::keys::{KeyCode as K, KeyEvent, KeyEvent as E, Modifiers as M};
use crate::tty::Sink;
use crate::validate::Validator;
use crate::{apply_backspace_direct, readline_direct, Context, Editor, Helper, Result};

mod common;
mod emacs;
mod history;
mod vi_cmd;
mod vi_insert;

fn init_editor(mode: EditMode, keys: &[KeyEvent]) -> Editor<()> {
    let config = Config::builder().edit_mode(mode).build();
    let mut editor = Editor::<()>::with_config(config);
    editor.term.keys.extend(keys.iter().cloned());
    editor
}

struct SimpleCompleter;
impl Completer for SimpleCompleter {
    type Candidate = String;

    fn complete(
        &self,
        line: &str,
        _pos: usize,
        _ctx: &Context<'_>,
    ) -> Result<(usize, Vec<String>)> {
        Ok((0, vec![line.to_owned() + "t"]))
    }
}
impl Hinter for SimpleCompleter {
    type Hint = String;

    fn hint(&self, _line: &str, _pos: usize, _ctx: &Context<'_>) -> Option<Self::Hint> {
        None
    }
}

impl Helper for SimpleCompleter {}
impl Highlighter for SimpleCompleter {}
impl Validator for SimpleCompleter {}

#[test]
fn complete_line() {
    let mut out = Sink::new();
    let history = crate::history::History::new();
    let helper = Some(SimpleCompleter);
    let mut s = init_state(&mut out, "rus", 3, helper.as_ref(), &history);
    let config = Config::default();
    let mut input_state = InputState::new(&config, Arc::new(RwLock::new(Trie::new())));
    let keys = vec![E::ENTER];
    let mut rdr: IntoIter<KeyEvent> = keys.into_iter();
    let cmd = super::complete_line(&mut rdr, &mut s, &mut input_state, &Config::default()).unwrap();
    assert_eq!(
        Some(Cmd::AcceptOrInsertLine {
            accept_in_the_middle: true
        }),
        cmd
    );
    assert_eq!("rust", s.line.as_str());
    assert_eq!(4, s.line.pos());
}

// `keys`: keys to press
// `expected_line`: line after enter key
fn assert_line(mode: EditMode, keys: &[KeyEvent], expected_line: &str) {
    let mut editor = init_editor(mode, keys);
    let actual_line = editor.readline(">>").unwrap();
    assert_eq!(expected_line, actual_line);
}

// `initial`: line status before `keys` pressed: strings before and after cursor
// `keys`: keys to press
// `expected_line`: line after enter key
fn assert_line_with_initial(
    mode: EditMode,
    initial: (&str, &str),
    keys: &[KeyEvent],
    expected_line: &str,
) {
    let mut editor = init_editor(mode, keys);
    let actual_line = editor.readline_with_initial(">>", initial).unwrap();
    assert_eq!(expected_line, actual_line);
}

// `initial`: line status before `keys` pressed: strings before and after cursor
// `keys`: keys to press
// `expected`: line status before enter key: strings before and after cursor
fn assert_cursor(mode: EditMode, initial: (&str, &str), keys: &[KeyEvent], expected: (&str, &str)) {
    let mut editor = init_editor(mode, keys);
    let actual_line = editor.readline_with_initial("", initial).unwrap();
    assert_eq!(expected.0.to_owned() + expected.1, actual_line);
    assert_eq!(expected.0.len(), editor.term.cursor);
}

// `entries`: history entries before `keys` pressed
// `keys`: keys to press
// `expected`: line status before enter key: strings before and after cursor
fn assert_history(
    mode: EditMode,
    entries: &[&str],
    keys: &[KeyEvent],
    prompt: &str,
    expected: (&str, &str),
) {
    let mut editor = init_editor(mode, keys);
    for entry in entries {
        editor.history.add(*entry);
    }
    let actual_line = editor.readline(prompt).unwrap();
    assert_eq!(expected.0.to_owned() + expected.1, actual_line);
    if prompt.is_empty() {
        assert_eq!(expected.0.len(), editor.term.cursor);
    }
}

#[test]
fn unknown_esc_key() {
    for mode in &[EditMode::Emacs, EditMode::Vi] {
        assert_line(*mode, &[E(K::UnknownEscSeq, M::NONE), E::ENTER], "");
    }
}

#[test]
fn test_send() {
    fn assert_send<T: Send>() {}
    assert_send::<Editor<()>>();
}

#[test]
fn test_sync() {
    fn assert_sync<T: Sync>() {}
    assert_sync::<Editor<()>>();
}

#[test]
fn test_apply_backspace_direct() {
    assert_eq!(
        &apply_backspace_direct("Hel\u{0008}\u{0008}el\u{0008}llo ☹\u{0008}☺"),
        "Hello ☺"
    );
}

#[test]
fn test_readline_direct() {
    use std::io::Cursor;

    let mut write_buf = vec![];
    let output = readline_direct(
        Cursor::new("([)\n\u{0008}\n\n\r\n])".as_bytes()),
        Cursor::new(&mut write_buf),
        &Some(crate::validate::MatchingBracketValidator::new()),
    );

    assert_eq!(
        &write_buf,
        b"Mismatched brackets: '[' is not properly closed"
    );
    assert_eq!(&output.unwrap(), "([\n\n\r\n])");
}
<|endoftext|>


<commit_before>#![no_std]

use core::fmt;
use core::fmt::Write;

use kata_io as io;
use kata_line_reader::LineReader;

/// Error type indicating why a command line is not runnable.
enum CommandError {
    UnknownCommand,
    BadArgs,
    Formatter(fmt::Error),
}

impl fmt::Display for CommandError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            CommandError::UnknownCommand => write!(f, "unknown command"),
            CommandError::BadArgs => write!(f, "invalid arguments"),
            CommandError::Formatter(e) => write!(f, "{}", e),
        }
    }
}

impl From<core::num::ParseIntError> for CommandError {
    fn from(_err: core::num::ParseIntError) -> CommandError {
        CommandError::BadArgs
    }
}

impl From<core::num::ParseFloatError> for CommandError {
    fn from(_err: core::num::ParseFloatError) -> CommandError {
        CommandError::BadArgs
    }
}

impl From<fmt::Error> for CommandError {
    fn from(err: fmt::Error) -> CommandError {
        CommandError::Formatter(err)
    }
}

/// Read-eval-print loop for the DebugConsole command line interface.
pub fn repl(output: &mut dyn io::Write, input: &mut dyn io::Read) -> ! {
    let mut line_reader = LineReader::new();
    loop {
        // The PROMPT is the Hiragana representation of the word "kata."
        const PROMPT: &str = "かた ";
        let _ = output.write_str(PROMPT);
        match line_reader.read_line(output, input) {
            Ok(cmdline) => dispatch_command(cmdline, output),
            Err(e) => {
                let _ = write!(output, "\n{}\n", e);
            }
        }
    }
}

/// Runs a command line.
///
/// The line is split on whitespace. The first token is the command; the
/// remaining tokens are the arguments.
fn dispatch_command(cmdline: &str, output: &mut dyn io::Write) {
    let mut args = cmdline.split_ascii_whitespace();
    match args.nth(0) {
        Some(command) => {
            // Statically binds command names to implementations fns, which are
            // defined below.
            //
            // Since even the binding is static, it is fine for each command
            // implementation to use its own preferred signature.
            let result = match command {
                "echo" => echo_command(cmdline, output),
                "add" => add_command(&mut args, output),
                "clear" => clear_command(output),
                _ => Err(CommandError::UnknownCommand),
            };
            if let Err(e) = result {
                let _ = write!(output, "{}\n", e);
            };
        }
        None => {
            let _ = output.write_str("\n");
        }
    };
}

/// Implements an "echo" command which writes its arguments to output.
fn echo_command(cmdline: &str, output: &mut dyn io::Write) -> Result<(), CommandError> {
    const COMMAND_LENGTH: usize = 5; // "echo "
    if cmdline.len() < COMMAND_LENGTH {
        Ok(())
    } else {
        Ok(write!(
            output,
            "{}\n",
            &cmdline[COMMAND_LENGTH..cmdline.len()]
        )?)
    }
}

/// Implements a binary float addition command.
///
/// This is a toy to demonstrate that the CLI can operate on some very basic
/// dynamic input and that the Rust runtime provides floating point arithmetic
/// on integer-only hardware. It is also a prototype example of "command taking
/// arguments." It should be removed once actually useful system control
/// commands are implemented and done cribbing from it.
fn add_command(
    args: &mut dyn Iterator<Item = &str>,
    output: &mut dyn io::Write,
) -> Result<(), CommandError> {
    if let Some(x_str) = args.nth(0) {
        if let Some(y_str) = args.nth(0) {
            let x = x_str.parse::<f32>()?;
            let y = y_str.parse::<f32>()?;
            return Ok(write!(output, "{}\n", x + y)?);
        }
    }
    Err(CommandError::BadArgs)
}

/// Implements a command that outputs the ANSI "clear console" sequence.
fn clear_command(output: &mut dyn io::Write) -> Result<(), CommandError> {
    Ok(output.write_str("\x1b\x63")?)
}
<commit_msg>shell: Update prompt with Kanji character for kata<commit_after>#![no_std]

use core::fmt;
use core::fmt::Write;

use kata_io as io;
use kata_line_reader::LineReader;

/// Error type indicating why a command line is not runnable.
enum CommandError {
    UnknownCommand,
    BadArgs,
    Formatter(fmt::Error),
}

impl fmt::Display for CommandError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            CommandError::UnknownCommand => write!(f, "unknown command"),
            CommandError::BadArgs => write!(f, "invalid arguments"),
            CommandError::Formatter(e) => write!(f, "{}", e),
        }
    }
}

impl From<core::num::ParseIntError> for CommandError {
    fn from(_err: core::num::ParseIntError) -> CommandError {
        CommandError::BadArgs
    }
}

impl From<core::num::ParseFloatError> for CommandError {
    fn from(_err: core::num::ParseFloatError) -> CommandError {
        CommandError::BadArgs
    }
}

impl From<fmt::Error> for CommandError {
    fn from(err: fmt::Error) -> CommandError {
        CommandError::Formatter(err)
    }
}

/// Read-eval-print loop for the DebugConsole command line interface.
pub fn repl(output: &mut dyn io::Write, input: &mut dyn io::Read) -> ! {
    let mut line_reader = LineReader::new();
    loop {
        // The PROMPT is the Kanji character for the word "form", or "kata."
        const PROMPT: &str = "形＞ ";
        let _ = output.write_str(PROMPT);
        match line_reader.read_line(output, input) {
            Ok(cmdline) => dispatch_command(cmdline, output),
            Err(e) => {
                let _ = write!(output, "\n{}\n", e);
            }
        }
    }
}

/// Runs a command line.
///
/// The line is split on whitespace. The first token is the command; the
/// remaining tokens are the arguments.
fn dispatch_command(cmdline: &str, output: &mut dyn io::Write) {
    let mut args = cmdline.split_ascii_whitespace();
    match args.nth(0) {
        Some(command) => {
            // Statically binds command names to implementations fns, which are
            // defined below.
            //
            // Since even the binding is static, it is fine for each command
            // implementation to use its own preferred signature.
            let result = match command {
                "echo" => echo_command(cmdline, output),
                "add" => add_command(&mut args, output),
                "clear" => clear_command(output),
                _ => Err(CommandError::UnknownCommand),
            };
            if let Err(e) = result {
                let _ = write!(output, "{}\n", e);
            };
        }
        None => {
            let _ = output.write_str("\n");
        }
    };
}

/// Implements an "echo" command which writes its arguments to output.
fn echo_command(cmdline: &str, output: &mut dyn io::Write) -> Result<(), CommandError> {
    const COMMAND_LENGTH: usize = 5; // "echo "
    if cmdline.len() < COMMAND_LENGTH {
        Ok(())
    } else {
        Ok(write!(
            output,
            "{}\n",
            &cmdline[COMMAND_LENGTH..cmdline.len()]
        )?)
    }
}

/// Implements a binary float addition command.
///
/// This is a toy to demonstrate that the CLI can operate on some very basic
/// dynamic input and that the Rust runtime provides floating point arithmetic
/// on integer-only hardware. It is also a prototype example of "command taking
/// arguments." It should be removed once actually useful system control
/// commands are implemented and done cribbing from it.
fn add_command(
    args: &mut dyn Iterator<Item = &str>,
    output: &mut dyn io::Write,
) -> Result<(), CommandError> {
    if let Some(x_str) = args.nth(0) {
        if let Some(y_str) = args.nth(0) {
            let x = x_str.parse::<f32>()?;
            let y = y_str.parse::<f32>()?;
            return Ok(write!(output, "{}\n", x + y)?);
        }
    }
    Err(CommandError::BadArgs)
}

/// Implements a command that outputs the ANSI "clear console" sequence.
fn clear_command(output: &mut dyn io::Write) -> Result<(), CommandError> {
    Ok(output.write_str("\x1b\x63")?)
}
<|endoftext|>


<commit_before>#![allow(unused_must_use)]

extern crate syntax;
extern crate rustc;
extern crate serialize;
extern crate getopts;
extern crate rustc_trans;

use getopts::{optflag,getopts};

use std::io;
use std::os;
use std::io::Reader;
use std::string::String;
use serialize::json;
use serialize::json::{Json, List, String, Object};
use syntax::diagnostics::registry;

use rustc::session;
use rustc::session::config;

use rustc_trans::driver::driver;

fn filter_json(j: &mut json::Json) {
    let mut replace = None;

    match *j {
        json::Object(ref mut ob) => {
            // remove
            ob.remove(&String::from_str("span"));
            ob.remove(&String::from_str("id"));
            let mut kv : Option<(String,Vec<Json>)> = None;
            match ob.get(&String::from_str("node")) {
                Some(&json::Object(ref ob2)) => {
                    match (ob2.get(&String::from_str("variant")),
                           ob2.get(&String::from_str("fields"))) {
                        (Some(&String(ref s)), Some(&List(ref ls))) => {
                            kv = Some((s.clone(), ls.clone()));
                        }
                        _ => ()
                    }
                }
                _ => ()
            }
            match kv {
                None => (),
                Some((k, v)) => {
                    ob.remove(&String::from_str("node"));
                    ob.insert(k, List(v));
                }
            }
            for (_, v) in ob.iter_mut() {
                filter_json(v);
            }
        }
        json::List(ref mut ls) => {
            for v in ls.iter_mut() {
                filter_json(v)
            }
            if ls.len() == 1 {
                replace = Some(ls.as_slice()[0].clone())
            }
        }
        _ => ()
    }
    match replace {
        None => (),
        Some(jj) => *j = jj
    }
}

static INDENT_STEP: int = 4;

fn print_indent(indent: int) {
    let mut out = io::stdout();
    for i in range(0, indent) {
        if i % INDENT_STEP == 0 {
            out.write_str("|");
        } else {
            out.write_str(" ");
        }
    }
}

fn print_sexp(indent: int, j: &json::Json) {
    let mut out = io::stdout();

    match *j {

        json::Object(ref ob) => {
            {
                for (k, v) in ob.iter() {
                    print_indent(indent);
                    out.write_str("(");
                    out.write_str(k.as_slice());
                    out.write_str("\n");
                    print_sexp(indent + INDENT_STEP, v);
                    print_indent(indent);
                    out.write_str(")\n");
                }
            }
        }
        json::List(ref ls) => {
            print_indent(indent);
            out.write_str("(\n");
            for v in ls.iter() {
                print_sexp(indent + INDENT_STEP, v);
            }
            print_indent(indent);
            out.write_str(")\n");
        }
        json::String(ref s) => {
            print_indent(indent);
            out.write_str(s.as_slice());
            out.write_str("\n");
        }
        json::Null => {
            print_indent(indent);
            out.write_str("<nil>\n");
        }
        json::Boolean(true) => {
            print_indent(indent);
            out.write_str("true\n");
        }
        json::Boolean(false) => {
            print_indent(indent);
            out.write_str("false\n");
        }
        json::I64(n) => {
            print_indent(indent);
            out.write_str(n.to_string().as_slice());
            out.write_str("\n");
        }
        json::U64(n) => {
            print_indent(indent);
            out.write_str(n.to_string().as_slice());
            out.write_str("\n");
        }
        json::F64(n) => {
            print_indent(indent);
            out.write_str(n.to_string().as_slice());
            out.write_str("\n");
        }
    }
}

fn main() {

    let args = os::args().into_iter().collect::<Vec<String>>();
    let opts = [ optflag("j", "", "dump output in JSON, not sexp") ];
    let matches = match getopts(args.tail(), &opts) {
        Ok(m) => { m }
        Err(f) => { panic!(f) }
    };
    let dump_json = matches.opt_present("j");

    match io::stdin().read_to_string() {
        Ok(text) => {
            let opt = config::basic_options();
            let sess = session::build_session(opt, None,
                                              registry::Registry::new(&rustc::DIAGNOSTICS));
            let cfg = config::build_configuration(&sess);
            let input = driver::Input::StrInput(text);
            let cr = driver::phase_1_parse_input(&sess, cfg, &input);

            // JSON-ify, meaning "encode then re-parse as just json", ugh.
            let ast_str = json::encode(&cr.module);
            let chars = ast_str.as_slice().chars().collect::<Vec<char>>();
            let mut b = json::Builder::new(chars.into_iter());
            let mut j = b.build().ok().unwrap();

            filter_json(&mut j);
            if dump_json {
                let mut writer = io::stdout();
                j.to_pretty_writer(&mut writer as &mut io::Writer);
            } else {
                print_sexp(0, &j);
            }
        },
        Err(ioerr) => {
            panic!("I/O Error: {}", ioerr.desc);
        }
    }
}
<commit_msg>Update rparse for library changes<commit_after>#![allow(unused_must_use)]

extern crate syntax;
extern crate rustc;
extern crate serialize;
extern crate getopts;
extern crate rustc_trans;

use getopts::{optflag,getopts};

use std::io;
use std::os;
use std::io::Reader;
use std::string::String;
use serialize::json;
use serialize::json::{Json};
use syntax::diagnostics::registry;

use rustc::session;
use rustc::session::config;

use rustc_trans::driver::driver;

fn filter_json(j: &mut json::Json) {
    let mut replace = None;

    match *j {
        Json::Object(ref mut ob) => {
            // remove
            ob.remove(&String::from_str("span"));
            ob.remove(&String::from_str("id"));
            let mut kv : Option<(String,Vec<Json>)> = None;
            match ob.get(&String::from_str("node")) {
                Some(&Json::Object(ref ob2)) => {
                    match (ob2.get(&String::from_str("variant")),
                           ob2.get(&String::from_str("fields"))) {
                        (Some(&Json::String(ref s)), Some(&Json::Array(ref ls))) => {
                            kv = Some((s.clone(), ls.clone()));
                        }
                        _ => ()
                    }
                }
                _ => ()
            }
            match kv {
                None => (),
                Some((k, v)) => {
                    ob.remove(&String::from_str("node"));
                    ob.insert(k, Json::Array(v));
                }
            }
            for (_, v) in ob.iter_mut() {
                filter_json(v);
            }
        }
        Json::Array(ref mut ls) => {
            for v in ls.iter_mut() {
                filter_json(v)
            }
            if ls.len() == 1 {
                replace = Some(ls.as_slice()[0].clone())
            }
        }
        _ => ()
    }
    match replace {
        None => (),
        Some(jj) => *j = jj
    }
}

static INDENT_STEP: int = 4;

fn print_indent(indent: int) {
    let mut out = io::stdout();
    for i in range(0, indent) {
        if i % INDENT_STEP == 0 {
            out.write_str("|");
        } else {
            out.write_str(" ");
        }
    }
}

fn print_sexp(indent: int, j: &json::Json) {
    let mut out = io::stdout();

    match *j {

        Json::Object(ref ob) => {
            {
                for (k, v) in ob.iter() {
                    print_indent(indent);
                    out.write_str("(");
                    out.write_str(k.as_slice());
                    out.write_str("\n");
                    print_sexp(indent + INDENT_STEP, v);
                    print_indent(indent);
                    out.write_str(")\n");
                }
            }
        }
        Json::Array(ref ls) => {
            print_indent(indent);
            out.write_str("(\n");
            for v in ls.iter() {
                print_sexp(indent + INDENT_STEP, v);
            }
            print_indent(indent);
            out.write_str(")\n");
        }
        Json::String(ref s) => {
            print_indent(indent);
            out.write_str(s.as_slice());
            out.write_str("\n");
        }
        Json::Null => {
            print_indent(indent);
            out.write_str("<nil>\n");
        }
        Json::Boolean(true) => {
            print_indent(indent);
            out.write_str("true\n");
        }
        Json::Boolean(false) => {
            print_indent(indent);
            out.write_str("false\n");
        }
        Json::I64(n) => {
            print_indent(indent);
            out.write_str(n.to_string().as_slice());
            out.write_str("\n");
        }
        Json::U64(n) => {
            print_indent(indent);
            out.write_str(n.to_string().as_slice());
            out.write_str("\n");
        }
        Json::F64(n) => {
            print_indent(indent);
            out.write_str(n.to_string().as_slice());
            out.write_str("\n");
        }
    }
}

fn main() {

    let args = os::args().into_iter().collect::<Vec<String>>();
    let opts = [ optflag("j", "", "dump output in JSON, not sexp") ];
    let matches = match getopts(args.tail(), &opts) {
        Ok(m) => { m }
        Err(f) => { panic!(f) }
    };
    let dump_json = matches.opt_present("j");

    match io::stdin().read_to_string() {
        Ok(text) => {
            let opt = config::basic_options();
            let sess = session::build_session(opt, None,
                                              registry::Registry::new(&rustc::DIAGNOSTICS));
            let cfg = config::build_configuration(&sess);
            let input = driver::Input::StrInput(text);
            let cr = driver::phase_1_parse_input(&sess, cfg, &input);

            // JSON-ify, meaning "encode then re-parse as just json", ugh.
            let ast_str = json::encode(&cr.module);
            let chars = ast_str.as_slice().chars().collect::<Vec<char>>();
            let mut b = json::Builder::new(chars.into_iter());
            let mut j = b.build().ok().unwrap();

            filter_json(&mut j);
            if dump_json {
                let mut writer = io::stdout();
                j.to_pretty_writer(&mut writer as &mut io::Writer);
            } else {
                print_sexp(0, &j);
            }
        },
        Err(ioerr) => {
            panic!("I/O Error: {}", ioerr.desc);
        }
    }
}
<|endoftext|>