<commit_before>extern crate desync;
extern crate futures;

use desync::Desync;

mod scheduler;
use self::scheduler::timeout::*;

use futures::prelude::*;
use futures::future;

use std::sync::*;
use std::time::*;
use std::thread::*;

#[derive(Debug)]
struct TestData {
    val: u32
}

#[test]
fn retrieve_data_synchronously() {
    let desynced = Desync::new(TestData { val: 0 });

    assert!(desynced.sync(|data| data.val) == 0);
}

#[test]
fn retrieve_data_into_local_var() {
    let desynced = Desync::new(TestData { val: 42 });
    let mut val = 0;

    desynced.sync(|data| val = data.val);

    assert!(val == 42);
}

#[test]
fn update_data_asynchronously() {
    let desynced = Desync::new(TestData { val: 0 });

    desynced.desync(|data| {
        sleep(Duration::from_millis(100));
        data.val = 42;
    });

    assert!(desynced.sync(|data| data.val) == 42);
}

#[test]
fn update_data_asynchronously_1000_times() {
    for _i in 0..1000 {
        timeout(|| {
            let desynced = Desync::new(TestData { val: 0 });

            desynced.desync(|data| {
                data.val = 42;
            });
            desynced.desync(|data| {
                data.val = 43;
            });

            assert!(desynced.sync(|data| data.val) == 43);
        }, 500);
    }
}

#[test]
fn update_data_with_future() {
    timeout(|| {
        use futures::executor;

        let desynced = Desync::new(TestData { val: 0 });

        desynced.desync(|data| {
            sleep(Duration::from_millis(100));
            data.val = 42;
        });

        executor::block_on(async {
            let future = desynced.future_desync(|data| { Box::pin(future::ready(data.val)) });
            assert!(future.await.unwrap() == 42);
        });
    }, 500);
}

#[test]
fn update_data_with_future_1000_times() {
    // Seems to timeout fairly reliably after signalling the future
    use futures::executor;

    for _i in 0..1000 {
        timeout(|| {
            let desynced = Desync::new(TestData { val: 0 });

            desynced.desync(|data| {
                data.val = 42;
            });
            desynced.desync(|data| {
                data.val = 43;
            });

            executor::block_on(async {
                let future = desynced.future_desync(|data| Box::pin(future::ready(data.val)));

                assert!(future.await.unwrap() == 43);
            });
        }, 500);
    }
}

#[test]
fn update_data_with_future_sync() {
    timeout(|| {
        use futures::executor;

        let desynced = Desync::new(TestData { val: 0 });

        desynced.desync(|data| {
            sleep(Duration::from_millis(100));
            data.val = 42;
        });

        executor::block_on(async {
            let future = desynced.future_sync(|data| { Box::pin(future::ready(data.val)) });
            assert!(future.await.unwrap() == 42);
        });
    }, 500);
}

#[test]
fn update_data_with_future_sync_1000_times() {
    // Seems to timeout fairly reliably after signalling the future
    use futures::executor;

    for _i in 0..1000 {
        timeout(|| {
            let desynced = Desync::new(TestData { val: 0 });

            desynced.desync(|data| {
                data.val = 42;
            });
            desynced.desync(|data| {
                data.val = 43;
            });

            executor::block_on(async {
                let future = desynced.future_sync(|data| Box::pin(future::ready(data.val)));

                assert!(future.await.unwrap() == 43);
            });
        }, 500);
    }
}

#[test]
fn dropping_while_running_isnt_obviously_bad() {
    let desynced = Desync::new(TestData { val: 0 });

    desynced.desync(|data| {
        sleep(Duration::from_millis(100));
        data.val = 42;
    });
    desynced.desync(|data| {
        sleep(Duration::from_millis(100));
        data.val = 42;
    });
}

#[test]
fn wait_for_future() {
    // TODO: occasional test failure that happens if the future 'arrives' before the queue is empty
    // (Because we need a future that arrives when the queue is actually suspended)
    timeout(|| {
        use futures::executor;
        use futures::channel::oneshot;

        // We use a oneshot as our future, and a mpsc channel to track progress
        let desynced                = Desync::new(0);
        let (future_tx, future_rx)  = oneshot::channel();

        // First value 0 -> 1
        desynced.desync(|val| {
            // Sleep here so the future should be waiting for us
            sleep(Duration::from_millis(100));
            assert!(*val == 0);
            *val = 1;
        });

        // Future should go 1 -> 2, but takes whatever future_tx sends
        let future = desynced.after(future_rx, |val, future_result| {
            assert!(*val == 1);
            *val = future_result.unwrap();

            // Return '4' to anything listening for this future
            4
        });

        // Finally, 3
        desynced.desync(move |val| { assert!(*val == 2); *val = 3 });

        executor::block_on(async {
            // Send '2' to the future
            future_tx.send(2).unwrap();

            // Future should resolve to 4
            assert!(future.await == Ok(4));

            // Final value should be 3
            assert!(desynced.sync(|val| *val) == 3);
        })
    }, 500);
}

#[test]
fn future_and_sync() {
    // This test seems to produce different behaviour if it's run by itself (this sleep tends to force it to run after the other tests and thus fail)
    // So far the failure seems reliable when this test is running exclusively
    sleep(Duration::from_millis(1000));

    use std::thread;
    use futures::prelude::*;
    use futures::channel::oneshot;

    // The idea here is we perform an action with a future() and read the result back with a sync() (which is a way you can mix-and-match
    // programming models with desync)
    //
    // The 'core' runs a request as a future, waiting for the channel result. We store the result in sync_request, and then retrieve
    // it again by calling sync - as Desync always runs things sequentially, it guarantees the ordering (something that's much harder
    // to achieve with a mutex)
    let (send, recv)    = oneshot::channel::<i32>();
    let core            = Desync::new(0);
    let sync_request    = Desync::new(None);

    // Send a request to the 'core' via the sync reqeust and store the result
    let _ = sync_request.future_desync(move |data| {
        async move {
            let result = core.future_desync(move |_core| {
                async move {
                    Some(recv.await.unwrap())
                }.boxed()
            }).await;

            *data = result.unwrap();
        }.boxed()
    });

    // Signal the future after a delay
    thread::spawn(move || {
        thread::sleep(Duration::from_millis(50));
        send.send(42).ok();
    });

    // Retrieve the result once the future completes
    let result = sync_request.sync(|req| req.take());

    // Should retrieve the value generated in the future
    assert!(result == Some(42));
}

#[test]
fn double_future_and_sync() {
    use std::thread;

    // TODO: signal with channels instead of using thread::sleep

    // This test will queue two futures here, each of which will need to return to another desync
    // If two futures are scheduled and triggered in a row when draining a queue that both signal
    let core        = Arc::new(Desync::new(()));

    let initiator_1 = Desync::new(None);
    let initiator_2 = Desync::new(None);
    let initiator_3 = Desync::new(None);

    let core_1      = Arc::clone(&core);
    initiator_1.future_desync(move |val| {
        async move {
            // Wait for a task on the core
            *val = core_1.future_desync(move |_| {
                async move { thread::sleep(Duration::from_millis(400)); Some(1) }.boxed()
            }).await.unwrap();
        }.boxed()
    }).detach();

    let core_2      = Arc::clone(&core);
    initiator_2.future_desync(move |val| {
        async move {
            // Wait for the original initiator to start its future
            thread::sleep(Duration::from_millis(100));

            // Wait for a task on the core
            *val = core_2.future_desync(move |_| {
                async move { thread::sleep(Duration::from_millis(200)); Some(2) }.boxed()
            }).await.unwrap();
        }.boxed()
    }).detach();

    let core_3      = Arc::clone(&core);
    initiator_3.future_desync(move |val| {
        async move {
            // Wait for the original initiator to start its future
            thread::sleep(Duration::from_millis(200));

            // Wait for a task on the core
            *val = core_3.future_desync(move |_| {
                async move { thread::sleep(Duration::from_millis(200)); Some(3) }.boxed()
            }).await.unwrap();
        }.boxed()
    }).detach();

    // Wait for the result from the futures synchronously
    assert!(initiator_3.sync(|val| { *val }) == Some(3));
    assert!(initiator_2.sync(|val| { *val }) == Some(2));
    assert!(initiator_1.sync(|val| { *val }) == Some(1));
}

#[test]
fn try_sync_succeeds_on_idle_queue() {
    timeout(|| {
        let core        = Desync::new(0);

        // Queue is doing nothing, so try_sync should succeed
        let sync_result = core.try_sync(|val| {
            *val = 42;
            1
        });

        // Queue is idle, so we should receive a result
        assert!(sync_result == Ok(1));

        // Double-check that the value was updated
        assert!(core.sync(|val| *val) == 42);
    }, 500);
}

#[test]
fn try_sync_succeeds_on_idle_queue_after_async_job() {
    timeout(|| {
        use std::thread;
        let core        = Desync::new(0);

        // Schedule something asynchronously and wait for it to complete
        core.desync(|_val| thread::sleep(Duration::from_millis(50)));
        core.sync(|_val| { });

        // Queue is doing nothing, so try_sync should succeed
        let sync_result = core.try_sync(|val| {
            *val= 42;
            1
        });

        // Queue is idle, so we should receive a result
        assert!(sync_result == Ok(1));

        // Double-check that the value was updated
        assert!(core.sync(|val| *val) == 42);
    }, 500);
}

#[test]
fn try_sync_fails_on_busy_queue() {
    timeout(|| {
        use std::sync::mpsc::*;

        let core        = Desync::new(0);

        // Schedule on the queue and block it
        let (tx, rx)    = channel();

        core.desync(move |_val| { rx.recv().ok(); });

        // Queue is busy, so try_sync should fail
        let sync_result = core.try_sync(|val| {
            *val = 42;
            1
        });

        // Queue is idle, so we should receive a result
        assert!(sync_result.is_err());

        // Unblock the queue
        tx.send(1).ok();

        // Double-check that the value was not updated
        assert!((core.sync(|val| *val)) == 0);
    }, 500);
}
<commit_msg>Can stop boxing things in the tests<commit_after>extern crate desync;
extern crate futures;

use desync::Desync;

mod scheduler;
use self::scheduler::timeout::*;

use futures::prelude::*;
use futures::future;

use std::sync::*;
use std::time::*;
use std::thread::*;

#[derive(Debug)]
struct TestData {
    val: u32
}

#[test]
fn retrieve_data_synchronously() {
    let desynced = Desync::new(TestData { val: 0 });

    assert!(desynced.sync(|data| data.val) == 0);
}

#[test]
fn retrieve_data_into_local_var() {
    let desynced = Desync::new(TestData { val: 42 });
    let mut val = 0;

    desynced.sync(|data| val = data.val);

    assert!(val == 42);
}

#[test]
fn update_data_asynchronously() {
    let desynced = Desync::new(TestData { val: 0 });

    desynced.desync(|data| {
        sleep(Duration::from_millis(100));
        data.val = 42;
    });

    assert!(desynced.sync(|data| data.val) == 42);
}

#[test]
fn update_data_asynchronously_1000_times() {
    for _i in 0..1000 {
        timeout(|| {
            let desynced = Desync::new(TestData { val: 0 });

            desynced.desync(|data| {
                data.val = 42;
            });
            desynced.desync(|data| {
                data.val = 43;
            });

            assert!(desynced.sync(|data| data.val) == 43);
        }, 500);
    }
}

