<commit_before>//@ignore-target-windows: Concurrency on Windows is not supported yet.
//@compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance

use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock};
use std::thread;
use std::time::{Duration, Instant};

// Check if Rust barriers are working.

/// This test is taken from the Rust documentation.
fn check_barriers() {
    let mut handles = Vec::with_capacity(10);
    let barrier = Arc::new(Barrier::new(10));
    for _ in 0..10 {
        let c = barrier.clone();
        // The same messages will be printed together.
        // You will NOT see any interleaving.
        handles.push(thread::spawn(move || {
            println!("before wait");
            c.wait();
            println!("after wait");
        }));
    }
    // Wait for other threads to finish.
    for handle in handles {
        handle.join().unwrap();
    }
}

// Check if Rust conditional variables are working.

/// The test taken from the Rust documentation.
fn check_conditional_variables_notify_one() {
    let pair = Arc::new((Mutex::new(false), Condvar::new()));
    let pair2 = pair.clone();

    // Spawn a new thread.
    let t = thread::spawn(move || {
        thread::yield_now();
        let (lock, cvar) = &*pair2;
        let mut started = lock.lock().unwrap();
        *started = true;
        // We notify the condvar that the value has changed.
        cvar.notify_one();
    });

    // Wait for the thread to fully start up.
    let (lock, cvar) = &*pair;
    let mut started = lock.lock().unwrap();
    while !*started {
        started = cvar.wait(started).unwrap();
    }

    t.join().unwrap();
}

/// Test that waiting on a conditional variable with a timeout does not
/// deadlock.
fn check_conditional_variables_timed_wait_timeout() {
    let lock = Mutex::new(());
    let cvar = Condvar::new();
    let guard = lock.lock().unwrap();
    let now = Instant::now();
    let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap();
    assert!(timeout.timed_out());
    let elapsed_time = now.elapsed().as_millis();
    assert!(100 <= elapsed_time && elapsed_time <= 1000);
}

/// Test that signaling a conditional variable when waiting with a timeout works
/// as expected.
fn check_conditional_variables_timed_wait_notimeout() {
    let pair = Arc::new((Mutex::new(()), Condvar::new()));
    let pair2 = pair.clone();

    let (lock, cvar) = &*pair;
    let guard = lock.lock().unwrap();

    let handle = thread::spawn(move || {
        let (_lock, cvar) = &*pair2;
        cvar.notify_one();
    });

    // macOS runners are very unreliable.
    let timeout = if cfg!(target_os = "macos") { 2000 } else { 500 };
    let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(timeout)).unwrap();
    assert!(!timeout.timed_out());
    handle.join().unwrap();
}

// Check if locks are working.

fn check_mutex() {
    let data = Arc::new(Mutex::new(0));
    let mut threads = Vec::new();

    for _ in 0..3 {
        let data = Arc::clone(&data);
        let thread = thread::spawn(move || {
            let mut data = data.lock().unwrap();
            thread::yield_now();
            *data += 1;
        });
        threads.push(thread);
    }

    for thread in threads {
        thread.join().unwrap();
    }

    assert!(data.try_lock().is_ok());

    let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap();
    assert_eq!(data, 3);
}

fn check_rwlock_write() {
    let data = Arc::new(RwLock::new(0));
    let mut threads = Vec::new();

    for _ in 0..3 {
        let data = Arc::clone(&data);
        let thread = thread::spawn(move || {
            let mut data = data.write().unwrap();
            thread::yield_now();
            *data += 1;
        });
        threads.push(thread);
    }

    for thread in threads {
        thread.join().unwrap();
    }

    assert!(data.try_write().is_ok());

    let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap();
    assert_eq!(data, 3);
}

fn check_rwlock_read_no_deadlock() {
    let l1 = Arc::new(RwLock::new(0));
    let l2 = Arc::new(RwLock::new(0));

    let l1_copy = Arc::clone(&l1);
    let l2_copy = Arc::clone(&l2);
    let _guard1 = l1.read().unwrap();
    let handle = thread::spawn(move || {
        let _guard2 = l2_copy.read().unwrap();
        thread::yield_now();
        let _guard1 = l1_copy.read().unwrap();
    });
    thread::yield_now();
    let _guard2 = l2.read().unwrap();
    handle.join().unwrap();
}

// Check if Rust once statics are working.

static mut VAL: usize = 0;
static INIT: Once = Once::new();

fn get_cached_val() -> usize {
    unsafe {
        INIT.call_once(|| {
            VAL = expensive_computation();
        });
        VAL
    }
}

fn expensive_computation() -> usize {
    let mut i = 1;
    let mut c = 1;
    while i < 1000 {
        i *= c;
        c += 1;
    }
    i
}

/// The test taken from the Rust documentation.
fn check_once() {
    let handles: Vec<_> = (0..10)
        .map(|_| {
            thread::spawn(|| {
                thread::yield_now();
                let val = get_cached_val();
                assert_eq!(val, 5040);
            })
        })
        .collect();
    for handle in handles {
        handle.join().unwrap();
    }
}

fn park_timeout() {
    let start = Instant::now();

    thread::park_timeout(Duration::from_millis(200));
    // Normally, waiting in park/park_timeout may spuriously wake up early, but we
    // know Miri's timed synchronization primitives do not do that.

    assert!((200..1000).contains(&start.elapsed().as_millis()));
}

fn park_unpark() {
    let t1 = thread::current();
    let t2 = thread::spawn(move || {
        thread::park();
        thread::sleep(Duration::from_millis(200));
        t1.unpark();
    });

    let start = Instant::now();

    t2.thread().unpark();
    thread::park();
    // Normally, waiting in park/park_timeout may spuriously wake up early, but we
    // know Miri's timed synchronization primitives do not do that.

    assert!((200..1000).contains(&start.elapsed().as_millis()));

    t2.join().unwrap();
}

fn main() {
    check_barriers();
    check_conditional_variables_notify_one();
    check_conditional_variables_timed_wait_timeout();
    check_conditional_variables_timed_wait_notimeout();
    check_mutex();
    check_rwlock_write();
    check_rwlock_read_no_deadlock();
    check_once();
    park_timeout();
    park_unpark();
}
<commit_msg>make a sync test more reliable<commit_after>//@ignore-target-windows: Concurrency on Windows is not supported yet.
//@compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance

use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock};
use std::thread;
use std::time::{Duration, Instant};

// Check if Rust barriers are working.

/// This test is taken from the Rust documentation.
fn check_barriers() {
    let mut handles = Vec::with_capacity(10);
    let barrier = Arc::new(Barrier::new(10));
    for _ in 0..10 {
        let c = barrier.clone();
        // The same messages will be printed together.
        // You will NOT see any interleaving.
        handles.push(thread::spawn(move || {
            println!("before wait");
            c.wait();
            println!("after wait");
        }));
    }
    // Wait for other threads to finish.
    for handle in handles {
        handle.join().unwrap();
    }
}

// Check if Rust conditional variables are working.

/// The test taken from the Rust documentation.
fn check_conditional_variables_notify_one() {
    let pair = Arc::new((Mutex::new(false), Condvar::new()));
    let pair2 = pair.clone();

    // Spawn a new thread.
    let t = thread::spawn(move || {
        thread::yield_now();
        let (lock, cvar) = &*pair2;
        let mut started = lock.lock().unwrap();
        *started = true;
        // We notify the condvar that the value has changed.
        cvar.notify_one();
    });

    // Wait for the thread to fully start up.
    let (lock, cvar) = &*pair;
    let mut started = lock.lock().unwrap();
    while !*started {
        started = cvar.wait(started).unwrap();
    }

    t.join().unwrap();
}

/// Test that waiting on a conditional variable with a timeout does not
/// deadlock.
fn check_conditional_variables_timed_wait_timeout() {
    let lock = Mutex::new(());
    let cvar = Condvar::new();
    let guard = lock.lock().unwrap();
    let now = Instant::now();
    let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap();
    assert!(timeout.timed_out());
    let elapsed_time = now.elapsed().as_millis();
    assert!(100 <= elapsed_time && elapsed_time <= 1000);
}

/// Test that signaling a conditional variable when waiting with a timeout works
/// as expected.
fn check_conditional_variables_timed_wait_notimeout() {
    let pair = Arc::new((Mutex::new(()), Condvar::new()));
    let pair2 = pair.clone();

    let (lock, cvar) = &*pair;
    let guard = lock.lock().unwrap();

    let handle = thread::spawn(move || {
        thread::sleep(Duration::from_millis(100)); // Make sure the other thread is waiting by the time we call `notify`.
        let (_lock, cvar) = &*pair2;
        cvar.notify_one();
    });

    let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(500)).unwrap();
    assert!(!timeout.timed_out());
    handle.join().unwrap();
}

// Check if locks are working.

fn check_mutex() {
    let data = Arc::new(Mutex::new(0));
    let mut threads = Vec::new();

    for _ in 0..3 {
        let data = Arc::clone(&data);
        let thread = thread::spawn(move || {
            let mut data = data.lock().unwrap();
            thread::yield_now();
            *data += 1;
        });
        threads.push(thread);
    }

    for thread in threads {
        thread.join().unwrap();
    }

    assert!(data.try_lock().is_ok());

    let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap();
    assert_eq!(data, 3);
}

fn check_rwlock_write() {
    let data = Arc::new(RwLock::new(0));
    let mut threads = Vec::new();

    for _ in 0..3 {
        let data = Arc::clone(&data);
        let thread = thread::spawn(move || {
            let mut data = data.write().unwrap();
            thread::yield_now();
            *data += 1;
        });
        threads.push(thread);
    }

    for thread in threads {
        thread.join().unwrap();
    }

    assert!(data.try_write().is_ok());

    let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap();
    assert_eq!(data, 3);
}

fn check_rwlock_read_no_deadlock() {
    let l1 = Arc::new(RwLock::new(0));
    let l2 = Arc::new(RwLock::new(0));

    let l1_copy = Arc::clone(&l1);
    let l2_copy = Arc::clone(&l2);
    let _guard1 = l1.read().unwrap();
    let handle = thread::spawn(move || {
        let _guard2 = l2_copy.read().unwrap();
        thread::yield_now();
        let _guard1 = l1_copy.read().unwrap();
    });
    thread::yield_now();
    let _guard2 = l2.read().unwrap();
    handle.join().unwrap();
}

// Check if Rust once statics are working.

static mut VAL: usize = 0;
static INIT: Once = Once::new();

fn get_cached_val() -> usize {
    unsafe {
        INIT.call_once(|| {
            VAL = expensive_computation();
        });
        VAL
    }
}

fn expensive_computation() -> usize {
    let mut i = 1;
    let mut c = 1;
    while i < 1000 {
        i *= c;
        c += 1;
    }
    i
}

/// The test taken from the Rust documentation.
fn check_once() {
    let handles: Vec<_> = (0..10)
        .map(|_| {
            thread::spawn(|| {
                thread::yield_now();
                let val = get_cached_val();
                assert_eq!(val, 5040);
            })
        })
        .collect();
    for handle in handles {
        handle.join().unwrap();
    }
}

fn park_timeout() {
    let start = Instant::now();

    thread::park_timeout(Duration::from_millis(200));
    // Normally, waiting in park/park_timeout may spuriously wake up early, but we
    // know Miri's timed synchronization primitives do not do that.

    assert!((200..1000).contains(&start.elapsed().as_millis()));
}

fn park_unpark() {
    let t1 = thread::current();
    let t2 = thread::spawn(move || {
        thread::park();
        thread::sleep(Duration::from_millis(200));
        t1.unpark();
    });

    let start = Instant::now();

    t2.thread().unpark();
    thread::park();
    // Normally, waiting in park/park_timeout may spuriously wake up early, but we
    // know Miri's timed synchronization primitives do not do that.

    assert!((200..1000).contains(&start.elapsed().as_millis()));

    t2.join().unwrap();
}

fn main() {
    check_barriers();
    check_conditional_variables_notify_one();
    check_conditional_variables_timed_wait_timeout();
    check_conditional_variables_timed_wait_notimeout();
    check_mutex();
    check_rwlock_write();
    check_rwlock_read_no_deadlock();
    check_once();
    park_timeout();
    park_unpark();
}
<|endoftext|>


<commit_before>use desync::scheduler::*;

use super::timeout::*;

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

use futures::prelude::*;
use futures::task;
use futures::task::{ArcWake, Poll};
use futures::channel::oneshot;

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

        let queue       = queue();
        let future      = future_sync(&queue, move || async {
            thread::sleep(Duration::from_millis(100));
            42
        });

        executor::block_on(async {
            assert!(future.await.unwrap() == 42);
        });
    }, 500);
}

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

        let scheduler   = Scheduler::new();

        // Even with 0 threads, futures should still run (by draining on the current thread as for sync actions)
        scheduler.set_max_threads(0);
        scheduler.despawn_threads_if_overloaded();

        let queue       = queue();
        let future      = scheduler.future_sync(&queue, move || async {
            thread::sleep(Duration::from_millis(100));
            42
        });

        executor::block_on(async {
            assert!(future.await.unwrap() == 42);
        });
    }, 500);
}

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

        let (tx, rx)    = oneshot::channel::<i32>();
        let scheduler   = Scheduler::new();

        // Even with 0 threads, futures should still run (by draining on the current thread as for sync actions)
        scheduler.set_max_threads(0);
        scheduler.despawn_threads_if_overloaded();

        // Schedule a future that will block until we send a value
        let queue       = queue();
        let future      = scheduler.future_sync(&queue, move || async {
            rx.await.expect("Receive result")
        });

        // Schedule a thread that will send a value
        thread::spawn(move || {
            // Wait for a bit before sending the result so the future should block
            thread::sleep(Duration::from_millis(100));

            tx.send(42).expect("Send")
        });

        executor::block_on(async {
            assert!(future.await.expect("result") == 42);
        });
    }, 500);
}

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

        // We use a oneshot as our future, and a mpsc channel to track progress
        let (tx, rx)                = channel();
        let (future_tx, future_rx)  = oneshot::channel();

        let scheduler   = scheduler();
        let queue       = queue();

        // Start by sending '1' from an async
        let tx2 = tx.clone();
        desync(&queue, move || { tx2.send(1).unwrap(); });

        // Then send the value sent via our oneshot using a future
        let tx2 = tx.clone();
        let future = scheduler.after(&queue, future_rx,
            move |val| val.map(move |val| { tx2.send(val).unwrap(); 4 }));

        // Then send '3'
        let tx2 = tx.clone();
        desync(&queue, move || { tx2.send(3).unwrap(); });

        // '1' should be available, but we should otherwise be blocked on the future
        assert!(rx.recv().unwrap() == 1);
        assert!(rx.recv_timeout(Duration::from_millis(100)).is_err());

        // Send '2' to the future
        future_tx.send(2).unwrap();

        executor::block_on(async {
            // Future should resolve to 4
            assert!(future.await.unwrap() == Ok(4));

            // Should receive the '2' from the future, then 3
            assert!(rx.recv_timeout(Duration::from_millis(100)).unwrap() == 2);
            assert!(rx.recv().unwrap() == 3);
        });
    }, 500);
}

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

        // We use a oneshot as our future, and a mpsc channel to track progress
        let (tx, rx)                = channel();
        let (future_tx, future_rx)  = oneshot::channel();

        let scheduler   = scheduler();
        let queue       = queue();

        // Start by sending '1' from an async
        let tx2 = tx.clone();
        desync(&queue, move || { thread::sleep(Duration::from_millis(100)); tx2.send(1).unwrap(); });

        // Then send the value sent via our oneshot using a future
        let tx2 = tx.clone();
        let future = scheduler.after(&queue, future_rx,
            move |val| val.map(move |val| { tx2.send(val).unwrap(); 4 }));

        // Then send '3'
        let tx2 = tx.clone();
        desync(&queue, move || { tx2.send(3).unwrap(); });

        // Send '2' to the future
        future_tx.send(2).unwrap();

        executor::block_on(async {
            // Future should resolve to 4
            assert!(future.await.unwrap() == Ok(4));

            // '1' should be available first
            assert!(rx.recv().unwrap() == 1);

            // Should receive the '2' from the future, then 3
            assert!(rx.recv_timeout(Duration::from_millis(100)).unwrap() == 2);
            assert!(rx.recv().unwrap() == 3);
        });
    }, 500);
}

///
/// Used for polling futures to see if they've notified us yet
///
struct TestWaker {
    pub awake: Mutex<bool>
}

impl ArcWake for TestWaker {
    fn wake_by_ref(arc_self: &Arc<Self>) {
        (*arc_self.awake.lock().unwrap()) = true;
    }
}

#[test]
fn poll_two_futures_on_one_queue() {
    // 0 threads so we force the future to act in 'drain' mode
    let scheduler   = Scheduler::new();

    // Even with 0 threads, futures should still run (by draining on the current thread as for sync actions)
    scheduler.set_max_threads(0);
    scheduler.despawn_threads_if_overloaded();

    // If a single queue has a future on
    let queue           = queue();
    let (done1, recv1)  = oneshot::channel::<()>();
    let (done2, recv2)  = oneshot::channel::<()>();

    let wake1           = Arc::new(TestWaker { awake: Mutex::new(false) });
    let wake2           = Arc::new(TestWaker { awake: Mutex::new(false) });

    // Wait for done1 then done2 to signal
    let mut future_1    = scheduler.future_sync(&queue, move || {
        async move { recv1.await.ok(); }
    });

    let mut future_2    = scheduler.future_sync(&queue, move || {
        async move { recv2.await.ok(); }
    });

    // Poll future 1 then future 2 (as there are no threads to run, we'll use the 'drain on current thread' style, which will return pending as recv is pending)
    let waker_ref           = task::waker_ref(&wake1);
    let mut ctxt            = task::Context::from_waker(&waker_ref);

    assert!(future_1.poll_unpin(&mut ctxt) == Poll::Pending);

    // Only future_1 should be 'pollable' at this point (ie, is in the WaitForPoll state from the previous call)
    let waker_ref           = task::waker_ref(&wake2);
    let mut ctxt            = task::Context::from_waker(&waker_ref);

    assert!(future_2.poll_unpin(&mut ctxt) == Poll::Pending);

    // Finish both futures
    done1.send(()).unwrap();

    let waker_ref           = task::waker_ref(&wake2);
    let mut ctxt            = task::Context::from_waker(&waker_ref);

    assert!(future_2.poll_unpin(&mut ctxt) == Poll::Pending);

    done2.send(()).unwrap();

    // future_1 should be signalled for polling, future_2 should not
    assert!((*wake2.awake.lock().unwrap()) == false);
    assert!((*wake1.awake.lock().unwrap()) == true);

    // Retrieve the result for future_1
    let waker_ref           = task::waker_ref(&wake2);
    let mut ctxt            = task::Context::from_waker(&waker_ref);

    assert!(future_1.poll_unpin(&mut ctxt) == Poll::Ready(Ok(())));

    // Both future 1 and future 2 should have signalled now

    // TODO: this is a possible bug with 0 threads - the thread won't reschedule after future_1 completes, so wake2 will not yet be set
    //          (This is quite a complicated problem: if the drain continued processing jobs until it became pending instead of scheduling
    //          in the background, this would work but the return from poll could be delayed indefinitely)
    // assert!((*wake2.awake.lock().unwrap()) == true);

    // Give the scheduler a chance to run the other future (it will be queued in the background, so this is required for the notification to occur)
    scheduler.set_max_threads(1);
    for _ in 0..100 {
        if *wake2.awake.lock().unwrap() { break; }
        thread::sleep(Duration::from_millis(1));
    }
    assert!((*wake2.awake.lock().unwrap()) == true);

    let waker_ref           = task::waker_ref(&wake2);
    let mut ctxt            = task::Context::from_waker(&waker_ref);

    // Should be able to retrieve the result of future_2
    assert!(future_2.poll_unpin(&mut ctxt) == Poll::Ready(Ok(())));

    // TODO: not actually sure if this is bad behaviour or not but if future_2 is polled first, future_1 won't be available until future_2
    //      completes. This is another 0 thread only issue as future_1 will be able to send its notification when the thread pool is available.
}
<commit_msg>Update comments<commit_after>use desync::scheduler::*;

use super::timeout::*;

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