#[test]
fn update_data_with_future() {
    timeout(|| {
        use futures::executor;

        let desynced = Desync::new(TestData { val: 0 });

        desynced.desync(|data| {
            sleep(Duration::from_millis(100));
            data.val = 42;
        });

        executor::block_on(async {
            let future = desynced.future_desync(|data| { future::ready(data.val) });
            assert!(future.await.unwrap() == 42);
        });
    }, 500);
}

#[test]
fn update_data_with_future_1000_times() {
    // Seems to timeout fairly reliably after signalling the future
    use futures::executor;

    for _i in 0..1000 {
        timeout(|| {
            let desynced = Desync::new(TestData { val: 0 });

            desynced.desync(|data| {
                data.val = 42;
            });
            desynced.desync(|data| {
                data.val = 43;
            });

            executor::block_on(async {
                let future = desynced.future_desync(|data| Box::pin(future::ready(data.val)));

                assert!(future.await.unwrap() == 43);
            });
        }, 500);
    }
}

#[test]
fn update_data_with_future_sync() {
    timeout(|| {
        use futures::executor;

        let desynced = Desync::new(TestData { val: 0 });

        desynced.desync(|data| {
            sleep(Duration::from_millis(100));
            data.val = 42;
        });

        executor::block_on(async {
            let future = desynced.future_sync(|data| { future::ready(data.val) });
            assert!(future.await.unwrap() == 42);
        });
    }, 500);
}

#[test]
fn update_data_with_future_sync_1000_times() {
    // Seems to timeout fairly reliably after signalling the future
    use futures::executor;

    for _i in 0..1000 {
        timeout(|| {
            let desynced = Desync::new(TestData { val: 0 });

            desynced.desync(|data| {
                data.val = 42;
            });
            desynced.desync(|data| {
                data.val = 43;
            });

            executor::block_on(async {
                let future = desynced.future_sync(|data| future::ready(data.val));

                assert!(future.await.unwrap() == 43);
            });
        }, 500);
    }
}

#[test]
fn dropping_while_running_isnt_obviously_bad() {
    let desynced = Desync::new(TestData { val: 0 });

    desynced.desync(|data| {
        sleep(Duration::from_millis(100));
        data.val = 42;
    });
    desynced.desync(|data| {
        sleep(Duration::from_millis(100));
        data.val = 42;
    });
}

#[test]
fn wait_for_future() {
    // TODO: occasional test failure that happens if the future 'arrives' before the queue is empty
    // (Because we need a future that arrives when the queue is actually suspended)
    timeout(|| {
        use futures::executor;
        use futures::channel::oneshot;

        // We use a oneshot as our future, and a mpsc channel to track progress
        let desynced                = Desync::new(0);
        let (future_tx, future_rx)  = oneshot::channel();

        // First value 0 -> 1
        desynced.desync(|val| {
            // Sleep here so the future should be waiting for us
            sleep(Duration::from_millis(100));
            assert!(*val == 0);
            *val = 1;
        });

        // Future should go 1 -> 2, but takes whatever future_tx sends
        let future = desynced.after(future_rx, |val, future_result| {
            assert!(*val == 1);
            *val = future_result.unwrap();

            // Return '4' to anything listening for this future
            4
        });

        // Finally, 3
        desynced.desync(move |val| { assert!(*val == 2); *val = 3 });

        executor::block_on(async {
            // Send '2' to the future
            future_tx.send(2).unwrap();

            // Future should resolve to 4
            assert!(future.await == Ok(4));

            // Final value should be 3
            assert!(desynced.sync(|val| *val) == 3);
        })
    }, 500);
}

#[test]
fn future_and_sync() {
    // This test seems to produce different behaviour if it's run by itself (this sleep tends to force it to run after the other tests and thus fail)
    // So far the failure seems reliable when this test is running exclusively
    sleep(Duration::from_millis(1000));

    use std::thread;
    use futures::prelude::*;
    use futures::channel::oneshot;

    // The idea here is we perform an action with a future() and read the result back with a sync() (which is a way you can mix-and-match
    // programming models with desync)
    //
    // The 'core' runs a request as a future, waiting for the channel result. We store the result in sync_request, and then retrieve
    // it again by calling sync - as Desync always runs things sequentially, it guarantees the ordering (something that's much harder
    // to achieve with a mutex)
    let (send, recv)    = oneshot::channel::<i32>();
    let core            = Desync::new(0);
    let sync_request    = Desync::new(None);

    // Send a request to the 'core' via the sync reqeust and store the result
    let _ = sync_request.future_desync(move |data| {
        async move {
            let result = core.future_desync(move |_core| {
                async move {
                    Some(recv.await.unwrap())
                }.boxed()
            }).await;

            *data = result.unwrap();
        }
    });

    // Signal the future after a delay
    thread::spawn(move || {
        thread::sleep(Duration::from_millis(50));
        send.send(42).ok();
    });

    // Retrieve the result once the future completes
    let result = sync_request.sync(|req| req.take());

    // Should retrieve the value generated in the future
    assert!(result == Some(42));
}

#[test]
fn double_future_and_sync() {
    use std::thread;

    // TODO: signal with channels instead of using thread::sleep

    // This test will queue two futures here, each of which will need to return to another desync
    // If two futures are scheduled and triggered in a row when draining a queue that both signal
    let core        = Arc::new(Desync::new(()));

    let initiator_1 = Desync::new(None);
    let initiator_2 = Desync::new(None);
    let initiator_3 = Desync::new(None);

    let core_1      = Arc::clone(&core);
    initiator_1.future_desync(move |val| {
        async move {
            // Wait for a task on the core
            *val = core_1.future_desync(move |_| {
                async move { thread::sleep(Duration::from_millis(400)); Some(1) }.boxed()
            }).await.unwrap();
        }
    }).detach();

    let core_2      = Arc::clone(&core);
    initiator_2.future_desync(move |val| {
        async move {
            // Wait for the original initiator to start its future
            thread::sleep(Duration::from_millis(100));

            // Wait for a task on the core
            *val = core_2.future_desync(move |_| {
                async move { thread::sleep(Duration::from_millis(200)); Some(2) }.boxed()
            }).await.unwrap();
        }
    }).detach();

    let core_3      = Arc::clone(&core);
    initiator_3.future_desync(move |val| {
        async move {
            // Wait for the original initiator to start its future
            thread::sleep(Duration::from_millis(200));

            // Wait for a task on the core
            *val = core_3.future_desync(move |_| {
                async move { thread::sleep(Duration::from_millis(200)); Some(3) }.boxed()
            }).await.unwrap();
        }
    }).detach();

    // Wait for the result from the futures synchronously
    assert!(initiator_3.sync(|val| { *val }) == Some(3));
    assert!(initiator_2.sync(|val| { *val }) == Some(2));
    assert!(initiator_1.sync(|val| { *val }) == Some(1));
}

#[test]
fn try_sync_succeeds_on_idle_queue() {
    timeout(|| {
        let core        = Desync::new(0);

        // Queue is doing nothing, so try_sync should succeed
        let sync_result = core.try_sync(|val| {
            *val = 42;
            1
        });

        // Queue is idle, so we should receive a result
        assert!(sync_result == Ok(1));

        // Double-check that the value was updated
        assert!(core.sync(|val| *val) == 42);
    }, 500);
}

#[test]
fn try_sync_succeeds_on_idle_queue_after_async_job() {
    timeout(|| {
        use std::thread;
        let core        = Desync::new(0);

        // Schedule something asynchronously and wait for it to complete
        core.desync(|_val| thread::sleep(Duration::from_millis(50)));
        core.sync(|_val| { });

        // Queue is doing nothing, so try_sync should succeed
        let sync_result = core.try_sync(|val| {
            *val= 42;
            1
        });

        // Queue is idle, so we should receive a result
        assert!(sync_result == Ok(1));

        // Double-check that the value was updated
        assert!(core.sync(|val| *val) == 42);
    }, 500);
}

#[test]
fn try_sync_fails_on_busy_queue() {
    timeout(|| {
        use std::sync::mpsc::*;

        let core        = Desync::new(0);

        // Schedule on the queue and block it
        let (tx, rx)    = channel();

        core.desync(move |_val| { rx.recv().ok(); });

        // Queue is busy, so try_sync should fail
        let sync_result = core.try_sync(|val| {
            *val = 42;
            1
        });

        // Queue is idle, so we should receive a result
        assert!(sync_result.is_err());

        // Unblock the queue
        tx.send(1).ok();

        // Double-check that the value was not updated
        assert!((core.sync(|val| *val)) == 0);
    }, 500);
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! ## The Cleanup module
//!
//! The cleanup module tracks what values need to be cleaned up as scopes
//! are exited, either via panic or just normal control flow.
//!
//! Cleanup items can be scheduled into any of the scopes on the stack.
//! Typically, when a scope is finished, we generate the cleanup code. This
//! corresponds to a normal exit from a block (for example, an expression
//! completing evaluation successfully without panic).

use llvm::{BasicBlockRef, ValueRef};
use base::{self, Lifetime};
use common;
use common::{BlockAndBuilder, FunctionContext, Funclet};
use glue;
use type_::Type;
use value::Value;
use rustc::ty::Ty;

pub struct CleanupScope<'tcx> {
    // Cleanup to run upon scope exit.
    cleanup: Option<DropValue<'tcx>>,

    // Computed on creation if compiling with landing pads (!sess.no_landing_pads)
    pub landing_pad: Option<BasicBlockRef>,
}

#[derive(Copy, Clone)]
pub struct DropValue<'tcx> {
    val: ValueRef,
    ty: Ty<'tcx>,
    skip_dtor: bool,
}

impl<'tcx> DropValue<'tcx> {
    fn trans<'a>(&self, funclet: Option<&'a Funclet>, bcx: &BlockAndBuilder<'a, 'tcx>) {
        glue::call_drop_glue(bcx, self.val, self.ty, self.skip_dtor, funclet)
    }
}

#[derive(Copy, Clone, Debug)]
enum UnwindKind {
    LandingPad,
    CleanupPad(ValueRef),
}

impl UnwindKind {
    /// Generates a branch going from `bcx` to `to_llbb` where `self` is
    /// the exit label attached to the start of `bcx`.
    ///
    /// Transitions from an exit label to other exit labels depend on the type
    /// of label. For example with MSVC exceptions unwind exit labels will use
    /// the `cleanupret` instruction instead of the `br` instruction.
    fn branch(&self, bcx: &BlockAndBuilder, to_llbb: BasicBlockRef) {
        match *self {
            UnwindKind::CleanupPad(pad) => {
                bcx.cleanup_ret(pad, Some(to_llbb));
            }
            UnwindKind::LandingPad => {
                bcx.br(to_llbb);
            }
        }
    }
}

impl PartialEq for UnwindKind {
    fn eq(&self, label: &UnwindKind) -> bool {
        match (*self, *label) {
            (UnwindKind::LandingPad, UnwindKind::LandingPad) |
            (UnwindKind::CleanupPad(..), UnwindKind::CleanupPad(..)) => true,
            _ => false,
        }
    }
}

impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
    /// Schedules a (deep) drop of `val`, which is a pointer to an instance of `ty`
    pub fn schedule_drop_mem(&self, val: ValueRef, ty: Ty<'tcx>) -> CleanupScope<'tcx> {
        if !self.ccx.shared().type_needs_drop(ty) { return CleanupScope::noop(); }
        let drop = DropValue {
            val: val,
            ty: ty,
            skip_dtor: false,
        };

        debug!("schedule_drop_mem(val={:?}, ty={:?}) skip_dtor={}", Value(val), ty, drop.skip_dtor);

        CleanupScope::new(self, drop)
    }

    /// Issue #23611: Schedules a (deep) drop of the contents of
    /// `val`, which is a pointer to an instance of struct/enum type
    /// `ty`. The scheduled code handles extracting the discriminant
    /// and dropping the contents associated with that variant
    /// *without* executing any associated drop implementation.
    pub fn schedule_drop_adt_contents(&self, val: ValueRef, ty: Ty<'tcx>) -> CleanupScope<'tcx> {
        // `if` below could be "!contents_needs_drop"; skipping drop
        // is just an optimization, so sound to be conservative.
        if !self.ccx.shared().type_needs_drop(ty) { return CleanupScope::noop(); }

        let drop = DropValue {
            val: val,
            ty: ty,
            skip_dtor: true,
        };

        debug!("schedule_drop_adt_contents(val={:?}, ty={:?}) skip_dtor={}",
               Value(val), ty, drop.skip_dtor);

        CleanupScope::new(self, drop)
    }
}

impl<'tcx> CleanupScope<'tcx> {
    fn new<'a>(fcx: &FunctionContext<'a, 'tcx>, drop_val: DropValue<'tcx>) -> CleanupScope<'tcx> {
        CleanupScope {
            cleanup: Some(drop_val),
            landing_pad: if !fcx.ccx.sess().no_landing_pads() {
                Some(CleanupScope::get_landing_pad(fcx, &drop_val))
            } else {
                None
            },
        }
    }

    pub fn noop() -> CleanupScope<'tcx> {
        CleanupScope {
            cleanup: None,
            landing_pad: None,
        }
    }

    pub fn trans<'a>(self, bcx: &'a BlockAndBuilder<'a, 'tcx>) {
        if let Some(cleanup) = self.cleanup {
            cleanup.trans(None, &bcx);
        }
    }

    /// Creates a landing pad for the top scope. The landing pad will perform all cleanups necessary
    /// for an unwind and then `resume` to continue error propagation:
    ///
    ///     landing_pad -> ... cleanups ... -> [resume]
    ///
    /// This should only be called once per function, as it creates an alloca for the landingpad.
    fn get_landing_pad<'a>(fcx: &FunctionContext<'a, 'tcx>, drop_val: &DropValue<'tcx>)
        -> BasicBlockRef {
        debug!("get_landing_pad");

        let mut pad_bcx = fcx.build_new_block("unwind_custom_");

        let llpersonality = pad_bcx.fcx().eh_personality();

        let resume_bcx = fcx.build_new_block("resume");
        let val = if base::wants_msvc_seh(fcx.ccx.sess()) {
            // A cleanup pad requires a personality function to be specified, so
            // we do that here explicitly (happens implicitly below through
            // creation of the landingpad instruction). We then create a
            // cleanuppad instruction which has no filters to run cleanup on all
            // exceptions.
            pad_bcx.set_personality_fn(llpersonality);
            let llretval = pad_bcx.cleanup_pad(None, &[]);
            resume_bcx.cleanup_ret(resume_bcx.cleanup_pad(None, &[]), None);
            UnwindKind::CleanupPad(llretval)
        } else {
            // The landing pad return type (the type being propagated). Not sure
            // what this represents but it's determined by the personality
            // function and this is what the EH proposal example uses.
            let llretty = Type::struct_(fcx.ccx, &[Type::i8p(fcx.ccx), Type::i32(fcx.ccx)], false);

            // The only landing pad clause will be 'cleanup'
            let llretval = pad_bcx.landing_pad(llretty, llpersonality, 1, pad_bcx.fcx().llfn);

            // The landing pad block is a cleanup
            pad_bcx.set_cleanup(llretval);

            let addr = pad_bcx.fcx().alloca(common::val_ty(llretval), "");
            Lifetime::Start.call(&pad_bcx, addr);
            pad_bcx.store(llretval, addr);
            let lp = resume_bcx.load(addr);
            Lifetime::End.call(&resume_bcx, addr);
            if !resume_bcx.sess().target.target.options.custom_unwind_resume {
                resume_bcx.resume(lp);
            } else {
                let exc_ptr = resume_bcx.extract_value(lp, 0);
                resume_bcx.call(fcx.eh_unwind_resume().reify(fcx.ccx), &[exc_ptr], None);
            }
            UnwindKind::LandingPad
        };

        let mut cleanup = fcx.build_new_block("clean_custom_");

        // Insert cleanup instructions into the cleanup block
        let funclet = match val {
            UnwindKind::CleanupPad(_) => Some(Funclet::new(cleanup.cleanup_pad(None, &[]))),
            UnwindKind::LandingPad => None,
        };
        drop_val.trans(funclet.as_ref(), &cleanup);

        // Insert instruction into cleanup block to branch to the exit
        val.branch(&mut cleanup, resume_bcx.llbb());

        // Branch into the cleanup block
        val.branch(&mut pad_bcx, cleanup.llbb());

        return pad_bcx.llbb();
    }
}
<commit_msg>Move get_landing_pad onto DropVal.<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! ## The Cleanup module
//!
//! The cleanup module tracks what values need to be cleaned up as scopes
//! are exited, either via panic or just normal control flow.
//!
//! Cleanup items can be scheduled into any of the scopes on the stack.
//! Typically, when a scope is finished, we generate the cleanup code. This
//! corresponds to a normal exit from a block (for example, an expression
//! completing evaluation successfully without panic).

use llvm::{BasicBlockRef, ValueRef};
use base::{self, Lifetime};
use common;
use common::{BlockAndBuilder, FunctionContext, Funclet};
use glue;
use type_::Type;
use value::Value;
use rustc::ty::Ty;

pub struct CleanupScope<'tcx> {
    // Cleanup to run upon scope exit.
    cleanup: Option<DropValue<'tcx>>,

    // Computed on creation if compiling with landing pads (!sess.no_landing_pads)
    pub landing_pad: Option<BasicBlockRef>,
}

#[derive(Copy, Clone)]
pub struct DropValue<'tcx> {
    val: ValueRef,
    ty: Ty<'tcx>,
    skip_dtor: bool,
}

impl<'tcx> DropValue<'tcx> {
    fn trans<'a>(&self, funclet: Option<&'a Funclet>, bcx: &BlockAndBuilder<'a, 'tcx>) {
        glue::call_drop_glue(bcx, self.val, self.ty, self.skip_dtor, funclet)
    }

    /// Creates a landing pad for the top scope. The landing pad will perform all cleanups necessary
    /// for an unwind and then `resume` to continue error propagation:
    ///
    ///     landing_pad -> ... cleanups ... -> [resume]
    ///
    /// This should only be called once per function, as it creates an alloca for the landingpad.
    fn get_landing_pad<'a>(&self, fcx: &FunctionContext<'a, 'tcx>) -> BasicBlockRef {
        debug!("get_landing_pad");

        let mut pad_bcx = fcx.build_new_block("unwind_custom_");

        let llpersonality = pad_bcx.fcx().eh_personality();

        let resume_bcx = fcx.build_new_block("resume");
        let val = if base::wants_msvc_seh(fcx.ccx.sess()) {
            // A cleanup pad requires a personality function to be specified, so
            // we do that here explicitly (happens implicitly below through
            // creation of the landingpad instruction). We then create a
            // cleanuppad instruction which has no filters to run cleanup on all
            // exceptions.
            pad_bcx.set_personality_fn(llpersonality);
            let llretval = pad_bcx.cleanup_pad(None, &[]);
            resume_bcx.cleanup_ret(resume_bcx.cleanup_pad(None, &[]), None);
            UnwindKind::CleanupPad(llretval)
        } else {
            // The landing pad return type (the type being propagated). Not sure
            // what this represents but it's determined by the personality
            // function and this is what the EH proposal example uses.
            let llretty = Type::struct_(fcx.ccx, &[Type::i8p(fcx.ccx), Type::i32(fcx.ccx)], false);

            // The only landing pad clause will be 'cleanup'
            let llretval = pad_bcx.landing_pad(llretty, llpersonality, 1, pad_bcx.fcx().llfn);

            // The landing pad block is a cleanup
            pad_bcx.set_cleanup(llretval);

            let addr = pad_bcx.fcx().alloca(common::val_ty(llretval), "");
            Lifetime::Start.call(&pad_bcx, addr);
            pad_bcx.store(llretval, addr);
            let lp = resume_bcx.load(addr);
            Lifetime::End.call(&resume_bcx, addr);
            if !resume_bcx.sess().target.target.options.custom_unwind_resume {
                resume_bcx.resume(lp);
            } else {
                let exc_ptr = resume_bcx.extract_value(lp, 0);
                resume_bcx.call(fcx.eh_unwind_resume().reify(fcx.ccx), &[exc_ptr], None);
            }
            UnwindKind::LandingPad
        };

        let mut cleanup = fcx.build_new_block("clean_custom_");

        // Insert cleanup instructions into the cleanup block
        let funclet = match val {
            UnwindKind::CleanupPad(_) => Some(Funclet::new(cleanup.cleanup_pad(None, &[]))),
            UnwindKind::LandingPad => None,
        };
        self.trans(funclet.as_ref(), &cleanup);

        // Insert instruction into cleanup block to branch to the exit
        val.branch(&mut cleanup, resume_bcx.llbb());

        // Branch into the cleanup block
        val.branch(&mut pad_bcx, cleanup.llbb());

        pad_bcx.llbb()
    }
}

#[derive(Copy, Clone, Debug)]
enum UnwindKind {
    LandingPad,
    CleanupPad(ValueRef),
}

impl UnwindKind {
    /// Generates a branch going from `bcx` to `to_llbb` where `self` is
    /// the exit label attached to the start of `bcx`.
    ///
    /// Transitions from an exit label to other exit labels depend on the type
    /// of label. For example with MSVC exceptions unwind exit labels will use
    /// the `cleanupret` instruction instead of the `br` instruction.
    fn branch(&self, bcx: &BlockAndBuilder, to_llbb: BasicBlockRef) {
        match *self {
            UnwindKind::CleanupPad(pad) => {
                bcx.cleanup_ret(pad, Some(to_llbb));
            }
            UnwindKind::LandingPad => {
                bcx.br(to_llbb);
            }
        }
    }
}

impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
    /// Schedules a (deep) drop of `val`, which is a pointer to an instance of `ty`
    pub fn schedule_drop_mem(&self, val: ValueRef, ty: Ty<'tcx>) -> CleanupScope<'tcx> {
        if !self.ccx.shared().type_needs_drop(ty) { return CleanupScope::noop(); }
        let drop = DropValue {
            val: val,
            ty: ty,
            skip_dtor: false,
        };

        debug!("schedule_drop_mem(val={:?}, ty={:?}) skip_dtor={}", Value(val), ty, drop.skip_dtor);

        CleanupScope::new(self, drop)
    }

    /// Issue #23611: Schedules a (deep) drop of the contents of
    /// `val`, which is a pointer to an instance of struct/enum type
    /// `ty`. The scheduled code handles extracting the discriminant
    /// and dropping the contents associated with that variant
    /// *without* executing any associated drop implementation.
    pub fn schedule_drop_adt_contents(&self, val: ValueRef, ty: Ty<'tcx>) -> CleanupScope<'tcx> {
        // `if` below could be "!contents_needs_drop"; skipping drop
        // is just an optimization, so sound to be conservative.
        if !self.ccx.shared().type_needs_drop(ty) { return CleanupScope::noop(); }

        let drop = DropValue {
            val: val,
            ty: ty,
            skip_dtor: true,
        };

        debug!("schedule_drop_adt_contents(val={:?}, ty={:?}) skip_dtor={}",
               Value(val), ty, drop.skip_dtor);

        CleanupScope::new(self, drop)
    }
}

impl<'tcx> CleanupScope<'tcx> {
    fn new<'a>(fcx: &FunctionContext<'a, 'tcx>, drop_val: DropValue<'tcx>) -> CleanupScope<'tcx> {
        CleanupScope {
            cleanup: Some(drop_val),
            landing_pad: if !fcx.ccx.sess().no_landing_pads() {
                Some(drop_val.get_landing_pad(fcx))
            } else {
                None
            },
        }
    }

    pub fn noop() -> CleanupScope<'tcx> {
        CleanupScope {
            cleanup: None,
            landing_pad: None,
        }
    }

    pub fn trans<'a>(self, bcx: &'a BlockAndBuilder<'a, 'tcx>) {
        if let Some(cleanup) = self.cleanup {
            cleanup.trans(None, &bcx);
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fmt;
use std::io;

use externalfiles::ExternalHtml;

#[deriving(Clone)]
pub struct Layout {
    pub logo: String,
    pub favicon: String,
    pub external_html: ExternalHtml,
    pub krate: String,
    pub playground_url: String,
}

pub struct Page<'a> {
    pub title: &'a str,
    pub ty: &'a str,
    pub root_path: &'a str,
    pub description: &'a str,
    pub keywords: &'a str
}

pub fn render<T: fmt::Show, S: fmt::Show>(
    dst: &mut io::Writer, layout: &Layout, page: &Page, sidebar: &S, t: &T)
    -> io::IoResult<()>
{
    write!(dst,
r##"<!DOCTYPE html>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="generator" content="rustdoc">
    <meta name="description" content="{description}">
    <meta name="keywords" content="{keywords}">

    <title>{title}</title>

    <link rel="stylesheet" type="text/css" href="{root_path}main.css">

    {favicon}
    {in_header}

    {before_content}

        {logo}
        {sidebar}

        <form class="search-form js-only">

                <input class="search-input" name="search"
                       autocomplete="off"
                       placeholder="Click or press 'S' to search, '?' for more options..."
                       type="search">

        </form>

{content}

Keyboard shortcuts

?

Show this help dialog

S

Focus the search field

⇤

Move up in search results

⇥

Move down in search results

⏎

Go to active search result

Search tricks

                Prefix searches with a type followed by a colon (e.g.
                fn:) to restrict the search to a given type.

                Accepted types are: fn, mod,
                struct, enum,
                trait, typedef (or
                tdef).

    {after_content}

    {play_js}

"##,
    content   = *t,
    root_path = page.root_path,
    ty        = page.ty,
    logo      = if layout.logo.len() == 0 {
        "".to_string()
    } else {
        format!("\
                 ",
                page.root_path, layout.krate,
                layout.logo)
    },
    title     = page.title,
    description = page.description,
    keywords = page.keywords,
    favicon   = if layout.favicon.len() == 0 {
        "".to_string()
    } else {
        format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon)
    },
    in_header = layout.external_html.in_header,
    before_content = layout.external_html.before_content,
    after_content = layout.external_html.after_content,
    sidebar   = *sidebar,
    krate     = layout.krate,
    play_url  = layout.playground_url,
    play_js   = if layout.playground_url.len() == 0 {
        "".to_string()
    } else {
        format!(r#""#, page.root_path)
    },
    )
}

pub fn redirect(dst: &mut io::Writer, url: &str) -> io::IoResult<()> {
    write!(dst,
r##"<!DOCTYPE html>

    <meta http-equiv="refresh" content="0;URL={url}">

"##,
    url = url,
    )
}
<commit_msg>rustdoc: Preserve query/fragment in redirects whenever possible.<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::fmt;
use std::io;

use externalfiles::ExternalHtml;

#[deriving(Clone)]
pub struct Layout {
    pub logo: String,
    pub favicon: String,
    pub external_html: ExternalHtml,
    pub krate: String,
    pub playground_url: String,
}

pub struct Page<'a> {
    pub title: &'a str,
    pub ty: &'a str,
    pub root_path: &'a str,
    pub description: &'a str,
    pub keywords: &'a str
}