use futures::prelude::*;
use futures::task;
use futures::task::{ArcWake, Poll};
use futures::channel::oneshot;

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

        let queue       = queue();
        let future      = future_sync(&queue, move || async {
            thread::sleep(Duration::from_millis(100));
            42
        });

        executor::block_on(async {
            assert!(future.await.unwrap() == 42);
        });
    }, 500);
}

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

        let scheduler   = Scheduler::new();

        // Even with 0 threads, futures should still run (by draining on the current thread as for sync actions)
        scheduler.set_max_threads(0);
        scheduler.despawn_threads_if_overloaded();

        let queue       = queue();
        let future      = scheduler.future_sync(&queue, move || async {
            thread::sleep(Duration::from_millis(100));
            42
        });

        executor::block_on(async {
            assert!(future.await.unwrap() == 42);
        });
    }, 500);
}

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

        let (tx, rx)    = oneshot::channel::<i32>();
        let scheduler   = Scheduler::new();

        // Even with 0 threads, futures should still run (by draining on the current thread as for sync actions)
        scheduler.set_max_threads(0);
        scheduler.despawn_threads_if_overloaded();

        // Schedule a future that will block until we send a value
        let queue       = queue();
        let future      = scheduler.future_sync(&queue, move || async {
            rx.await.expect("Receive result")
        });

        // Schedule a thread that will send a value
        thread::spawn(move || {
            // Wait for a bit before sending the result so the future should block
            thread::sleep(Duration::from_millis(100));

            tx.send(42).expect("Send")
        });

        executor::block_on(async {
            assert!(future.await.expect("result") == 42);
        });
    }, 500);
}

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

        // We use a oneshot as our future, and a mpsc channel to track progress
        let (tx, rx)                = channel();
        let (future_tx, future_rx)  = oneshot::channel();

        let scheduler   = scheduler();
        let queue       = queue();

        // Start by sending '1' from an async
        let tx2 = tx.clone();
        desync(&queue, move || { tx2.send(1).unwrap(); });

        // Then send the value sent via our oneshot using a future
        let tx2 = tx.clone();
        let future = scheduler.after(&queue, future_rx,
            move |val| val.map(move |val| { tx2.send(val).unwrap(); 4 }));

        // Then send '3'
        let tx2 = tx.clone();
        desync(&queue, move || { tx2.send(3).unwrap(); });

        // '1' should be available, but we should otherwise be blocked on the future
        assert!(rx.recv().unwrap() == 1);
        assert!(rx.recv_timeout(Duration::from_millis(100)).is_err());

        // Send '2' to the future
        future_tx.send(2).unwrap();

        executor::block_on(async {
            // Future should resolve to 4
            assert!(future.await.unwrap() == Ok(4));

            // Should receive the '2' from the future, then 3
            assert!(rx.recv_timeout(Duration::from_millis(100)).unwrap() == 2);
            assert!(rx.recv().unwrap() == 3);
        });
    }, 500);
}

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

        // We use a oneshot as our future, and a mpsc channel to track progress
        let (tx, rx)                = channel();
        let (future_tx, future_rx)  = oneshot::channel();

        let scheduler   = scheduler();
        let queue       = queue();

        // Start by sending '1' from an async
        let tx2 = tx.clone();
        desync(&queue, move || { thread::sleep(Duration::from_millis(100)); tx2.send(1).unwrap(); });

        // Then send the value sent via our oneshot using a future
        let tx2 = tx.clone();
        let future = scheduler.after(&queue, future_rx,
            move |val| val.map(move |val| { tx2.send(val).unwrap(); 4 }));

        // Then send '3'
        let tx2 = tx.clone();
        desync(&queue, move || { tx2.send(3).unwrap(); });

        // Send '2' to the future
        future_tx.send(2).unwrap();

        executor::block_on(async {
            // Future should resolve to 4
            assert!(future.await.unwrap() == Ok(4));

            // '1' should be available first
            assert!(rx.recv().unwrap() == 1);

            // Should receive the '2' from the future, then 3
            assert!(rx.recv_timeout(Duration::from_millis(100)).unwrap() == 2);
            assert!(rx.recv().unwrap() == 3);
        });
    }, 500);
}

///
/// Used for polling futures to see if they've notified us yet
///
struct TestWaker {
    pub awake: Mutex<bool>
}

impl ArcWake for TestWaker {
    fn wake_by_ref(arc_self: &Arc<Self>) {
        (*arc_self.awake.lock().unwrap()) = true;
    }
}

#[test]
fn poll_two_futures_on_one_queue() {
    // 0 threads so we force the future to act in 'drain' mode
    let scheduler   = Scheduler::new();

    // Even with 0 threads, futures should still run (by draining on the current thread as for sync actions)
    scheduler.set_max_threads(0);
    scheduler.despawn_threads_if_overloaded();

    // If a single queue has a future on
    let queue           = queue();
    let (done1, recv1)  = oneshot::channel::<()>();
    let (done2, recv2)  = oneshot::channel::<()>();

    let wake1           = Arc::new(TestWaker { awake: Mutex::new(false) });
    let wake2           = Arc::new(TestWaker { awake: Mutex::new(false) });

    // Wait for done1 then done2 to signal
    let mut future_1    = scheduler.future_sync(&queue, move || {
        async move { recv1.await.ok(); }
    });

    let mut future_2    = scheduler.future_sync(&queue, move || {
        async move { recv2.await.ok(); }
    });

    // Poll future 1 then future 2 (as there are no threads to run, we'll use the 'drain on current thread' style, which will return pending as recv is pending)
    let waker_ref           = task::waker_ref(&wake1);
    let mut ctxt            = task::Context::from_waker(&waker_ref);

    assert!(future_1.poll_unpin(&mut ctxt) == Poll::Pending);

    // Only future_1 should be 'pollable' at this point (ie, is in the WaitForPoll state from the previous call)
    let waker_ref           = task::waker_ref(&wake2);
    let mut ctxt            = task::Context::from_waker(&waker_ref);

    assert!(future_2.poll_unpin(&mut ctxt) == Poll::Pending);

    // Finish both futures
    done1.send(()).unwrap();

    let waker_ref           = task::waker_ref(&wake2);
    let mut ctxt            = task::Context::from_waker(&waker_ref);

    // Poll the other future: it should be pending as it's waiting to be scheduled
    assert!(future_2.poll_unpin(&mut ctxt) == Poll::Pending);

    done2.send(()).unwrap();

    // future_1 should be signalled for polling, future_2 should not (as it can't start until future_1 is finished)
    assert!((*wake2.awake.lock().unwrap()) == false);
    assert!((*wake1.awake.lock().unwrap()) == true);

    // Retrieve the result for future_1
    let waker_ref           = task::waker_ref(&wake2);
    let mut ctxt            = task::Context::from_waker(&waker_ref);

    assert!(future_1.poll_unpin(&mut ctxt) == Poll::Ready(Ok(())));

    // Both future 1 and future 2 should have signalled now

    // TODO: this is a possible bug with 0 threads - the thread won't reschedule after future_1 completes, so wake2 will not yet be set
    //          (This is quite a complicated problem: if the drain continued processing jobs until it became pending instead of scheduling
    //          in the background, this would work but the return from poll could be delayed indefinitely)
    // assert!((*wake2.awake.lock().unwrap()) == true);

    // Give the scheduler a chance to run the other future (it will be queued in the background, so this is required for the notification to occur)
    scheduler.set_max_threads(1);
    for _ in 0..100 {
        if *wake2.awake.lock().unwrap() { break; }
        thread::sleep(Duration::from_millis(1));
    }
    assert!((*wake2.awake.lock().unwrap()) == true);

    let waker_ref           = task::waker_ref(&wake2);
    let mut ctxt            = task::Context::from_waker(&waker_ref);

    // Should be able to retrieve the result of future_2
    assert!(future_2.poll_unpin(&mut ctxt) == Poll::Ready(Ok(())));

    // TODO: not actually sure if this is bad behaviour or not but if future_2 is polled first, future_1 won't be available until future_2
    //      completes. This is another 0 thread only issue as future_1 will be able to send its notification when the thread pool is available.
}
<|endoftext|>


<commit_before>// Compiled transfer syntax specifiers.

// -- the three base transfer syntaxes, fully supported --

pub const IMPLICIT_VR_LITTLE_ENDIAN: Ts = Ts::new(
    "1.2.840.10008.1.2",
    "Implicit VR Little Endian",
    Endianness::Little,
    false,
    Codec::None,
);
submit_transfer_syntax!(IMPLICIT_VR_LITTLE_ENDIAN);

pub const EXPLICIT_VR_LITTLE_ENDIAN: Ts = Ts::new(
    "1.2.840.10008.1.2.1",
    "Explicit VR Little Endian",
    Endianness::Little,
    true,
    Codec::None,
);
submit_transfer_syntax!(EXPLICIT_VR_LITTLE_ENDIAN);

pub const EXPLICIT_VR_BIG_ENDIAN: Ts = Ts::new(
    "1.2.840.10008.1.2.2",
    "Explicit VR Big Endian",
    Endianness::Big,
    true,
    Codec::None,
);
submit_transfer_syntax!(EXPLICIT_VR_BIG_ENDIAN);

// --- stub transfer syntaxes, known but not supported ---

pub const DEFLATED_EXPLICIT_VR_LITTLE_ENDIAN: Ts = Ts::new(
    "1.2.840.10008.1.2.1.99",
    "Deflated Explicit VR Little Endian",
    Endianness::Little,
    true,
    Codec::Unsupported,
);
submit_transfer_syntax!(DEFLATED_EXPLICIT_VR_LITTLE_ENDIAN);

pub const JPIP_DEREFERENCED_DEFLATE: Ts = Ts::new(
    "1.2.840.10008.1.2.4.95",
    "JPIP Referenced Deflate",
    Endianness::Little,
    true,
    Codec::Unsupported,
);
submit_transfer_syntax!(JPIP_DEREFERENCED_DEFLATE);

// --- partially supported transfer syntaxes, pixel data encapsulation not supported ---

pub const JPEG_BASELINE: Ts = create_ts_stub("1.2.840.10008.1.2.4.50", "JPEG Baseline (Process 1)");
submit_transfer_syntax!(JPEG_BASELINE);
pub const JPEG_EXTENDED: Ts = create_ts_stub("1.2.840.10008.1.2.4.51", "JPEG Extended (Process 2 & 4)");
submit_transfer_syntax!(JPEG_EXTENDED);
pub const JPEG_LOSSLESS_NON_HIERARCHICAL: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.57", "JPEG Lossless, Non-Hierarchical (Process 14)");
submit_transfer_syntax!(JPEG_LOSSLESS_NON_HIERARCHICAL);
pub const JPEG_LOSSLESS_NON_HIERARCHICAL_FIRST_ORDER_PREDICTION: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.70", "JPEG Lossless, Non-Hierarchical, First-Order Prediction");
submit_transfer_syntax!(JPEG_LOSSLESS_NON_HIERARCHICAL_FIRST_ORDER_PREDICTION);
pub const JPEG_LS_LOSSLESS_IMAGE_COMPRESSION: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.80", "JPEG-LS Lossless Image Compression");
submit_transfer_syntax!(JPEG_LS_LOSSLESS_IMAGE_COMPRESSION);
pub const JPEG_LS_LOSSY_IMAGE_COMPRESSION: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.81", "JPEG-LS Lossy (Near-Lossless) Image Compression");
submit_transfer_syntax!(JPEG_LS_LOSSY_IMAGE_COMPRESSION);
pub const JPEG_2000_IMAGE_COMPRESSION_LOSSLESS_ONLY: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.90", "JPEG 2000 Image Compression (Lossless Only)");
submit_transfer_syntax!(JPEG_2000_IMAGE_COMPRESSION_LOSSLESS_ONLY);
pub const JPEG_2000_IMAGE_COMPRESSION: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.91", "JPEG 2000 Image Compression");
submit_transfer_syntax!(JPEG_2000_IMAGE_COMPRESSION);
pub const JPEG_2000_PART2_MULTI_COMPONENT_IMAGE_COMPRESSION_LOSSLESS_ONLY: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.92", "JPEG 2000 Part 2 Multi-component Image Compression (Lossless Only)");
submit_transfer_syntax!(JPEG_2000_PART2_MULTI_COMPONENT_IMAGE_COMPRESSION_LOSSLESS_ONLY);
pub const JPEG_2000_PART2_MULTI_COMPONENT_IMAGE_COMPRESSION: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.93", "JPEG 2000 Part 2 Multi-component Image Compression");
submit_transfer_syntax!(JPEG_2000_PART2_MULTI_COMPONENT_IMAGE_COMPRESSION);
pub const JPIP_REFERENCED: Ts = create_ts_stub("1.2.840.10008.1.2.4.94", "JPIP Referenced");
submit_transfer_syntax!(JPIP_REFERENCED);
pub const MPEG2_MAIN_PROFILE_MAIN_LEVEL: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.100", "MPEG2 Main Profile / Main Level");
submit_transfer_syntax!(MPEG2_MAIN_PROFILE_MAIN_LEVEL);
pub const MPEG2_MAIN_PROFILE_HIGH_LEVEL: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.101", "MPEG2 Main Profile / High Level");
submit_transfer_syntax!(MPEG2_MAIN_PROFILE_HIGH_LEVEL);
pub const MPEG4_AVC_H264_HIGH_PROFILE: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.102", "MPEG-4 AVC/H.264 High Profile / Level 4.1");
submit_transfer_syntax!(MPEG4_AVC_H264_HIGH_PROFILE);
pub const MPEG4_AVC_H264_BD_COMPATIBLE_HIGH_PROFILE: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.103", "MPEG-4 AVC/H.264 BD-Compatible High Profile / Level 4.1");
submit_transfer_syntax!(MPEG4_AVC_H264_BD_COMPATIBLE_HIGH_PROFILE);
pub const MPEG4_AVC_H264_HIGH_PROFILE_FOR_2D_VIDEO: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.104", "MPEG-4 AVC/H.264 High Profile / Level 4.2 For 2D Video");
submit_transfer_syntax!(MPEG4_AVC_H264_HIGH_PROFILE_FOR_2D_VIDEO);
pub const MPEG4_AVC_H264_HIGH_PROFILE_FOR_3D_VIDEO: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.105", "MPEG-4 AVC/H.264 High Profile / Level 4.2 For 3D Video");
submit_transfer_syntax!(MPEG4_AVC_H264_HIGH_PROFILE_FOR_3D_VIDEO);
pub const MPEG4_AVC_H264_STEREO_HIGH_PROFILE: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.106", "MPEG-4 AVC/H.264 Stereo High Profile / Level 4.2");
submit_transfer_syntax!(MPEG4_AVC_H264_STEREO_HIGH_PROFILE);
pub const HEVC_H265_MAIN_PROFILE: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.107", "HEVC/H.265 Main Profile / Level 5.1");
submit_transfer_syntax!(HEVC_H265_MAIN_PROFILE);
pub const HEVC_H265_MAIN_10_PROFILE: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.108", "HEVC/H.265 Main 10 Profile / Level 5.1");
submit_transfer_syntax!(HEVC_H265_MAIN_10_PROFILE);
pub const RLE_LOSSLESS: Ts = create_ts_stub("1.2.840.10008.1.2.5", "RLE Lossless");
submit_transfer_syntax!(RLE_LOSSLESS);
<commit_msg>Fix more TS UIDs<commit_after>// Compiled transfer syntax specifiers.

// -- the three base transfer syntaxes, fully supported --

pub const IMPLICIT_VR_LITTLE_ENDIAN: Ts = Ts::new(
    "1.2.840.10008.1.2",
    "Implicit VR Little Endian",
    Endianness::Little,
    false,
    Codec::None,
);
submit_transfer_syntax!(IMPLICIT_VR_LITTLE_ENDIAN);

pub const EXPLICIT_VR_LITTLE_ENDIAN: Ts = Ts::new(
    "1.2.840.10008.1.2.1",
    "Explicit VR Little Endian",
    Endianness::Little,
    true,
    Codec::None,
);
submit_transfer_syntax!(EXPLICIT_VR_LITTLE_ENDIAN);

pub const EXPLICIT_VR_BIG_ENDIAN: Ts = Ts::new(
    "1.2.840.10008.1.2.2",
    "Explicit VR Big Endian",
    Endianness::Big,
    true,
    Codec::None,
);
submit_transfer_syntax!(EXPLICIT_VR_BIG_ENDIAN);

// --- stub transfer syntaxes, known but not supported ---

pub const DEFLATED_EXPLICIT_VR_LITTLE_ENDIAN: Ts = Ts::new(
    "1.2.840.10008.1.2.1.99",
    "Deflated Explicit VR Little Endian",
    Endianness::Little,
    true,
    Codec::Unsupported,
);
submit_transfer_syntax!(DEFLATED_EXPLICIT_VR_LITTLE_ENDIAN);

pub const JPIP_DEREFERENCED_DEFLATE: Ts = Ts::new(
    "1.2.840.10008.1.2.4.95",
    "JPIP Referenced Deflate",
    Endianness::Little,
    true,
    Codec::Unsupported,
);
submit_transfer_syntax!(JPIP_DEREFERENCED_DEFLATE);

// --- partially supported transfer syntaxes, pixel data encapsulation not supported ---

pub const JPEG_BASELINE: Ts = create_ts_stub("1.2.840.10008.1.2.4.50", "JPEG Baseline (Process 1)");
submit_transfer_syntax!(JPEG_BASELINE);
pub const JPEG_EXTENDED: Ts = create_ts_stub("1.2.840.10008.1.2.4.51", "JPEG Extended (Process 2 & 4)");
submit_transfer_syntax!(JPEG_EXTENDED);
pub const JPEG_LOSSLESS_NON_HIERARCHICAL: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.57", "JPEG Lossless, Non-Hierarchical (Process 14)");
submit_transfer_syntax!(JPEG_LOSSLESS_NON_HIERARCHICAL);
pub const JPEG_LOSSLESS_NON_HIERARCHICAL_FIRST_ORDER_PREDICTION: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.70", "JPEG Lossless, Non-Hierarchical, First-Order Prediction");
submit_transfer_syntax!(JPEG_LOSSLESS_NON_HIERARCHICAL_FIRST_ORDER_PREDICTION);
pub const JPEG_LS_LOSSLESS_IMAGE_COMPRESSION: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.80", "JPEG-LS Lossless Image Compression");
submit_transfer_syntax!(JPEG_LS_LOSSLESS_IMAGE_COMPRESSION);
pub const JPEG_LS_LOSSY_IMAGE_COMPRESSION: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.81", "JPEG-LS Lossy (Near-Lossless) Image Compression");
submit_transfer_syntax!(JPEG_LS_LOSSY_IMAGE_COMPRESSION);
pub const JPEG_2000_IMAGE_COMPRESSION_LOSSLESS_ONLY: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.90", "JPEG 2000 Image Compression (Lossless Only)");
submit_transfer_syntax!(JPEG_2000_IMAGE_COMPRESSION_LOSSLESS_ONLY);
pub const JPEG_2000_IMAGE_COMPRESSION: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.91", "JPEG 2000 Image Compression");
submit_transfer_syntax!(JPEG_2000_IMAGE_COMPRESSION);
pub const JPEG_2000_PART2_MULTI_COMPONENT_IMAGE_COMPRESSION_LOSSLESS_ONLY: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.92", "JPEG 2000 Part 2 Multi-component Image Compression (Lossless Only)");
submit_transfer_syntax!(JPEG_2000_PART2_MULTI_COMPONENT_IMAGE_COMPRESSION_LOSSLESS_ONLY);
pub const JPEG_2000_PART2_MULTI_COMPONENT_IMAGE_COMPRESSION: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.93", "JPEG 2000 Part 2 Multi-component Image Compression");
submit_transfer_syntax!(JPEG_2000_PART2_MULTI_COMPONENT_IMAGE_COMPRESSION);
pub const JPIP_REFERENCED: Ts = create_ts_stub("1.2.840.10008.1.2.4.94", "JPIP Referenced");
submit_transfer_syntax!(JPIP_REFERENCED);
pub const MPEG2_MAIN_PROFILE_MAIN_LEVEL: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.100", "MPEG2 Main Profile / Main Level");
submit_transfer_syntax!(MPEG2_MAIN_PROFILE_MAIN_LEVEL);
pub const MPEG2_MAIN_PROFILE_HIGH_LEVEL: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.101", "MPEG2 Main Profile / High Level");
submit_transfer_syntax!(MPEG2_MAIN_PROFILE_HIGH_LEVEL);
pub const MPEG4_AVC_H264_HIGH_PROFILE: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.102", "MPEG-4 AVC/H.264 High Profile / Level 4.1");
submit_transfer_syntax!(MPEG4_AVC_H264_HIGH_PROFILE);
pub const MPEG4_AVC_H264_BD_COMPATIBLE_HIGH_PROFILE: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.103", "MPEG-4 AVC/H.264 BD-Compatible High Profile / Level 4.1");
submit_transfer_syntax!(MPEG4_AVC_H264_BD_COMPATIBLE_HIGH_PROFILE);
pub const MPEG4_AVC_H264_HIGH_PROFILE_FOR_2D_VIDEO: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.104", "MPEG-4 AVC/H.264 High Profile / Level 4.2 For 2D Video");
submit_transfer_syntax!(MPEG4_AVC_H264_HIGH_PROFILE_FOR_2D_VIDEO);
pub const MPEG4_AVC_H264_HIGH_PROFILE_FOR_3D_VIDEO: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.105", "MPEG-4 AVC/H.264 High Profile / Level 4.2 For 3D Video");
submit_transfer_syntax!(MPEG4_AVC_H264_HIGH_PROFILE_FOR_3D_VIDEO);
pub const MPEG4_AVC_H264_STEREO_HIGH_PROFILE: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.106", "MPEG-4 AVC/H.264 Stereo High Profile / Level 4.2");
submit_transfer_syntax!(MPEG4_AVC_H264_STEREO_HIGH_PROFILE);
pub const HEVC_H265_MAIN_PROFILE: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.107", "HEVC/H.265 Main Profile / Level 5.1");
submit_transfer_syntax!(HEVC_H265_MAIN_PROFILE);
pub const HEVC_H265_MAIN_10_PROFILE: Ts = create_ts_stub(
    "1.2.840.10008.1.2.4.108", "HEVC/H.265 Main 10 Profile / Level 5.1");
submit_transfer_syntax!(HEVC_H265_MAIN_10_PROFILE);
pub const RLE_LOSSLESS: Ts = create_ts_stub("1.2.840.10008.1.2.5", "RLE Lossless");
submit_transfer_syntax!(RLE_LOSSLESS);
<|endoftext|>


<commit_before>//! Common types for room directory endpoints.

use js_int::UInt;
use serde::{Deserialize, Serialize};

mod filter_room_type_serde;
mod room_network_serde;

use crate::{
    room::RoomType,
    serde::{Incoming, StringEnum},
    OwnedMxcUri, OwnedRoomAliasId, OwnedRoomId, PrivOwnedStr,
};

/// A chunk of a room list response, describing one room.
///
/// To create an instance of this type, first create a `PublicRoomsChunkInit` and convert it via
/// `PublicRoomsChunk::from` / `.into()`.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct PublicRoomsChunk {
    /// The canonical alias of the room, if any.
    #[serde(skip_serializing_if = "Option::is_none")]
    #[cfg_attr(
        feature = "compat",
        serde(default, deserialize_with = "crate::serde::empty_string_as_none")
    )]
    pub canonical_alias: Option<OwnedRoomAliasId>,

    /// The name of the room, if any.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,

    /// The number of members joined to the room.
    pub num_joined_members: UInt,

    /// The ID of the room.
    pub room_id: OwnedRoomId,

    /// The topic of the room, if any.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub topic: Option<String>,

    /// Whether the room may be viewed by guest users without joining.
    pub world_readable: bool,

    /// Whether guest users may join the room and participate in it.
    ///
    /// If they can, they will be subject to ordinary power level rules like any other user.
    pub guest_can_join: bool,

    /// The URL for the room's avatar, if one is set.
    ///
    /// If you activate the `compat` feature, this field being an empty string in JSON will result
    /// in `None` here during deserialization.
    #[serde(skip_serializing_if = "Option::is_none")]
    #[cfg_attr(
        feature = "compat",
        serde(default, deserialize_with = "crate::serde::empty_string_as_none")
    )]
    pub avatar_url: Option<OwnedMxcUri>,

    /// The join rule of the room.
    #[serde(default, skip_serializing_if = "crate::serde::is_default")]
    pub join_rule: PublicRoomJoinRule,

    /// The type of room from `m.room.create`, if any.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub room_type: Option<RoomType>,
}