pub fn render<T: fmt::Show, S: fmt::Show>(
    dst: &mut io::Writer, layout: &Layout, page: &Page, sidebar: &S, t: &T)
    -> io::IoResult<()>
{
    write!(dst,
r##"<!DOCTYPE html>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="generator" content="rustdoc">
    <meta name="description" content="{description}">
    <meta name="keywords" content="{keywords}">

    <title>{title}</title>

    <link rel="stylesheet" type="text/css" href="{root_path}main.css">

    {favicon}
    {in_header}

    {before_content}

        {logo}
        {sidebar}

        <form class="search-form js-only">

                <input class="search-input" name="search"
                       autocomplete="off"
                       placeholder="Click or press 'S' to search, '?' for more options..."
                       type="search">

        </form>

{content}

Keyboard shortcuts

?

Show this help dialog

S

Focus the search field

⇤

Move up in search results

⇥

Move down in search results

⏎

Go to active search result

Search tricks

                Prefix searches with a type followed by a colon (e.g.
                fn:) to restrict the search to a given type.

                Accepted types are: fn, mod,
                struct, enum,
                trait, typedef (or
                tdef).

    {after_content}

    {play_js}

"##,
    content   = *t,
    root_path = page.root_path,
    ty        = page.ty,
    logo      = if layout.logo.len() == 0 {
        "".to_string()
    } else {
        format!("\
                 ",
                page.root_path, layout.krate,
                layout.logo)
    },
    title     = page.title,
    description = page.description,
    keywords = page.keywords,
    favicon   = if layout.favicon.len() == 0 {
        "".to_string()
    } else {
        format!(r#"<link rel="shortcut icon" href="{}">"#, layout.favicon)
    },
    in_header = layout.external_html.in_header,
    before_content = layout.external_html.before_content,
    after_content = layout.external_html.after_content,
    sidebar   = *sidebar,
    krate     = layout.krate,
    play_url  = layout.playground_url,
    play_js   = if layout.playground_url.len() == 0 {
        "".to_string()
    } else {
        format!(r#""#, page.root_path)
    },
    )
}

pub fn redirect(dst: &mut io::Writer, url: &str) -> io::IoResult<()> {
    //

"##,
    url = url,
    )
}
<|endoftext|>


<commit_before>//! Tools to work with format string literals for the `format_args!` family of macros.
use syntax::{
    ast::{self, IsString},
    AstNode, AstToken, TextRange,
};

pub fn is_format_string(string: &ast::String) -> bool {
    // Check if `string` is a format string argument of a macro invocation.
    // `string` is a string literal, mapped down into the innermost macro expansion.
    // Since `format_args!` etc. remove the format string when expanding, but place all arguments
    // in the expanded output, we know that the string token is (part of) the format string if it
    // appears in `format_args!` (otherwise it would have been mapped down further).
    //
    // This setup lets us correctly highlight the components of `concat!("{}", "bla")` format
    // strings. It still fails for `concat!("{", "}")`, but that is rare.
    format!("{string} {bar}", bar = string);
    (|| {
        let macro_call = string.syntax().ancestors().find_map(ast::MacroCall::cast)?;
        let name = macro_call.path()?.segment()?.name_ref()?;

        if !matches!(
            name.text().as_str(),
            "format_args" | "format_args_nl" | "const_format_args" | "panic_2015" | "panic_2021"
        ) {
            return None;
        }

        // NB: we match against `panic_2015`/`panic_2021` here because they have a special-cased arm for
        // `"{}"`, which otherwise wouldn't get highlighted.

        Some(())
    })()
    .is_some()
}

#[derive(Debug)]
pub enum FormatSpecifier {
    Open,
    Close,
    Integer,
    Identifier,
    Colon,
    Fill,
    Align,
    Sign,
    NumberSign,
    Zero,
    DollarSign,
    Dot,
    Asterisk,
    QuestionMark,
}

pub fn lex_format_specifiers(
    string: &ast::String,
    mut callback: &mut dyn FnMut(TextRange, FormatSpecifier),
) {
    let mut char_ranges = Vec::new();
    string.escaped_char_ranges(&mut |range, res| char_ranges.push((range, res)));
    let mut chars = char_ranges
        .iter()
        .filter_map(|(range, res)| Some((*range, *res.as_ref().ok()?)))
        .peekable();

    while let Some((range, first_char)) = chars.next() {
        if let '{' = first_char {
            // Format specifier, see syntax at https://doc.rust-lang.org/std/fmt/index.html#syntax
            if let Some((_, '{')) = chars.peek() {
                // Escaped format specifier, `{{`
                chars.next();
                continue;
            }

            callback(range, FormatSpecifier::Open);

            // check for integer/identifier
            let (_, int_char) = chars.peek().copied().unwrap_or_default();
            match int_char {
                // integer
                '0'..='9' => read_integer(&mut chars, &mut callback),
                // identifier
                c if c == '_' || c.is_alphabetic() => read_identifier(&mut chars, &mut callback),
                _ => {}
            }

            if let Some((_, ':')) = chars.peek() {
                skip_char_and_emit(&mut chars, FormatSpecifier::Colon, &mut callback);

                // check for fill/align
                let mut cloned = chars.clone().take(2);
                let (_, first) = cloned.next().unwrap_or_default();
                let (_, second) = cloned.next().unwrap_or_default();
                match second {
                    '<' | '^' | '>' => {
                        // alignment specifier, first char specifies fillment
                        skip_char_and_emit(&mut chars, FormatSpecifier::Fill, &mut callback);
                        skip_char_and_emit(&mut chars, FormatSpecifier::Align, &mut callback);
                    }
                    _ => {
                        if let '<' | '^' | '>' = first {
                            skip_char_and_emit(&mut chars, FormatSpecifier::Align, &mut callback);
                        }
                    }
                }

                // check for sign
                match chars.peek().copied().unwrap_or_default().1 {
                    '+' | '-' => {
                        skip_char_and_emit(&mut chars, FormatSpecifier::Sign, &mut callback);
                    }
                    _ => {}
                }

                // check for `#`
                if let Some((_, '#')) = chars.peek() {
                    skip_char_and_emit(&mut chars, FormatSpecifier::NumberSign, &mut callback);
                }

                // check for `0`
                let mut cloned = chars.clone().take(2);
                let first = cloned.next().map(|next| next.1);
                let second = cloned.next().map(|next| next.1);

                if first == Some('0') && second != Some('$') {
                    skip_char_and_emit(&mut chars, FormatSpecifier::Zero, &mut callback);
                }

                // width
                match chars.peek().copied().unwrap_or_default().1 {
                    '0'..='9' => {
                        read_integer(&mut chars, &mut callback);
                        if let Some((_, '$')) = chars.peek() {
                            skip_char_and_emit(
                                &mut chars,
                                FormatSpecifier::DollarSign,
                                &mut callback,
                            );
                        }
                    }
                    c if c == '_' || c.is_alphabetic() => {
                        read_identifier(&mut chars, &mut callback);

                        if chars.peek().map(|&(_, c)| c) == Some('?') {
                            skip_char_and_emit(
                                &mut chars,
                                FormatSpecifier::QuestionMark,
                                &mut callback,
                            );
                        }

                        // can be either width (indicated by dollar sign, or type in which case
                        // the next sign has to be `}`)
                        let next = chars.peek().map(|&(_, c)| c);

                        match next {
                            Some('$') => skip_char_and_emit(
                                &mut chars,
                                FormatSpecifier::DollarSign,
                                &mut callback,
                            ),
                            Some('}') => {
                                skip_char_and_emit(
                                    &mut chars,
                                    FormatSpecifier::Close,
                                    &mut callback,
                                );
                                continue;
                            }
                            _ => continue,
                        };
                    }
                    _ => {}
                }

                // precision
                if let Some((_, '.')) = chars.peek() {
                    skip_char_and_emit(&mut chars, FormatSpecifier::Dot, &mut callback);

                    match chars.peek().copied().unwrap_or_default().1 {
                        '*' => {
                            skip_char_and_emit(
                                &mut chars,
                                FormatSpecifier::Asterisk,
                                &mut callback,
                            );
                        }
                        '0'..='9' => {
                            read_integer(&mut chars, &mut callback);
                            if let Some((_, '$')) = chars.peek() {
                                skip_char_and_emit(
                                    &mut chars,
                                    FormatSpecifier::DollarSign,
                                    &mut callback,
                                );
                            }
                        }
                        c if c == '_' || c.is_alphabetic() => {
                            read_identifier(&mut chars, &mut callback);
                            if chars.peek().map(|&(_, c)| c) != Some('$') {
                                continue;
                            }
                            skip_char_and_emit(
                                &mut chars,
                                FormatSpecifier::DollarSign,
                                &mut callback,
                            );
                        }
                        _ => {
                            continue;
                        }
                    }
                }

                // type
                match chars.peek().copied().unwrap_or_default().1 {
                    '?' => {
                        skip_char_and_emit(
                            &mut chars,
                            FormatSpecifier::QuestionMark,
                            &mut callback,
                        );
                    }
                    c if c == '_' || c.is_alphabetic() => {
                        read_identifier(&mut chars, &mut callback);

                        if chars.peek().map(|&(_, c)| c) == Some('?') {
                            skip_char_and_emit(
                                &mut chars,
                                FormatSpecifier::QuestionMark,
                                &mut callback,
                            );
                        }
                    }
                    _ => {}
                }
            }

            if let Some((_, '}')) = chars.peek() {
                skip_char_and_emit(&mut chars, FormatSpecifier::Close, &mut callback);
            }
            continue;
        }
    }

    fn skip_char_and_emit<I, F>(
        chars: &mut std::iter::Peekable<I>,
        emit: FormatSpecifier,
        callback: &mut F,
    ) where
        I: Iterator<Item = (TextRange, char)>,
        F: FnMut(TextRange, FormatSpecifier),
    {
        let (range, _) = chars.next().unwrap();
        callback(range, emit);
    }

    fn read_integer<I, F>(chars: &mut std::iter::Peekable<I>, callback: &mut F)
    where
        I: Iterator<Item = (TextRange, char)>,
        F: FnMut(TextRange, FormatSpecifier),
    {
        let (mut range, c) = chars.next().unwrap();
        assert!(c.is_ascii_digit());
        while let Some(&(r, next_char)) = chars.peek() {
            if next_char.is_ascii_digit() {
                chars.next();
                range = range.cover(r);
            } else {
                break;
            }
        }
        callback(range, FormatSpecifier::Integer);
    }

    fn read_identifier<I, F>(chars: &mut std::iter::Peekable<I>, callback: &mut F)
    where
        I: Iterator<Item = (TextRange, char)>,
        F: FnMut(TextRange, FormatSpecifier),
    {
        let (mut range, c) = chars.next().unwrap();
        assert!(c.is_alphabetic() || c == '_');
        while let Some(&(r, next_char)) = chars.peek() {
            if next_char == '_' || next_char.is_ascii_digit() || next_char.is_alphabetic() {
                chars.next();
                range = range.cover(r);
            } else {
                break;
            }
        }
        callback(range, FormatSpecifier::Identifier);
    }
}
<commit_msg>Remove spurious format<commit_after>//! Tools to work with format string literals for the `format_args!` family of macros.
use syntax::{
    ast::{self, IsString},
    AstNode, AstToken, TextRange,
};

pub fn is_format_string(string: &ast::String) -> bool {
    // Check if `string` is a format string argument of a macro invocation.
    // `string` is a string literal, mapped down into the innermost macro expansion.
    // Since `format_args!` etc. remove the format string when expanding, but place all arguments
    // in the expanded output, we know that the string token is (part of) the format string if it
    // appears in `format_args!` (otherwise it would have been mapped down further).
    //
    // This setup lets us correctly highlight the components of `concat!("{}", "bla")` format
    // strings. It still fails for `concat!("{", "}")`, but that is rare.
    (|| {
        let macro_call = string.syntax().ancestors().find_map(ast::MacroCall::cast)?;
        let name = macro_call.path()?.segment()?.name_ref()?;

        if !matches!(
            name.text().as_str(),
            "format_args" | "format_args_nl" | "const_format_args" | "panic_2015" | "panic_2021"
        ) {
            return None;
        }

        // NB: we match against `panic_2015`/`panic_2021` here because they have a special-cased arm for
        // `"{}"`, which otherwise wouldn't get highlighted.

        Some(())
    })()
    .is_some()
}

#[derive(Debug)]
pub enum FormatSpecifier {
    Open,
    Close,
    Integer,
    Identifier,
    Colon,
    Fill,
    Align,
    Sign,
    NumberSign,
    Zero,
    DollarSign,
    Dot,
    Asterisk,
    QuestionMark,
}

pub fn lex_format_specifiers(
    string: &ast::String,
    mut callback: &mut dyn FnMut(TextRange, FormatSpecifier),
) {
    let mut char_ranges = Vec::new();
    string.escaped_char_ranges(&mut |range, res| char_ranges.push((range, res)));
    let mut chars = char_ranges
        .iter()
        .filter_map(|(range, res)| Some((*range, *res.as_ref().ok()?)))
        .peekable();

    while let Some((range, first_char)) = chars.next() {
        if let '{' = first_char {
            // Format specifier, see syntax at https://doc.rust-lang.org/std/fmt/index.html#syntax
            if let Some((_, '{')) = chars.peek() {
                // Escaped format specifier, `{{`
                chars.next();
                continue;
            }

            callback(range, FormatSpecifier::Open);

            // check for integer/identifier
            let (_, int_char) = chars.peek().copied().unwrap_or_default();
            match int_char {
                // integer
                '0'..='9' => read_integer(&mut chars, &mut callback),
                // identifier
                c if c == '_' || c.is_alphabetic() => read_identifier(&mut chars, &mut callback),
                _ => {}
            }

            if let Some((_, ':')) = chars.peek() {
                skip_char_and_emit(&mut chars, FormatSpecifier::Colon, &mut callback);

                // check for fill/align
                let mut cloned = chars.clone().take(2);
                let (_, first) = cloned.next().unwrap_or_default();
                let (_, second) = cloned.next().unwrap_or_default();
                match second {
                    '<' | '^' | '>' => {
                        // alignment specifier, first char specifies fillment
                        skip_char_and_emit(&mut chars, FormatSpecifier::Fill, &mut callback);
                        skip_char_and_emit(&mut chars, FormatSpecifier::Align, &mut callback);
                    }
                    _ => {
                        if let '<' | '^' | '>' = first {
                            skip_char_and_emit(&mut chars, FormatSpecifier::Align, &mut callback);
                        }
                    }
                }

                // check for sign
                match chars.peek().copied().unwrap_or_default().1 {
                    '+' | '-' => {
                        skip_char_and_emit(&mut chars, FormatSpecifier::Sign, &mut callback);
                    }
                    _ => {}
                }

                // check for `#`
                if let Some((_, '#')) = chars.peek() {
                    skip_char_and_emit(&mut chars, FormatSpecifier::NumberSign, &mut callback);
                }

                // check for `0`
                let mut cloned = chars.clone().take(2);
                let first = cloned.next().map(|next| next.1);
                let second = cloned.next().map(|next| next.1);

                if first == Some('0') && second != Some('$') {
                    skip_char_and_emit(&mut chars, FormatSpecifier::Zero, &mut callback);
                }

                // width
                match chars.peek().copied().unwrap_or_default().1 {
                    '0'..='9' => {
                        read_integer(&mut chars, &mut callback);
                        if let Some((_, '$')) = chars.peek() {
                            skip_char_and_emit(
                                &mut chars,
                                FormatSpecifier::DollarSign,
                                &mut callback,
                            );
                        }
                    }
                    c if c == '_' || c.is_alphabetic() => {
                        read_identifier(&mut chars, &mut callback);

                        if chars.peek().map(|&(_, c)| c) == Some('?') {
                            skip_char_and_emit(
                                &mut chars,
                                FormatSpecifier::QuestionMark,
                                &mut callback,
                            );
                        }

                        // can be either width (indicated by dollar sign, or type in which case
                        // the next sign has to be `}`)
                        let next = chars.peek().map(|&(_, c)| c);

                        match next {
                            Some('$') => skip_char_and_emit(
                                &mut chars,
                                FormatSpecifier::DollarSign,
                                &mut callback,
                            ),
                            Some('}') => {
                                skip_char_and_emit(
                                    &mut chars,
                                    FormatSpecifier::Close,
                                    &mut callback,
                                );
                                continue;
                            }
                            _ => continue,
                        };
                    }
                    _ => {}
                }

                // precision
                if let Some((_, '.')) = chars.peek() {
                    skip_char_and_emit(&mut chars, FormatSpecifier::Dot, &mut callback);

                    match chars.peek().copied().unwrap_or_default().1 {
                        '*' => {
                            skip_char_and_emit(
                                &mut chars,
                                FormatSpecifier::Asterisk,
                                &mut callback,
                            );
                        }
                        '0'..='9' => {
                            read_integer(&mut chars, &mut callback);
                            if let Some((_, '$')) = chars.peek() {
                                skip_char_and_emit(
                                    &mut chars,
                                    FormatSpecifier::DollarSign,
                                    &mut callback,
                                );
                            }
                        }
                        c if c == '_' || c.is_alphabetic() => {
                            read_identifier(&mut chars, &mut callback);
                            if chars.peek().map(|&(_, c)| c) != Some('$') {
                                continue;
                            }
                            skip_char_and_emit(
                                &mut chars,
                                FormatSpecifier::DollarSign,
                                &mut callback,
                            );
                        }
                        _ => {
                            continue;
                        }
                    }
                }

                // type
                match chars.peek().copied().unwrap_or_default().1 {
                    '?' => {
                        skip_char_and_emit(
                            &mut chars,
                            FormatSpecifier::QuestionMark,
                            &mut callback,
                        );
                    }
                    c if c == '_' || c.is_alphabetic() => {
                        read_identifier(&mut chars, &mut callback);

                        if chars.peek().map(|&(_, c)| c) == Some('?') {
                            skip_char_and_emit(
                                &mut chars,
                                FormatSpecifier::QuestionMark,
                                &mut callback,
                            );
                        }
                    }
                    _ => {}
                }
            }

            if let Some((_, '}')) = chars.peek() {
                skip_char_and_emit(&mut chars, FormatSpecifier::Close, &mut callback);
            }
            continue;
        }
    }

    fn skip_char_and_emit<I, F>(
        chars: &mut std::iter::Peekable<I>,
        emit: FormatSpecifier,
        callback: &mut F,
    ) where
        I: Iterator<Item = (TextRange, char)>,
        F: FnMut(TextRange, FormatSpecifier),
    {
        let (range, _) = chars.next().unwrap();
        callback(range, emit);
    }

    fn read_integer<I, F>(chars: &mut std::iter::Peekable<I>, callback: &mut F)
    where
        I: Iterator<Item = (TextRange, char)>,
        F: FnMut(TextRange, FormatSpecifier),
    {
        let (mut range, c) = chars.next().unwrap();
        assert!(c.is_ascii_digit());
        while let Some(&(r, next_char)) = chars.peek() {
            if next_char.is_ascii_digit() {
                chars.next();
                range = range.cover(r);
            } else {
                break;
            }
        }
        callback(range, FormatSpecifier::Integer);
    }

    fn read_identifier<I, F>(chars: &mut std::iter::Peekable<I>, callback: &mut F)
    where
        I: Iterator<Item = (TextRange, char)>,
        F: FnMut(TextRange, FormatSpecifier),
    {
        let (mut range, c) = chars.next().unwrap();
        assert!(c.is_alphabetic() || c == '_');
        while let Some(&(r, next_char)) = chars.peek() {
            if next_char == '_' || next_char.is_ascii_digit() || next_char.is_alphabetic() {
                chars.next();
                range = range.cover(r);
            } else {
                break;
            }
        }
        callback(range, FormatSpecifier::Identifier);
    }
}
<|endoftext|>


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

#[crate_id = "github.com/mozilla-servo/rust-cssparser#cssparser:0.1"];
#[feature(globs, macro_rules)];
#[crate_type = "lib"];
#[crate_type = "dylib"];
#[crate_type = "rlib"];

extern crate encoding;  // https://github.com/lifthrasiir/rust-encoding

#[cfg(test)]
extern crate test;

#[cfg(test)]
extern crate serialize;

pub use tokenizer::tokenize;
pub use parser::{parse_stylesheet_rules, parse_rule_list, parse_declaration_list,
                 parse_one_rule, parse_one_declaration, parse_one_component_value};
pub use from_bytes::{decode_stylesheet_bytes, parse_stylesheet_rules_from_bytes};
pub use color::{RGBA, Color, CurrentColor};
pub use nth::parse_nth;
pub use serializer::{ToCss, serialize_identifier, serialize_string};

pub mod ast;
mod tokenizer;
mod parser;
mod from_bytes;
mod color;
mod nth;
mod serializer;

#[cfg(test)]
mod tests;
<commit_msg>Update to current rust: use the new attributes syntax.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#![crate_id = "github.com/mozilla-servo/rust-cssparser#cssparser:0.1"]
#![crate_type = "lib"]
#![crate_type = "dylib"]
#![crate_type = "rlib"]

#![feature(globs, macro_rules)]

extern crate encoding;  // https://github.com/lifthrasiir/rust-encoding

#[cfg(test)]
extern crate test;

#[cfg(test)]
extern crate serialize;

pub use tokenizer::tokenize;
pub use parser::{parse_stylesheet_rules, parse_rule_list, parse_declaration_list,
                 parse_one_rule, parse_one_declaration, parse_one_component_value};
pub use from_bytes::{decode_stylesheet_bytes, parse_stylesheet_rules_from_bytes};
pub use color::{RGBA, Color, CurrentColor};
pub use nth::parse_nth;
pub use serializer::{ToCss, serialize_identifier, serialize_string};

pub mod ast;
mod tokenizer;
mod parser;
mod from_bytes;
mod color;
mod nth;
mod serializer;

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>#![crate_name = "rustic"]
#![allow(ctypes)]
#![feature(globs)]
#![feature(lang_items)]
#![crate_type="lib"]
#![no_std]

extern crate core;

#[allow(dead_code)]
#[path = "arch/x86/"]
mod platform {
  pub mod drivers;
  pub mod io;
}

pub mod kernel;

#[lang = "begin_unwind"]
extern fn begin_unwind(args: &core::fmt::Arguments, file: &str, line: uint) -> ! {
  loop {}
}

#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}
<commit_msg>remove old hacks needed by older versions of rust<commit_after>#![crate_name = "rustic"]
#![crate_type = "lib"]
#![allow(ctypes)]
#![feature(globs)]
#![no_std]
extern crate core;

use platform::io;

#[path = "arch/x86/"]
mod platform {
  pub mod drivers;
  pub mod io;
}

pub mod kernel;
<|endoftext|>


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

use std::{borrow::Cow, cell::Cell, mem};

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use enum_primitive_derive::Primitive;
use failure::{self, ensure, format_err};
use num_traits::FromPrimitive;
use serde_derive::{Deserialize, Serialize};

use crate::{BinaryKey, BinaryValue};

use super::{IndexAccess, IndexAddress, View};

/// TODO Add documentation. [ECR-2820]
const INDEXES_POOL_NAME: &str = "__INDEXES_POOL__";
/// TODO Add documentation. [ECR-2820]
const INDEXES_POOL_LEN_NAME: &str = "INDEXES_POOL_LEN";

/// TODO Add documentation. [ECR-2820]
#[derive(Debug, Copy, Clone, PartialEq, Primitive, Serialize, Deserialize)]
#[repr(u32)]
pub enum IndexType {
    Map = 1,
    List = 2,
    Entry = 3,
    ValueSet = 4,
    KeySet = 5,
    SparseList = 6,
    ProofList = 7,
    ProofMap = 8,
    Unknown = 255,
}

/// TODO Add documentation. [ECR-2820]
pub trait BinaryAttribute {
    /// TODO Add documentation. [ECR-2820]
    fn size(&self) -> usize;
    /// TODO Add documentation. [ECR-2820]
    fn write<W: std::io::Write>(&self, buffer: &mut W);
    /// TODO Add documentation. [ECR-2820]
    fn read<R: std::io::Read>(buffer: &mut R) -> Self;
}

/// No-op implementation.
impl BinaryAttribute for () {
    fn size(&self) -> usize {
        0
    }

    fn write<W: std::io::Write>(&self, _buffer: &mut W) {}

    fn read<R: std::io::Read>(_buffer: &mut R) -> Self {}
}

impl BinaryAttribute for u64 {
    fn size(&self) -> usize {
        mem::size_of_val(self)
    }

    fn write<W: std::io::Write>(&self, buffer: &mut W) {
        buffer.write_u64::<LittleEndian>(*self).unwrap()
    }

    fn read<R: std::io::Read>(buffer: &mut R) -> Self {
        buffer.read_u64::<LittleEndian>().unwrap()
    }
}

impl Default for IndexType {
    fn default() -> Self {
        IndexType::Unknown
    }
}

/// TODO Add documentation. [ECR-2820]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct IndexMetadata<V> {
    identifier: u64,
    index_type: IndexType,
    state: V,
}

impl<V> BinaryValue for IndexMetadata<V>
where
    V: BinaryAttribute,
{
    fn to_bytes(&self) -> Vec<u8> {
        let state_len = self.state.size();
        let mut buf = Vec::with_capacity(
            mem::size_of_val(&self.identifier)
                + mem::size_of_val(&self.index_type)
                + mem::size_of::<u32>()
                + state_len,
        );

        buf.write_u64::<LittleEndian>(self.identifier).unwrap();
        buf.write_u32::<LittleEndian>(self.index_type as u32)
            .unwrap();
        buf.write_u32::<LittleEndian>(state_len as u32).unwrap();
        self.state.write(&mut buf);
        buf
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        let mut bytes = bytes.as_ref();

        let identifier = bytes.read_u64::<LittleEndian>()?;
        let index_type = bytes.read_u32::<LittleEndian>()?;
        let state_len = bytes.read_u32::<LittleEndian>()? as usize;

        ensure!(bytes.len() >= state_len, "Index state is too short");

        let mut state_bytes = &bytes[0..state_len];
        let state = V::read(&mut state_bytes);

        Ok(Self {
            identifier,
            index_type: IndexType::from_u32(index_type)
                .ok_or_else(|| format_err!("Unknown index type: {}", index_type))?,
            state,
        })
    }
}

impl<V> IndexMetadata<V> {
    fn index_address(&self) -> IndexAddress {
        IndexAddress::new().append_bytes(&self.identifier)
    }
}

impl IndexAddress {
    fn index_name(&self) -> Vec<u8> {
        if let Some(bytes) = self.bytes() {
            concat_keys!(self.name(), bytes)
        } else {
            concat_keys!(self.name())
        }
    }
}

/// TODO Add documentation. [ECR-2820]
pub fn index_metadata<T, V>(
    index_access: T,
    index_address: &IndexAddress,
    index_type: IndexType,
) -> (IndexAddress, IndexState<T, V>)
where
    T: IndexAccess,
    V: BinaryAttribute + Copy + Default,
{
    let index_name = index_address.index_name();

    let mut pool = IndexesPool::new(index_access);
    let metadata = if let Some(metadata) = pool.index_metadata(&index_name) {
        assert_eq!(
            metadata.index_type, index_type,
            "Index type doesn't match specified"
        );
        metadata
    } else {
        pool.set_index_metadata(&index_name, index_type)
    };

    let index_address = metadata.index_address();
    let index_state = IndexState::new(index_access, index_name, metadata);
    (index_address, index_state)
}

/// TODO Add documentation. [ECR-2820]
struct IndexesPool<T: IndexAccess>(View<T>);

impl<T: IndexAccess> IndexesPool<T> {
    fn new(index_access: T) -> Self {
        let pool_address = IndexAddress::from(INDEXES_POOL_NAME);
        Self(View::new(index_access, pool_address))
    }

    fn index_metadata<V>(&self, index_name: &[u8]) -> Option<IndexMetadata<V>>
    where
        V: BinaryAttribute + Default + Copy,
    {
        self.0.get(index_name)
    }

    fn set_index_metadata<V>(
        &mut self,
        index_name: &[u8],
        index_type: IndexType,
    ) -> IndexMetadata<V>
    where
        V: BinaryAttribute + Default + Copy,
    {
        let mut pool_len = View::new(
            self.0.index_access,
            IndexAddress::from(INDEXES_POOL_LEN_NAME),
        );
        let len: u64 = pool_len.get(&()).unwrap_or_default();

        let metadata = IndexMetadata {
            index_type,
            identifier: len,
            state: V::default(),
        };

        self.0.put(index_name, metadata);
        pool_len.put(&(), len + 1);
        metadata
    }
}

/// TODO Add documentation. [ECR-2820]
pub struct IndexState<T, V>
where
    V: BinaryAttribute + Default + Copy,
    T: IndexAccess,
{
    index_access: T,
    index_name: Vec<u8>,
    cache: Cell<IndexMetadata<V>>,
}