/// Initial set of mandatory fields of `PublicRoomsChunk`.
///
/// This struct will not be updated even if additional fields are added to `PublicRoomsChunk` in a
/// new (non-breaking) release of the Matrix specification.
#[derive(Debug)]
#[allow(clippy::exhaustive_structs)]
pub struct PublicRoomsChunkInit {
    /// The number of members joined to the room.
    pub num_joined_members: UInt,

    /// The ID of the room.
    pub room_id: OwnedRoomId,

    /// Whether the room may be viewed by guest users without joining.
    pub world_readable: bool,

    /// Whether guest users may join the room and participate in it.
    ///
    /// If they can, they will be subject to ordinary power level rules like any other user.
    pub guest_can_join: bool,
}

impl From<PublicRoomsChunkInit> for PublicRoomsChunk {
    fn from(init: PublicRoomsChunkInit) -> Self {
        let PublicRoomsChunkInit { num_joined_members, room_id, world_readable, guest_can_join } =
            init;

        Self {
            canonical_alias: None,
            name: None,
            num_joined_members,
            room_id,
            topic: None,
            world_readable,
            guest_can_join,
            avatar_url: None,
            join_rule: PublicRoomJoinRule::default(),
            room_type: None,
        }
    }
}

/// A filter for public rooms lists
#[derive(Clone, Debug, Default, Incoming, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[incoming_derive(Default)]
pub struct Filter<'a> {
    /// A string to search for in the room metadata, e.g. name, topic, canonical alias etc.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub generic_search_term: Option<&'a str>,

    /// The room types to include in the results.
    ///
    /// Includes all room types if it is empty.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub room_types: Vec<RoomTypeFilter>,
}

impl Filter<'_> {
    /// Creates an empty `Filter`.
    pub fn new() -> Self {
        Default::default()
    }

    /// Returns `true` if the filter is empty.
    pub fn is_empty(&self) -> bool {
        self.generic_search_term.is_none()
    }
}

/// Information about which networks/protocols from application services on the
/// homeserver from which to request rooms.
#[derive(Clone, Debug, PartialEq, Eq, Incoming)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[incoming_derive(Clone, PartialEq, Eq, !Deserialize)]
pub enum RoomNetwork<'a> {
    /// Return rooms from the Matrix network.
    Matrix,

    /// Return rooms from all the networks/protocols the homeserver knows about.
    All,

    /// Return rooms from a specific third party network/protocol.
    ThirdParty(&'a str),
}

impl<'a> Default for RoomNetwork<'a> {
    fn default() -> Self {
        RoomNetwork::Matrix
    }
}

/// The rule used for users wishing to join a public room.
#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/string_enum.md"))]
#[derive(Clone, Debug, Default, PartialEq, Eq, StringEnum)]
#[ruma_enum(rename_all = "snake_case")]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum PublicRoomJoinRule {
    /// Users can request an invite to the room.
    Knock,

    /// Anyone can join the room without any prior action.
    #[default]
    Public,

    #[doc(hidden)]
    _Custom(PrivOwnedStr),
}

/// An enum of possible room types to filter.
///
/// This type can hold an arbitrary string. To build this with a custom value, convert it from an
/// `Option<string>` with `::from()` / `.into()`. [`RoomTypeFilter::Default`] can be constructed
/// from `None`.
///
/// To check for values that are not available as a documented variant here, use its string
/// representation, obtained through [`.as_str()`](Self::as_str()).
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum RoomTypeFilter {
    /// The default room type, defined without a `room_type`.
    Default,

    /// A space.
    Space,

    /// A custom room type.
    #[doc(hidden)]
    _Custom(PrivOwnedStr),
}

impl RoomTypeFilter {
    /// Get the string representation of this `RoomTypeFilter`.
    ///
    /// [`RoomTypeFilter::Default`] returns `None`.
    pub fn as_str(&self) -> Option<&str> {
        match self {
            RoomTypeFilter::Default => None,
            RoomTypeFilter::Space => Some("m.space"),
            RoomTypeFilter::_Custom(s) => Some(&s.0),
        }
    }
}

impl<T> From<Option<T>> for RoomTypeFilter
where
    T: AsRef<str> + Into<Box<str>>,
{
    fn from(s: Option<T>) -> Self {
        match s {
            None => Self::Default,
            Some(s) => match s.as_ref() {
                "m.space" => Self::Space,
                _ => Self::_Custom(PrivOwnedStr(s.into())),
            },
        }
    }
}

#[cfg(test)]
mod tests {
    use assert_matches::assert_matches;
    use serde_json::{from_value as from_json_value, json, to_value as to_json_value};

    use super::{Filter, IncomingFilter, IncomingRoomNetwork, RoomNetwork, RoomTypeFilter};

    #[test]
    fn serialize_matrix_network_only() {
        let json = json!({});
        assert_eq!(to_json_value(RoomNetwork::Matrix).unwrap(), json);
    }

    #[test]
    fn deserialize_matrix_network_only() {
        let json = json!({ "include_all_networks": false });
        assert_eq!(
            from_json_value::<IncomingRoomNetwork>(json).unwrap(),
            IncomingRoomNetwork::Matrix
        );
    }

    #[test]
    fn serialize_default_network_is_empty() {
        let json = json!({});
        assert_eq!(to_json_value(RoomNetwork::default()).unwrap(), json);
    }

    #[test]
    fn deserialize_empty_network_is_default() {
        let json = json!({});
        assert_eq!(
            from_json_value::<IncomingRoomNetwork>(json).unwrap(),
            IncomingRoomNetwork::Matrix
        );
    }

    #[test]
    fn serialize_include_all_networks() {
        let json = json!({ "include_all_networks": true });
        assert_eq!(to_json_value(RoomNetwork::All).unwrap(), json);
    }

    #[test]
    fn deserialize_include_all_networks() {
        let json = json!({ "include_all_networks": true });
        assert_eq!(from_json_value::<IncomingRoomNetwork>(json).unwrap(), IncomingRoomNetwork::All);
    }

    #[test]
    fn serialize_third_party_network() {
        let json = json!({ "third_party_instance_id": "freenode" });
        assert_eq!(to_json_value(RoomNetwork::ThirdParty("freenode")).unwrap(), json);
    }

    #[test]
    fn deserialize_third_party_network() {
        let json = json!({ "third_party_instance_id": "freenode" });
        assert_eq!(
            from_json_value::<IncomingRoomNetwork>(json).unwrap(),
            IncomingRoomNetwork::ThirdParty("freenode".into())
        );
    }

    #[test]
    fn deserialize_include_all_networks_and_third_party_exclusivity() {
        let json = json!({ "include_all_networks": true, "third_party_instance_id": "freenode" });
        assert_eq!(
            from_json_value::<IncomingRoomNetwork>(json).unwrap_err().to_string().as_str(),
            "`include_all_networks = true` and `third_party_instance_id` are mutually exclusive."
        );
    }

    #[test]
    fn serialize_filter_empty() {
        let filter = Filter::default();
        let json = json!({});
        assert_eq!(to_json_value(filter).unwrap(), json);
    }

    #[test]
    fn deserialize_filter_empty() {
        let json = json!({});
        let filter = from_json_value::<IncomingFilter>(json).unwrap();
        assert_eq!(filter.generic_search_term, None);
        assert_eq!(filter.room_types.len(), 0);
    }

    #[test]
    fn serialize_filter_room_types() {
        let filter = Filter {
            generic_search_term: None,
            room_types: vec![
                RoomTypeFilter::Default,
                RoomTypeFilter::Space,
                Some("custom_type").into(),
            ],
        };
        let json = json!({ "room_types": [null, "m.space", "custom_type"] });
        assert_eq!(to_json_value(filter).unwrap(), json);
    }

    #[test]
    fn deserialize_filter_room_types() {
        let json = json!({ "room_types": [null, "m.space", "custom_type"] });
        let filter = from_json_value::<IncomingFilter>(json).unwrap();
        assert_eq!(filter.room_types.len(), 3);
        assert_eq!(filter.room_types[0], RoomTypeFilter::Default);
        assert_eq!(filter.room_types[1], RoomTypeFilter::Space);
        assert_matches!(filter.room_types[2], RoomTypeFilter::_Custom(_));
        assert_eq!(filter.room_types[2].as_str(), Some("custom_type"));
    }
}
<commit_msg>common: Derive Default for (Incoming)RoomNetwork<commit_after>//! Common types for room directory endpoints.

use js_int::UInt;
use serde::{Deserialize, Serialize};

mod filter_room_type_serde;
mod room_network_serde;

use crate::{
    room::RoomType,
    serde::{Incoming, StringEnum},
    OwnedMxcUri, OwnedRoomAliasId, OwnedRoomId, PrivOwnedStr,
};

/// A chunk of a room list response, describing one room.
///
/// To create an instance of this type, first create a `PublicRoomsChunkInit` and convert it via
/// `PublicRoomsChunk::from` / `.into()`.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub struct PublicRoomsChunk {
    /// The canonical alias of the room, if any.
    #[serde(skip_serializing_if = "Option::is_none")]
    #[cfg_attr(
        feature = "compat",
        serde(default, deserialize_with = "crate::serde::empty_string_as_none")
    )]
    pub canonical_alias: Option<OwnedRoomAliasId>,

    /// The name of the room, if any.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub name: Option<String>,

    /// The number of members joined to the room.
    pub num_joined_members: UInt,

    /// The ID of the room.
    pub room_id: OwnedRoomId,

    /// The topic of the room, if any.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub topic: Option<String>,

    /// Whether the room may be viewed by guest users without joining.
    pub world_readable: bool,

    /// Whether guest users may join the room and participate in it.
    ///
    /// If they can, they will be subject to ordinary power level rules like any other user.
    pub guest_can_join: bool,

    /// The URL for the room's avatar, if one is set.
    ///
    /// If you activate the `compat` feature, this field being an empty string in JSON will result
    /// in `None` here during deserialization.
    #[serde(skip_serializing_if = "Option::is_none")]
    #[cfg_attr(
        feature = "compat",
        serde(default, deserialize_with = "crate::serde::empty_string_as_none")
    )]
    pub avatar_url: Option<OwnedMxcUri>,

    /// The join rule of the room.
    #[serde(default, skip_serializing_if = "crate::serde::is_default")]
    pub join_rule: PublicRoomJoinRule,

    /// The type of room from `m.room.create`, if any.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub room_type: Option<RoomType>,
}

/// Initial set of mandatory fields of `PublicRoomsChunk`.
///
/// This struct will not be updated even if additional fields are added to `PublicRoomsChunk` in a
/// new (non-breaking) release of the Matrix specification.
#[derive(Debug)]
#[allow(clippy::exhaustive_structs)]
pub struct PublicRoomsChunkInit {
    /// The number of members joined to the room.
    pub num_joined_members: UInt,