impl<T, V> IndexState<T, V>
where
    V: BinaryAttribute + Default + Copy,
    T: IndexAccess,
{
    pub fn new(index_access: T, index_name: Vec<u8>, metadata: IndexMetadata<V>) -> Self {
        Self {
            index_access,
            index_name,
            cache: Cell::new(metadata),
        }
    }

    /// TODO Add documentation. [ECR-2820]
    pub fn get(&self) -> V {
        self.cache.get().state
    }

    /// TODO Add documentation. [ECR-2820]
    pub fn set(&mut self, state: V) {
        let mut cache = self.cache.get_mut();
        cache.state = state;
        View::new(self.index_access, IndexAddress::from(INDEXES_POOL_NAME))
            .put(&self.index_name, *cache);
    }
}

impl<T, V> std::fmt::Debug for IndexState<T, V>
where
    T: IndexAccess,
    V: BinaryAttribute + Default + Copy,
{
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        f.debug_struct("IndexState").finish()
    }
}

#[cfg(test)]
mod tests {
    use crate::BinaryValue;

    use super::{IndexMetadata, IndexType};

    #[test]
    fn test_index_metadata_binary_value() {
        let metadata = IndexMetadata {
            identifier: 12,
            index_type: IndexType::ProofList,
            state: 16_u64,
        };

        let bytes = metadata.to_bytes();
        assert_eq!(IndexMetadata::from_bytes(bytes.into()).unwrap(), metadata);
    }
}
<commit_msg>Use RefCell instead of Cell<commit_after>// Copyright 2018 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::{borrow::Cow, cell::RefCell, mem};

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use enum_primitive_derive::Primitive;
use failure::{self, ensure, format_err};
use num_traits::FromPrimitive;
use serde_derive::{Deserialize, Serialize};

use crate::{BinaryKey, BinaryValue};

use super::{IndexAccess, IndexAddress, View};

/// TODO Add documentation. [ECR-2820]
const INDEXES_POOL_NAME: &str = "__INDEXES_POOL__";
/// TODO Add documentation. [ECR-2820]
const INDEXES_POOL_LEN_NAME: &str = "INDEXES_POOL_LEN";

/// TODO Add documentation. [ECR-2820]
#[derive(Debug, Copy, Clone, PartialEq, Primitive, Serialize, Deserialize)]
#[repr(u32)]
pub enum IndexType {
    Map = 1,
    List = 2,
    Entry = 3,
    ValueSet = 4,
    KeySet = 5,
    SparseList = 6,
    ProofList = 7,
    ProofMap = 8,
    Unknown = 255,
}

/// TODO Add documentation. [ECR-2820]
pub trait BinaryAttribute {
    /// TODO Add documentation. [ECR-2820]
    fn size(&self) -> usize;
    /// TODO Add documentation. [ECR-2820]
    fn write<W: std::io::Write>(&self, buffer: &mut W);
    /// TODO Add documentation. [ECR-2820]
    fn read<R: std::io::Read>(buffer: &mut R) -> Self;
}

/// No-op implementation.
impl BinaryAttribute for () {
    fn size(&self) -> usize {
        0
    }

    fn write<W: std::io::Write>(&self, _buffer: &mut W) {}

    fn read<R: std::io::Read>(_buffer: &mut R) -> Self {}
}

impl BinaryAttribute for u64 {
    fn size(&self) -> usize {
        mem::size_of_val(self)
    }

    fn write<W: std::io::Write>(&self, buffer: &mut W) {
        buffer.write_u64::<LittleEndian>(*self).unwrap()
    }

    fn read<R: std::io::Read>(buffer: &mut R) -> Self {
        buffer.read_u64::<LittleEndian>().unwrap()
    }
}

impl Default for IndexType {
    fn default() -> Self {
        IndexType::Unknown
    }
}

/// TODO Add documentation. [ECR-2820]
#[derive(Debug, Clone, PartialEq)]
pub struct IndexMetadata<V> {
    identifier: u64,
    index_type: IndexType,
    state: V,
}

impl<V> BinaryValue for IndexMetadata<V>
where
    V: BinaryAttribute,
{
    fn to_bytes(&self) -> Vec<u8> {
        let state_len = self.state.size();
        let mut buf = Vec::with_capacity(
            mem::size_of_val(&self.identifier)
                + mem::size_of_val(&self.index_type)
                + mem::size_of::<u32>()
                + state_len,
        );

        buf.write_u64::<LittleEndian>(self.identifier).unwrap();
        buf.write_u32::<LittleEndian>(self.index_type as u32)
            .unwrap();
        buf.write_u32::<LittleEndian>(state_len as u32).unwrap();
        self.state.write(&mut buf);
        buf
    }

    fn from_bytes(bytes: Cow<[u8]>) -> Result<Self, failure::Error> {
        let mut bytes = bytes.as_ref();

        let identifier = bytes.read_u64::<LittleEndian>()?;
        let index_type = bytes.read_u32::<LittleEndian>()?;
        let state_len = bytes.read_u32::<LittleEndian>()? as usize;

        ensure!(bytes.len() >= state_len, "Index state is too short");

        let mut state_bytes = &bytes[0..state_len];
        let state = V::read(&mut state_bytes);

        Ok(Self {
            identifier,
            index_type: IndexType::from_u32(index_type)
                .ok_or_else(|| format_err!("Unknown index type: {}", index_type))?,
            state,
        })
    }
}

impl<V> IndexMetadata<V> {
    fn index_address(&self) -> IndexAddress {
        IndexAddress::new().append_bytes(&self.identifier)
    }
}

impl IndexAddress {
    fn index_name(&self) -> Vec<u8> {
        if let Some(bytes) = self.bytes() {
            concat_keys!(self.name(), bytes)
        } else {
            concat_keys!(self.name())
        }
    }
}

/// TODO Add documentation. [ECR-2820]
pub fn index_metadata<T, V>(
    index_access: T,
    index_address: &IndexAddress,
    index_type: IndexType,
) -> (IndexAddress, IndexState<T, V>)
where
    T: IndexAccess,
    V: BinaryAttribute + Copy + Default,
{
    let index_name = index_address.index_name();

    let mut pool = IndexesPool::new(index_access);
    let metadata = if let Some(metadata) = pool.index_metadata(&index_name) {
        assert_eq!(
            metadata.index_type, index_type,
            "Index type doesn't match specified"
        );
        metadata
    } else {
        pool.set_index_metadata(&index_name, index_type)
    };

    let index_address = metadata.index_address();
    let index_state = IndexState::new(index_access, index_name, metadata);
    (index_address, index_state)
}

/// TODO Add documentation. [ECR-2820]
struct IndexesPool<T: IndexAccess>(View<T>);

impl<T: IndexAccess> IndexesPool<T> {
    fn new(index_access: T) -> Self {
        let pool_address = IndexAddress::from(INDEXES_POOL_NAME);
        Self(View::new(index_access, pool_address))
    }

    fn index_metadata<V>(&self, index_name: &[u8]) -> Option<IndexMetadata<V>>
    where
        V: BinaryAttribute + Default + Copy,
    {
        self.0.get(index_name)
    }

    fn set_index_metadata<V>(
        &mut self,
        index_name: &[u8],
        index_type: IndexType,
    ) -> IndexMetadata<V>
    where
        V: BinaryAttribute + Default + Copy,
    {
        let mut pool_len = View::new(
            self.0.index_access,
            IndexAddress::from(INDEXES_POOL_LEN_NAME),
        );
        let len: u64 = pool_len.get(&()).unwrap_or_default();

        let metadata = IndexMetadata {
            index_type,
            identifier: len,
            state: V::default(),
        };

        self.0.put(index_name, metadata.to_bytes());
        pool_len.put(&(), len + 1);
        metadata
    }
}

/// TODO Add documentation. [ECR-2820]
pub struct IndexState<T, V>
where
    V: BinaryAttribute + Default + Copy,
    T: IndexAccess,
{
    index_access: T,
    index_name: Vec<u8>,
    cache: RefCell<IndexMetadata<V>>,
}

impl<T, V> IndexState<T, V>
where
    V: BinaryAttribute + Default + Copy,
    T: IndexAccess,
{
    pub fn new(index_access: T, index_name: Vec<u8>, metadata: IndexMetadata<V>) -> Self {
        Self {
            index_access,
            index_name,
            cache: RefCell::new(metadata),
        }
    }

    /// TODO Add documentation. [ECR-2820]
    pub fn get(&self) -> V {
        self.cache.borrow().state
    }

    /// TODO Add documentation. [ECR-2820]
    pub fn set(&mut self, state: V) {
        let mut cache = self.cache.get_mut();
        cache.state = state;
        View::new(self.index_access, IndexAddress::from(INDEXES_POOL_NAME))
            .put(&self.index_name, cache.to_bytes());
    }
}

impl<T, V> std::fmt::Debug for IndexState<T, V>
where
    T: IndexAccess,
    V: BinaryAttribute + Default + Copy,
{
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        f.debug_struct("IndexState").finish()
    }
}

#[cfg(test)]
mod tests {
    use crate::BinaryValue;

    use super::{IndexMetadata, IndexType};

    #[test]
    fn test_index_metadata_binary_value() {
        let metadata = IndexMetadata {
            identifier: 12,
            index_type: IndexType::ProofList,
            state: 16_u64,
        };

        let bytes = metadata.to_bytes();
        assert_eq!(IndexMetadata::from_bytes(bytes.into()).unwrap(), metadata);
    }
}
<|endoftext|>


<commit_before>use byteorder::{LittleEndian, ReadBytesExt};
use serde_json;
use std::ffi::OsStr;
use std::io::{BufReader, ErrorKind as IoErrorKind, Read, Result as IoResult};
use std::process::{Child, Command, Stdio};
use super::{AudioSource, AudioType, DcaError, DcaMetadata, VoiceError};
use internal::prelude::*;

use std::fs::File;
use std::result::Result as StdResult;

struct ChildContainer(Child);

impl Read for ChildContainer {
    fn read(&mut self, buffer: &mut [u8]) -> IoResult<usize> {
        self.0.stdout.as_mut().unwrap().read(buffer)
    }
}

struct InputSource<R: Read + Send + 'static> {
    stereo: bool,
    reader: R,
    kind: AudioType,
}

impl<R: Read + Send> AudioSource for InputSource<R> {
    fn is_stereo(&mut self) -> bool { self.stereo }

    fn get_type(&self) -> AudioType { self.kind.clone() }

    fn read_pcm_frame(&mut self, buffer: &mut [i16]) -> Option<usize> {
        for (i, v) in buffer.iter_mut().enumerate() {
            *v = match self.reader.read_i16::<LittleEndian>() {
                Ok(v) => v,
                Err(ref e) => {
                    return if e.kind() == IoErrorKind::UnexpectedEof {
                        Some(i)
                    } else {
                        None
                    }
                },
            }
        }

        Some(buffer.len())
    }

    fn read_opus_frame(&mut self) -> Option<Vec<u8>> {
        match self.reader.read_i16::<LittleEndian>() {
            Ok(size) => {
                if size <= 0 {
                    warn!("Invalid opus frame size: {}", size);
                    return None;
                }

                let mut frame = Vec::with_capacity(size as usize);

                {
                    let reader = self.reader.by_ref();

                    if reader.take(size as u64).read_to_end(&mut frame).is_err() {
                        return None;
                    }
                }

                Some(frame)
            },
            Err(ref e) => {
                if e.kind() == IoErrorKind::UnexpectedEof {
                    Some(Vec::new())
                } else {
                    None
                }
            },
        }
    }
}