    /// The ID of the room.
    pub room_id: OwnedRoomId,

    /// Whether the room may be viewed by guest users without joining.
    pub world_readable: bool,

    /// Whether guest users may join the room and participate in it.
    ///
    /// If they can, they will be subject to ordinary power level rules like any other user.
    pub guest_can_join: bool,
}

impl From<PublicRoomsChunkInit> for PublicRoomsChunk {
    fn from(init: PublicRoomsChunkInit) -> Self {
        let PublicRoomsChunkInit { num_joined_members, room_id, world_readable, guest_can_join } =
            init;

        Self {
            canonical_alias: None,
            name: None,
            num_joined_members,
            room_id,
            topic: None,
            world_readable,
            guest_can_join,
            avatar_url: None,
            join_rule: PublicRoomJoinRule::default(),
            room_type: None,
        }
    }
}

/// A filter for public rooms lists
#[derive(Clone, Debug, Default, Incoming, Serialize)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[incoming_derive(Default)]
pub struct Filter<'a> {
    /// A string to search for in the room metadata, e.g. name, topic, canonical alias etc.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub generic_search_term: Option<&'a str>,

    /// The room types to include in the results.
    ///
    /// Includes all room types if it is empty.
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub room_types: Vec<RoomTypeFilter>,
}

impl Filter<'_> {
    /// Creates an empty `Filter`.
    pub fn new() -> Self {
        Default::default()
    }

    /// Returns `true` if the filter is empty.
    pub fn is_empty(&self) -> bool {
        self.generic_search_term.is_none()
    }
}

/// Information about which networks/protocols from application services on the
/// homeserver from which to request rooms.
#[derive(Clone, Debug, Default, PartialEq, Eq, Incoming)]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
#[incoming_derive(Clone, Default, PartialEq, Eq, !Deserialize)]
pub enum RoomNetwork<'a> {
    /// Return rooms from the Matrix network.
    #[default]
    Matrix,

    /// Return rooms from all the networks/protocols the homeserver knows about.
    All,

    /// Return rooms from a specific third party network/protocol.
    ThirdParty(&'a str),
}

/// The rule used for users wishing to join a public room.
#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/string_enum.md"))]
#[derive(Clone, Debug, Default, PartialEq, Eq, StringEnum)]
#[ruma_enum(rename_all = "snake_case")]
#[cfg_attr(not(feature = "unstable-exhaustive-types"), non_exhaustive)]
pub enum PublicRoomJoinRule {
    /// Users can request an invite to the room.
    Knock,

    /// Anyone can join the room without any prior action.
    #[default]
    Public,

    #[doc(hidden)]
    _Custom(PrivOwnedStr),
}

/// An enum of possible room types to filter.
///
/// This type can hold an arbitrary string. To build this with a custom value, convert it from an
/// `Option<string>` with `::from()` / `.into()`. [`RoomTypeFilter::Default`] can be constructed
/// from `None`.
///
/// To check for values that are not available as a documented variant here, use its string
/// representation, obtained through [`.as_str()`](Self::as_str()).
#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum RoomTypeFilter {
    /// The default room type, defined without a `room_type`.
    Default,

    /// A space.
    Space,

    /// A custom room type.
    #[doc(hidden)]
    _Custom(PrivOwnedStr),
}

impl RoomTypeFilter {
    /// Get the string representation of this `RoomTypeFilter`.
    ///
    /// [`RoomTypeFilter::Default`] returns `None`.
    pub fn as_str(&self) -> Option<&str> {
        match self {
            RoomTypeFilter::Default => None,
            RoomTypeFilter::Space => Some("m.space"),
            RoomTypeFilter::_Custom(s) => Some(&s.0),
        }
    }
}

impl<T> From<Option<T>> for RoomTypeFilter
where
    T: AsRef<str> + Into<Box<str>>,
{
    fn from(s: Option<T>) -> Self {
        match s {
            None => Self::Default,
            Some(s) => match s.as_ref() {
                "m.space" => Self::Space,
                _ => Self::_Custom(PrivOwnedStr(s.into())),
            },
        }
    }
}

#[cfg(test)]
mod tests {
    use assert_matches::assert_matches;
    use serde_json::{from_value as from_json_value, json, to_value as to_json_value};

    use super::{Filter, IncomingFilter, IncomingRoomNetwork, RoomNetwork, RoomTypeFilter};

    #[test]
    fn serialize_matrix_network_only() {
        let json = json!({});
        assert_eq!(to_json_value(RoomNetwork::Matrix).unwrap(), json);
    }

    #[test]
    fn deserialize_matrix_network_only() {
        let json = json!({ "include_all_networks": false });
        assert_eq!(
            from_json_value::<IncomingRoomNetwork>(json).unwrap(),
            IncomingRoomNetwork::Matrix
        );
    }

    #[test]
    fn serialize_default_network_is_empty() {
        let json = json!({});
        assert_eq!(to_json_value(RoomNetwork::default()).unwrap(), json);
    }

    #[test]
    fn deserialize_empty_network_is_default() {
        let json = json!({});
        assert_eq!(
            from_json_value::<IncomingRoomNetwork>(json).unwrap(),
            IncomingRoomNetwork::Matrix
        );
    }

    #[test]
    fn serialize_include_all_networks() {
        let json = json!({ "include_all_networks": true });
        assert_eq!(to_json_value(RoomNetwork::All).unwrap(), json);
    }

    #[test]
    fn deserialize_include_all_networks() {
        let json = json!({ "include_all_networks": true });
        assert_eq!(from_json_value::<IncomingRoomNetwork>(json).unwrap(), IncomingRoomNetwork::All);
    }

    #[test]
    fn serialize_third_party_network() {
        let json = json!({ "third_party_instance_id": "freenode" });
        assert_eq!(to_json_value(RoomNetwork::ThirdParty("freenode")).unwrap(), json);
    }

    #[test]
    fn deserialize_third_party_network() {
        let json = json!({ "third_party_instance_id": "freenode" });
        assert_eq!(
            from_json_value::<IncomingRoomNetwork>(json).unwrap(),
            IncomingRoomNetwork::ThirdParty("freenode".into())
        );
    }

    #[test]
    fn deserialize_include_all_networks_and_third_party_exclusivity() {
        let json = json!({ "include_all_networks": true, "third_party_instance_id": "freenode" });
        assert_eq!(
            from_json_value::<IncomingRoomNetwork>(json).unwrap_err().to_string().as_str(),
            "`include_all_networks = true` and `third_party_instance_id` are mutually exclusive."
        );
    }

    #[test]
    fn serialize_filter_empty() {
        let filter = Filter::default();
        let json = json!({});
        assert_eq!(to_json_value(filter).unwrap(), json);
    }

    #[test]
    fn deserialize_filter_empty() {
        let json = json!({});
        let filter = from_json_value::<IncomingFilter>(json).unwrap();
        assert_eq!(filter.generic_search_term, None);
        assert_eq!(filter.room_types.len(), 0);
    }

    #[test]
    fn serialize_filter_room_types() {
        let filter = Filter {
            generic_search_term: None,
            room_types: vec![
                RoomTypeFilter::Default,
                RoomTypeFilter::Space,
                Some("custom_type").into(),
            ],
        };
        let json = json!({ "room_types": [null, "m.space", "custom_type"] });
        assert_eq!(to_json_value(filter).unwrap(), json);
    }

    #[test]
    fn deserialize_filter_room_types() {
        let json = json!({ "room_types": [null, "m.space", "custom_type"] });
        let filter = from_json_value::<IncomingFilter>(json).unwrap();
        assert_eq!(filter.room_types.len(), 3);
        assert_eq!(filter.room_types[0], RoomTypeFilter::Default);
        assert_eq!(filter.room_types[1], RoomTypeFilter::Space);
        assert_matches!(filter.room_types[2], RoomTypeFilter::_Custom(_));
        assert_eq!(filter.room_types[2].as_str(), Some("custom_type"));
    }
}
<|endoftext|>


<commit_before>use std::cell::Cell;
use std::mem;

use crossbeam_utils::CachePadded;

#[test]
fn default() {
    let x: CachePadded<u64> = Default::default();
    assert_eq!(*x, 0);
}

#[test]
fn store_u64() {
    let x: CachePadded<u64> = CachePadded::new(17);
    assert_eq!(*x, 17);
}

#[test]
fn store_pair() {
    let x: CachePadded<(u64, u64)> = CachePadded::new((17, 37));
    assert_eq!(x.0, 17);
    assert_eq!(x.1, 37);
}

#[test]
fn distance() {
    let arr = [CachePadded::new(17u8), CachePadded::new(37u8)];
    let a = &*arr[0] as *const u8;
    let b = &*arr[1] as *const u8;
    assert!(unsafe { a.offset(64) } <= b);
}

#[test]
fn different_sizes() {
    CachePadded::new(17u8);
    CachePadded::new(17u16);
    CachePadded::new(17u32);
    CachePadded::new([17u64; 0]);
    CachePadded::new([17u64; 1]);
    CachePadded::new([17u64; 2]);
    CachePadded::new([17u64; 3]);
    CachePadded::new([17u64; 4]);
    CachePadded::new([17u64; 5]);
    CachePadded::new([17u64; 6]);
    CachePadded::new([17u64; 7]);
    CachePadded::new([17u64; 8]);
}

#[test]
fn large() {
    let a = [17u64; 9];
    let b = CachePadded::new(a);
    assert!(mem::size_of_val(&a) <= mem::size_of_val(&b));
}

#[test]
fn debug() {
    assert_eq!(
        format!("{:?}", CachePadded::new(17u64)),
        "CachePadded { value: 17 }"
    );
}

#[test]
fn drops() {
    let count = Cell::new(0);

    struct Foo<'a>(&'a Cell<usize>);

    impl<'a> Drop for Foo<'a> {
        fn drop(&mut self) {
            self.0.set(self.0.get() + 1);
        }
    }

    let a = CachePadded::new(Foo(&count));
    let b = CachePadded::new(Foo(&count));

    assert_eq!(count.get(), 0);
    drop(a);
    assert_eq!(count.get(), 1);
    drop(b);
    assert_eq!(count.get(), 2);
}

#[test]
fn clone() {
    let a = CachePadded::new(17);
    let b = a.clone();
    assert_eq!(*a, *b);
}

#[test]
fn runs_custom_clone() {
    let count = Cell::new(0);

    struct Foo<'a>(&'a Cell<usize>);

    impl<'a> Clone for Foo<'a> {
        fn clone(&self) -> Foo<'a> {
            self.0.set(self.0.get() + 1);
            Foo::<'a>(self.0)
        }
    }

    let a = CachePadded::new(Foo(&count));
    let _ = a.clone();

    assert_eq!(count.get(), 1);
}
<commit_msg>Fix CachePadded test<commit_after>use std::cell::Cell;
use std::mem;

use crossbeam_utils::CachePadded;

#[test]
fn default() {
    let x: CachePadded<u64> = Default::default();
    assert_eq!(*x, 0);
}