/// Opens an audio file through `ffmpeg` and creates an audio source.
pub fn ffmpeg<P: AsRef<OsStr>>(path: P) -> Result<Box<AudioSource>> {
    let path = path.as_ref();

    // Will fail if the path is not to a file on the fs. Likely a YouTube URI.
    let is_stereo = is_stereo(path).unwrap_or(false);
    let stereo_val = if is_stereo { "2" } else { "1" };

    let args = [
        "-f",
        "s16le",
        "-ac",
        stereo_val,
        "-ar",
        "48000",
        "-acodec",
        "pcm_s16le",
        "-",
    ];

    let command = Command::new("ffmpeg")
        .arg("-i")
        .arg(path)
        .args(&args)
        .stderr(Stdio::null())
        .stdin(Stdio::null())
        .stdout(Stdio::piped())
        .spawn()?;

    Ok(pcm(is_stereo, ChildContainer(command)))
}

/// Creates a streamed audio source from a DCA file.
/// Currently only accepts the DCA1 format.
pub fn dca<P: AsRef<OsStr>>(path: P) -> StdResult<Box<AudioSource>, DcaError> {
    let file = File::open(path.as_ref()).map_err(DcaError::IoError)?;

    let mut reader = BufReader::new(file);

    let mut header = [0u8; 4];

    // Read in the magic number to verify it's a DCA file.
    reader.read_exact(&mut header).map_err(DcaError::IoError)?;

    if header != b"DCA1"[..] {
        return Err(DcaError::InvalidHeader);
    }

    reader.read_exact(&mut header).map_err(DcaError::IoError)?;

    let size = (&header[..]).read_i32::<LittleEndian>().unwrap();

    // Sanity check
    if size < 2 {
        return Err(DcaError::InvalidSize(size));
    }

    let mut raw_json = Vec::with_capacity(size as usize);

    {
        let json_reader = reader.by_ref();
        json_reader
            .take(size as u64)
            .read_to_end(&mut raw_json)
            .map_err(DcaError::IoError)?;
    }

    let metadata = serde_json::from_slice::<DcaMetadata>(raw_json.as_slice())
        .map_err(DcaError::InvalidMetadata)?;

    Ok(opus(metadata.is_stereo(), reader))
}

/// Creates an Opus audio source.
pub fn opus<R: Read + Send + 'static>(is_stereo: bool, reader: R) -> Box<AudioSource> {
    Box::new(InputSource {
        stereo: is_stereo,
        reader: reader,
        kind: AudioType::Opus,
    })
}

/// Creates a PCM audio source.
pub fn pcm<R: Read + Send + 'static>(is_stereo: bool, reader: R) -> Box<AudioSource> {
    Box::new(InputSource {
        stereo: is_stereo,
        reader: reader,
        kind: AudioType::Pcm,
    })
}

/// Creates a streamed audio source with `youtube-dl` and `ffmpeg`.
pub fn ytdl(uri: &str) -> Result<Box<AudioSource>> {
    let args = [
        "-f",
        "webm[abr>0]/bestaudio/best",
        "--no-playlist",
        "--print-json",
        "--skip-download",
        uri,
    ];

    let out = Command::new("youtube-dl")
        .args(&args)
        .stdin(Stdio::null())
        .output()?;

    if !out.status.success() {
        return Err(Error::Voice(VoiceError::YouTubeDLRun(out)));
    }

    let value = serde_json::from_reader(&out.stdout[..])?;
    let mut obj = match value {
        Value::Object(obj) => obj,
        other => return Err(Error::Voice(VoiceError::YouTubeDLProcessing(other))),
    };

    let uri = match obj.remove("url") {
        Some(v) => {
            match v {
                Value::String(uri) => uri,
                other => return Err(Error::Voice(VoiceError::YouTubeDLUrl(other))),
            }
        },
        None => return Err(Error::Voice(VoiceError::YouTubeDLUrl(Value::Object(obj)))),
    };

    ffmpeg(&uri)
}

fn is_stereo(path: &OsStr) -> Result<bool> {
    let args = ["-v", "quiet", "-of", "json", "-show-streams", "-i"];

    let out = Command::new("ffprobe")
        .args(&args)
        .arg(path)
        .stdin(Stdio::null())
        .output()?;

    let value: Value = serde_json::from_reader(&out.stdout[..])?;

    let streams = value
        .as_object()
        .and_then(|m| m.get("streams"))
        .and_then(|v| v.as_array())
        .ok_or(Error::Voice(VoiceError::Streams))?;

    let check = streams.iter().any(|stream| {
        let channels = stream.as_object().and_then(|m| {
            m.get("channels").and_then(|v| v.as_i64())
        });

        channels == Some(2)
    });

    Ok(check)
}
<commit_msg>Split frame reading for PCM and Opus<commit_after>use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
use serde_json;
use std::ffi::OsStr;
use std::io::{BufReader, ErrorKind as IoErrorKind, Read, Result as IoResult};
use std::process::{Child, Command, Stdio};
use super::{AudioSource, AudioType, DcaError, DcaMetadata, VoiceError};
use internal::prelude::*;

use std::fs::File;
use std::result::Result as StdResult;

struct ChildContainer(Child);

impl Read for ChildContainer {
    fn read(&mut self, buffer: &mut [u8]) -> IoResult<usize> {
        self.0.stdout.as_mut().unwrap().read(buffer)
    }
}

struct InputSource<R: Read + Send + 'static> {
    stereo: bool,
    reader: R,
    kind: AudioType,
}

impl<R: Read + Send> AudioSource for InputSource<R> {
    fn is_stereo(&mut self) -> bool { self.stereo }

    fn get_type(&self) -> AudioType { self.kind.clone() }

    fn read_pcm_frame(&mut self, buffer: &mut [i16]) -> Option<usize> {
        for (i, v) in buffer.iter_mut().enumerate() {
            *v = match self.reader.read_i16::<LittleEndian>() {
                Ok(v) => v,
                Err(ref e) => {
                    return if e.kind() == IoErrorKind::UnexpectedEof {
                        Some(i)
                    } else {
                        None
                    }
                },
            }
        }

        Some(buffer.len())
    }

    fn read_opus_frame(&mut self) -> Option<Vec<u8>> {
        match self.reader.read_i16::<LittleEndian>() {
            Ok(size) => {
                if size <= 0 {
                    warn!("Invalid opus frame size: {}", size);
                    return None;
                }

                let mut frame = Vec::with_capacity(size as usize);

                {
                    let reader = self.reader.by_ref();

                    if reader.take(size as u64).read_to_end(&mut frame).is_err() {
                        return None;
                    }
                }

                Some(frame)
            },
            Err(ref e) => {
                if e.kind() == IoErrorKind::UnexpectedEof {
                    Some(Vec::new())
                } else {
                    None
                }
            },
        }
    }
}

/// Opens an audio file through `ffmpeg` and creates an audio source.
pub fn ffmpeg<P: AsRef<OsStr>>(path: P) -> Result<Box<AudioSource>> {
    let path = path.as_ref();

    // Will fail if the path is not to a file on the fs. Likely a YouTube URI.
    let is_stereo = is_stereo(path).unwrap_or(false);
    let stereo_val = if is_stereo { "2" } else { "1" };

    let args = [
        "-f",
        "s16le",
        "-ac",
        stereo_val,
        "-ar",
        "48000",
        "-acodec",
        "pcm_s16le",
        "-",
    ];

    let command = Command::new("ffmpeg")
        .arg("-i")
        .arg(path)
        .args(&args)
        .stderr(Stdio::null())
        .stdin(Stdio::null())
        .stdout(Stdio::piped())
        .spawn()?;

    Ok(pcm(is_stereo, ChildContainer(command)))
}

/// Creates a streamed audio source from a DCA file.
/// Currently only accepts the DCA1 format.
pub fn dca<P: AsRef<OsStr>>(path: P) -> StdResult<Box<AudioSource>, DcaError> {
    let file = File::open(path.as_ref()).map_err(DcaError::IoError)?;

    let mut reader = BufReader::new(file);

    let mut header = [0u8; 4];

    // Read in the magic number to verify it's a DCA file.
    reader.read_exact(&mut header).map_err(DcaError::IoError)?;

    if header != b"DCA1"[..] {
        return Err(DcaError::InvalidHeader);
    }

    reader.read_exact(&mut header).map_err(DcaError::IoError)?;

    let size = (&header[..]).read_i32::<LittleEndian>().unwrap();

    // Sanity check
    if size < 2 {
        return Err(DcaError::InvalidSize(size));
    }

    let mut raw_json = Vec::with_capacity(size as usize);

    {
        let json_reader = reader.by_ref();
        json_reader
            .take(size as u64)
            .read_to_end(&mut raw_json)
            .map_err(DcaError::IoError)?;
    }

    let metadata = serde_json::from_slice::<DcaMetadata>(raw_json.as_slice())
        .map_err(DcaError::InvalidMetadata)?;

    Ok(opus(metadata.is_stereo(), reader))
}

/// Creates an Opus audio source.
pub fn opus<R: Read + Send + 'static>(is_stereo: bool, reader: R) -> Box<AudioSource> {
    Box::new(InputSource {
        stereo: is_stereo,
        reader: reader,
        kind: AudioType::Opus,
    })
}

/// Creates a PCM audio source.
pub fn pcm<R: Read + Send + 'static>(is_stereo: bool, reader: R) -> Box<AudioSource> {
    Box::new(InputSource {
        stereo: is_stereo,
        reader: reader,
        kind: AudioType::Pcm,
    })
}

/// Creates a streamed audio source with `youtube-dl` and `ffmpeg`.
pub fn ytdl(uri: &str) -> Result<Box<AudioSource>> {
    let args = [
        "-f",
        "webm[abr>0]/bestaudio/best",
        "--no-playlist",
        "--print-json",
        "--skip-download",
        uri,
    ];

    let out = Command::new("youtube-dl")
        .args(&args)
        .stdin(Stdio::null())
        .output()?;

    if !out.status.success() {
        return Err(Error::Voice(VoiceError::YouTubeDLRun(out)));
    }

    let value = serde_json::from_reader(&out.stdout[..])?;
    let mut obj = match value {
        Value::Object(obj) => obj,
        other => return Err(Error::Voice(VoiceError::YouTubeDLProcessing(other))),
    };

    let uri = match obj.remove("url") {
        Some(v) => {
            match v {
                Value::String(uri) => uri,
                other => return Err(Error::Voice(VoiceError::YouTubeDLUrl(other))),
            }
        },
        None => return Err(Error::Voice(VoiceError::YouTubeDLUrl(Value::Object(obj)))),
    };

    ffmpeg(&uri)
}

fn is_stereo(path: &OsStr) -> Result<bool> {
    let args = ["-v", "quiet", "-of", "json", "-show-streams", "-i"];

    let out = Command::new("ffprobe")
        .args(&args)
        .arg(path)
        .stdin(Stdio::null())
        .output()?;

    let value: Value = serde_json::from_reader(&out.stdout[..])?;

    let streams = value
        .as_object()
        .and_then(|m| m.get("streams"))
        .and_then(|v| v.as_array())
        .ok_or(Error::Voice(VoiceError::Streams))?;

    let check = streams.iter().any(|stream| {
        let channels = stream.as_object().and_then(|m| {
            m.get("channels").and_then(|v| v.as_i64())
        });

        channels == Some(2)
    });

    Ok(check)
}
<|endoftext|>