#[test]
fn store_u64() {
    let x: CachePadded<u64> = CachePadded::new(17);
    assert_eq!(*x, 17);
}

#[test]
fn store_pair() {
    let x: CachePadded<(u64, u64)> = CachePadded::new((17, 37));
    assert_eq!(x.0, 17);
    assert_eq!(x.1, 37);
}

#[test]
fn distance() {
    let arr = [CachePadded::new(17u8), CachePadded::new(37u8)];
    let a = &*arr[0] as *const u8;
    let b = &*arr[1] as *const u8;
    let align = mem::align_of::<CachePadded<()>>();
    assert!(align >= 32);
    assert_eq!(unsafe { a.add(align) }, b);
}

#[test]
fn different_sizes() {
    CachePadded::new(17u8);
    CachePadded::new(17u16);
    CachePadded::new(17u32);
    CachePadded::new([17u64; 0]);
    CachePadded::new([17u64; 1]);
    CachePadded::new([17u64; 2]);
    CachePadded::new([17u64; 3]);
    CachePadded::new([17u64; 4]);
    CachePadded::new([17u64; 5]);
    CachePadded::new([17u64; 6]);
    CachePadded::new([17u64; 7]);
    CachePadded::new([17u64; 8]);
}

#[test]
fn large() {
    let a = [17u64; 9];
    let b = CachePadded::new(a);
    assert!(mem::size_of_val(&a) <= mem::size_of_val(&b));
}

#[test]
fn debug() {
    assert_eq!(
        format!("{:?}", CachePadded::new(17u64)),
        "CachePadded { value: 17 }"
    );
}

#[test]
fn drops() {
    let count = Cell::new(0);

    struct Foo<'a>(&'a Cell<usize>);

    impl<'a> Drop for Foo<'a> {
        fn drop(&mut self) {
            self.0.set(self.0.get() + 1);
        }
    }

    let a = CachePadded::new(Foo(&count));
    let b = CachePadded::new(Foo(&count));

    assert_eq!(count.get(), 0);
    drop(a);
    assert_eq!(count.get(), 1);
    drop(b);
    assert_eq!(count.get(), 2);
}

#[test]
fn clone() {
    let a = CachePadded::new(17);
    let b = a.clone();
    assert_eq!(*a, *b);
}

#[test]
fn runs_custom_clone() {
    let count = Cell::new(0);

    struct Foo<'a>(&'a Cell<usize>);

    impl<'a> Clone for Foo<'a> {
        fn clone(&self) -> Foo<'a> {
            self.0.set(self.0.get() + 1);
            Foo::<'a>(self.0)
        }
    }

    let a = CachePadded::new(Foo(&count));
    let _ = a.clone();

    assert_eq!(count.get(), 1);
}
<|endoftext|>


<commit_before>//! A pure rust replacement for the [miniz](https://github.com/richgel999/miniz)
//! DEFLATE/zlib encoder/decoder.
//! The plan for this crate is to be used as a back-end for the
//! [flate2](https://github.com/alexcrichton/flate2-rs) crate and eventually remove the
//! need to depend on a C library.
//!
//! # Usage
//! ## Simple compression/decompression:
//! ``` rust
//!
//! use miniz_oxide::inflate::decompress_to_vec;
//! use miniz_oxide::deflate::compress_to_vec;
//!
//! fn roundtrip(data: &[u8]) {
//!     let compressed = compress_to_vec(data, 6);
//!     let decompressed = decompress_to_vec(compressed.as_slice()).expect("Failed to decompress!");
//! #   let _ = decompressed;
//! }
//!
//! # roundtrip(b"Test_data test data lalalal blabla");
//!
//! ```

extern crate adler32;

pub mod deflate;
pub mod inflate;
mod shared;

pub use crate::shared::update_adler32 as mz_adler32_oxide;
pub use crate::shared::{MZ_ADLER32_INIT, MZ_DEFAULT_WINDOW_BITS};

/// A list of flush types.
///
/// See [http://www.bolet.org/~pornin/deflate-flush.html] for more in-depth info.
#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum MZFlush {
    /// Don't force any flushing.
    /// Used when more input data is expected.
    None = 0,
    /// Zlib partial flush.
    /// Currently treated as `Sync`.
    Partial = 1,
    /// Finish compressing the currently buffered data, and output an empty raw block.
    /// Has no use in decompression.
    Sync = 2,
    /// Same as `Sync`, but resets the compression dictionary so that further compressed
    /// data does not depend on data compressed before the flush.
    /// Has no use in decompression.
    Full = 3,
    /// Attempt to flush the remaining data and end the stream.
    Finish = 4,
    /// Not implemented.
    Block = 5,
}

impl MZFlush {
    /// Create an MZFlush value from an integer value.
    ///
    /// Returns `MZError::Param` on invalid values.
    pub fn new(flush: i32) -> Result<Self, MZError> {
        match flush {
            0 => Ok(MZFlush::None),
            1 | 2 => Ok(MZFlush::Sync),
            3 => Ok(MZFlush::Full),
            4 => Ok(MZFlush::Finish),
            _ => Err(MZError::Param),
        }
    }
}

/// A list of miniz successful status codes.
#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum MZStatus {
    Ok = 0,
    StreamEnd = 1,
    NeedDict = 2,
}

/// A list of miniz failed status codes.
#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum MZError {
    ErrNo = -1,
    Stream = -2,
    Data = -3,
    Mem = -4,
    Buf = -5,
    Version = -6,
    Param = -10_000,
}

/// How compressed data is wrapped.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum DataFormat {
    /// Wrapped using the [zlib](http://www.zlib.org/rfc-zlib.html) format.
    Zlib,
    /// Raw DEFLATE.
    Raw,
}

impl DataFormat {
    pub(crate) fn from_window_bits(window_bits: i32) -> DataFormat {
        if window_bits > 0 {
            DataFormat::Zlib
        } else {
            DataFormat::Raw
        }
    }

    pub(crate) fn to_window_bits(self) -> i32 {
        match self {
            DataFormat::Zlib => shared::MZ_DEFAULT_WINDOW_BITS,
            DataFormat::Raw => -shared::MZ_DEFAULT_WINDOW_BITS,
        }
    }
}

/// `Result` alias for all miniz status codes both successful and failed.
pub type MZResult = Result<MZStatus, MZError>;

/// A structure containg the result of a call to the inflate or deflate streaming functions.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct StreamResult {
    /// The number of bytes consumed from the input slice.
    pub bytes_consumed: usize,
    /// The number of bytes written to the output slice.
    pub bytes_written: usize,
    /// The return status of the call.
    pub status: MZResult,
}

impl StreamResult {
    #[inline]
    pub(crate) fn error(error: MZError) -> StreamResult {
        StreamResult {
            bytes_consumed: 0,
            bytes_written: 0,
            status: Err(error),
        }
    }
}

impl std::convert::From<StreamResult> for MZResult {
    fn from(res: StreamResult) -> Self {
        res.status
    }
}

impl std::convert::From<&StreamResult> for MZResult {
    fn from(res: &StreamResult) -> Self {
        res.status
    }
}
<commit_msg>Forbid unsafe code in the core crate (#56)<commit_after>//! A pure rust replacement for the [miniz](https://github.com/richgel999/miniz)
//! DEFLATE/zlib encoder/decoder.
//! The plan for this crate is to be used as a back-end for the
//! [flate2](https://github.com/alexcrichton/flate2-rs) crate and eventually remove the
//! need to depend on a C library.
//!
//! # Usage
//! ## Simple compression/decompression:
//! ``` rust
//!
//! use miniz_oxide::inflate::decompress_to_vec;
//! use miniz_oxide::deflate::compress_to_vec;
//!
//! fn roundtrip(data: &[u8]) {
//!     let compressed = compress_to_vec(data, 6);
//!     let decompressed = decompress_to_vec(compressed.as_slice()).expect("Failed to decompress!");
//! #   let _ = decompressed;
//! }
//!
//! # roundtrip(b"Test_data test data lalalal blabla");
//!
//! ```

#![forbid(unsafe_code)]

extern crate adler32;

pub mod deflate;
pub mod inflate;
mod shared;

pub use crate::shared::update_adler32 as mz_adler32_oxide;
pub use crate::shared::{MZ_ADLER32_INIT, MZ_DEFAULT_WINDOW_BITS};

/// A list of flush types.
///
/// See [http://www.bolet.org/~pornin/deflate-flush.html] for more in-depth info.
#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum MZFlush {
    /// Don't force any flushing.
    /// Used when more input data is expected.
    None = 0,
    /// Zlib partial flush.
    /// Currently treated as `Sync`.
    Partial = 1,
    /// Finish compressing the currently buffered data, and output an empty raw block.
    /// Has no use in decompression.
    Sync = 2,
    /// Same as `Sync`, but resets the compression dictionary so that further compressed
    /// data does not depend on data compressed before the flush.
    /// Has no use in decompression.
    Full = 3,
    /// Attempt to flush the remaining data and end the stream.
    Finish = 4,
    /// Not implemented.
    Block = 5,
}

impl MZFlush {
    /// Create an MZFlush value from an integer value.
    ///
    /// Returns `MZError::Param` on invalid values.
    pub fn new(flush: i32) -> Result<Self, MZError> {
        match flush {
            0 => Ok(MZFlush::None),
            1 | 2 => Ok(MZFlush::Sync),
            3 => Ok(MZFlush::Full),
            4 => Ok(MZFlush::Finish),
            _ => Err(MZError::Param),
        }
    }
}

/// A list of miniz successful status codes.
#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum MZStatus {
    Ok = 0,
    StreamEnd = 1,
    NeedDict = 2,
}

/// A list of miniz failed status codes.
#[repr(i32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum MZError {
    ErrNo = -1,
    Stream = -2,
    Data = -3,
    Mem = -4,
    Buf = -5,
    Version = -6,
    Param = -10_000,
}

/// How compressed data is wrapped.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum DataFormat {
    /// Wrapped using the [zlib](http://www.zlib.org/rfc-zlib.html) format.
    Zlib,
    /// Raw DEFLATE.
    Raw,
}

impl DataFormat {
    pub(crate) fn from_window_bits(window_bits: i32) -> DataFormat {
        if window_bits > 0 {
            DataFormat::Zlib
        } else {
            DataFormat::Raw
        }
    }

    pub(crate) fn to_window_bits(self) -> i32 {
        match self {
            DataFormat::Zlib => shared::MZ_DEFAULT_WINDOW_BITS,
            DataFormat::Raw => -shared::MZ_DEFAULT_WINDOW_BITS,
        }
    }
}

/// `Result` alias for all miniz status codes both successful and failed.
pub type MZResult = Result<MZStatus, MZError>;

/// A structure containg the result of a call to the inflate or deflate streaming functions.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct StreamResult {
    /// The number of bytes consumed from the input slice.
    pub bytes_consumed: usize,
    /// The number of bytes written to the output slice.
    pub bytes_written: usize,
    /// The return status of the call.
    pub status: MZResult,
}

impl StreamResult {
    #[inline]
    pub(crate) fn error(error: MZError) -> StreamResult {
        StreamResult {
            bytes_consumed: 0,
            bytes_written: 0,
            status: Err(error),
        }
    }
}

impl std::convert::From<StreamResult> for MZResult {
    fn from(res: StreamResult) -> Self {
        res.status
    }
}

impl std::convert::From<&StreamResult> for MZResult {
    fn from(res: &StreamResult) -> Self {
        res.status
    }
}
<|endoftext|>


<commit_before>use crossbeam_channel::Sender;
use std::fmt::Display;

use pueue_lib::network::message::*;
use pueue_lib::settings::PUEUE_DEFAULT_GROUP;
use pueue_lib::state::SharedState;

use crate::network::response_helper::*;

mod add;
mod clean;
mod edit;
mod enqueue;
mod group;
mod kill;
mod log;
mod parallel;
mod pause;
mod remove;
mod restart;
mod send;
mod start;
mod stash;
mod switch;

pub static SENDER_ERR: &str = "Failed to send message to task handler thread";

pub fn handle_message(message: Message, sender: &Sender<Message>, state: &SharedState) -> Message {
    match message {
        Message::Add(message) => add::add_task(message, sender, state),
        Message::Clean(message) => clean::clean(message, state),
        Message::Edit(message) => edit::edit(message, state),
        Message::EditRequest(task_id) => edit::edit_request(task_id, state),
        Message::Enqueue(message) => enqueue::enqueue(message, state),
        Message::Group(message) => group::group(message, sender, state),
        Message::Kill(message) => kill::kill(message, sender, state),
        Message::Log(message) => log::get_log(message, state),
        Message::Parallel(message) => parallel::set_parallel_tasks(message, state),
        Message::Pause(message) => pause::pause(message, sender, state),
        Message::Remove(task_ids) => remove::remove(task_ids, state),
        Message::Reset(message) => reset(message, sender),
        Message::Restart(message) => restart::restart_multiple(message, sender, state),
        Message::Send(message) => send::send(message, sender, state),
        Message::Start(message) => start::start(message, sender, state),
        Message::Stash(task_ids) => stash::stash(task_ids, state),
        Message::Switch(message) => switch::switch(message, state),
        Message::Status => get_status(state),
        _ => create_failure_message("Not yet implemented"),
    }
}

/// Invoked when calling `pueue reset`.
/// Forward the reset request to the task handler.
/// The handler then kills all children and clears the task queue.
fn reset(message: ResetMessage, sender: &Sender<Message>) -> Message {
    sender.send(Message::Reset(message)).expect(SENDER_ERR);
    create_success_message("Everything is being reset right now.")
}

/// Invoked when calling `pueue status`.
/// Return the current state.
fn get_status(state: &SharedState) -> Message {
    let state = state.lock().unwrap().clone();
    Message::StatusResponse(Box::new(state))
}

fn ok_or_failure_message<T, E: Display>(result: Result<T, E>) -> Result<T, Message> {
    match result {
        Ok(inner) => Ok(inner),
        Err(error) => Err(create_failure_message(format!(
            "Failed to save state. This is a bug: {}",
            error
        ))),
    }
}

#[macro_export]
macro_rules! ok_or_return_failure_message {
    ($expression:expr) => {
        match ok_or_failure_message($expression) {
            Ok(task_id) => task_id,
            Err(error) => return error,
        }
    };
}

#[cfg(test)]
mod fixtures {
    pub use crossbeam_channel::Sender;
    use std::collections::HashMap;
    use std::sync::{Arc, Mutex};
    use tempfile::TempDir;

    pub use pueue_lib::network::message::*;
    pub use pueue_lib::network::protocol::socket_cleanup;
    pub use pueue_lib::settings::Settings;
    pub use pueue_lib::state::{SharedState, State};
    pub use pueue_lib::task::{Task, TaskResult, TaskStatus};

    pub use super::*;
    pub use crate::network::response_helper::*;

    pub fn get_settings() -> (Settings, TempDir) {
        let tempdir = TempDir::new().expect("Failed to create test pueue directory");
        let mut settings: Settings = Settings::default_config()
            .expect("Failed to get default config")
            .try_into()
            .expect("Failed to get test settings");
        settings.shared.pueue_directory = tempdir.path().clone().to_owned();

        (settings, tempdir)
    }

    pub fn get_state() -> (SharedState, TempDir) {
        let (settings, tempdir) = get_settings();

        // Create the normal pueue directories.
        let log_dir = tempdir.path().join("log");
        if !log_dir.exists() {
            std::fs::create_dir(log_dir).expect("Failed to create test log dir");
        }
        let task_log_dir = tempdir.path().join("task_log");
        if !task_log_dir.exists() {
            std::fs::create_dir(task_log_dir).expect("Failed to create test task log dir");
        }

        let state = State::new(&settings, None);
        (Arc::new(Mutex::new(state)), tempdir)
    }

    /// Create a new task with stub data
    pub fn get_stub_task(id: &str, status: TaskStatus) -> Task {
        Task::new(
            format!("{}", id),
            "/tmp".to_string(),
            HashMap::new(),
            PUEUE_DEFAULT_GROUP.to_string(),
            status,
            Vec::new(),
            None,
        )
    }

    pub fn get_stub_state() -> (SharedState, TempDir) {
        let (state, tempdir) = get_state();
        {
            // Queued task
            let mut state = state.lock().unwrap();
            let task = get_stub_task("0", TaskStatus::Queued);
            state.add_task(task);

            // Finished task
            let task = get_stub_task("1", TaskStatus::Done(TaskResult::Success));
            state.add_task(task);

            // Stashed task
            let task = get_stub_task("2", TaskStatus::Stashed { enqueue_at: None });
            state.add_task(task);

            // Running task
            let task = get_stub_task("3", TaskStatus::Running);
            state.add_task(task);

            // Paused task
            let task = get_stub_task("4", TaskStatus::Paused);
            state.add_task(task);
        }

        (state, tempdir)
    }
}
<commit_msg>fix: Clippy issue<commit_after>use crossbeam_channel::Sender;
use std::fmt::Display;

use pueue_lib::network::message::*;
use pueue_lib::state::SharedState;

use crate::network::response_helper::*;

mod add;
mod clean;
mod edit;
mod enqueue;
mod group;
mod kill;
mod log;
mod parallel;
mod pause;
mod remove;
mod restart;
mod send;
mod start;
mod stash;
mod switch;

pub static SENDER_ERR: &str = "Failed to send message to task handler thread";

pub fn handle_message(message: Message, sender: &Sender<Message>, state: &SharedState) -> Message {
    match message {
        Message::Add(message) => add::add_task(message, sender, state),
        Message::Clean(message) => clean::clean(message, state),
        Message::Edit(message) => edit::edit(message, state),
        Message::EditRequest(task_id) => edit::edit_request(task_id, state),
        Message::Enqueue(message) => enqueue::enqueue(message, state),
        Message::Group(message) => group::group(message, sender, state),
        Message::Kill(message) => kill::kill(message, sender, state),
        Message::Log(message) => log::get_log(message, state),
        Message::Parallel(message) => parallel::set_parallel_tasks(message, state),
        Message::Pause(message) => pause::pause(message, sender, state),
        Message::Remove(task_ids) => remove::remove(task_ids, state),
        Message::Reset(message) => reset(message, sender),
        Message::Restart(message) => restart::restart_multiple(message, sender, state),
        Message::Send(message) => send::send(message, sender, state),
        Message::Start(message) => start::start(message, sender, state),
        Message::Stash(task_ids) => stash::stash(task_ids, state),
        Message::Switch(message) => switch::switch(message, state),
        Message::Status => get_status(state),
        _ => create_failure_message("Not yet implemented"),
    }
}

/// Invoked when calling `pueue reset`.
/// Forward the reset request to the task handler.
/// The handler then kills all children and clears the task queue.
fn reset(message: ResetMessage, sender: &Sender<Message>) -> Message {
    sender.send(Message::Reset(message)).expect(SENDER_ERR);
    create_success_message("Everything is being reset right now.")
}

/// Invoked when calling `pueue status`.
/// Return the current state.
fn get_status(state: &SharedState) -> Message {
    let state = state.lock().unwrap().clone();
    Message::StatusResponse(Box::new(state))
}

fn ok_or_failure_message<T, E: Display>(result: Result<T, E>) -> Result<T, Message> {
    match result {
        Ok(inner) => Ok(inner),
        Err(error) => Err(create_failure_message(format!(
            "Failed to save state. This is a bug: {}",
            error
        ))),
    }
}

#[macro_export]
macro_rules! ok_or_return_failure_message {
    ($expression:expr) => {
        match ok_or_failure_message($expression) {
            Ok(task_id) => task_id,
            Err(error) => return error,
        }
    };
}

#[cfg(test)]
mod fixtures {
    pub use crossbeam_channel::Sender;
    use std::collections::HashMap;
    use std::sync::{Arc, Mutex};
    use tempfile::TempDir;

    pub use pueue_lib::network::message::*;
    pub use pueue_lib::network::protocol::socket_cleanup;
    pub use pueue_lib::settings::{Settings, PUEUE_DEFAULT_GROUP};
    pub use pueue_lib::state::{SharedState, State};
    pub use pueue_lib::task::{Task, TaskResult, TaskStatus};

    pub use super::*;
    pub use crate::network::response_helper::*;

    pub fn get_settings() -> (Settings, TempDir) {
        let tempdir = TempDir::new().expect("Failed to create test pueue directory");
        let mut settings: Settings = Settings::default_config()
            .expect("Failed to get default config")
            .try_into()
            .expect("Failed to get test settings");
        settings.shared.pueue_directory = tempdir.path().clone().to_owned();

        (settings, tempdir)
    }

    pub fn get_state() -> (SharedState, TempDir) {
        let (settings, tempdir) = get_settings();

        // Create the normal pueue directories.
        let log_dir = tempdir.path().join("log");
        if !log_dir.exists() {
            std::fs::create_dir(log_dir).expect("Failed to create test log dir");
        }
        let task_log_dir = tempdir.path().join("task_log");
        if !task_log_dir.exists() {
            std::fs::create_dir(task_log_dir).expect("Failed to create test task log dir");
        }

        let state = State::new(&settings, None);
        (Arc::new(Mutex::new(state)), tempdir)
    }

    /// Create a new task with stub data
    pub fn get_stub_task(id: &str, status: TaskStatus) -> Task {
        Task::new(
            format!("{}", id),
            "/tmp".to_string(),
            HashMap::new(),
            PUEUE_DEFAULT_GROUP.to_string(),
            status,
            Vec::new(),
            None,
        )
    }

    pub fn get_stub_state() -> (SharedState, TempDir) {
        let (state, tempdir) = get_state();
        {
            // Queued task
            let mut state = state.lock().unwrap();
            let task = get_stub_task("0", TaskStatus::Queued);
            state.add_task(task);

            // Finished task
            let task = get_stub_task("1", TaskStatus::Done(TaskResult::Success));
            state.add_task(task);

            // Stashed task
            let task = get_stub_task("2", TaskStatus::Stashed { enqueue_at: None });
            state.add_task(task);

            // Running task
            let task = get_stub_task("3", TaskStatus::Running);
            state.add_task(task);

            // Paused task
            let task = get_stub_task("4", TaskStatus::Paused);
            state.add_task(task);
        }

        (state, tempdir)
    }
}
<|endoftext|>