//! This example demonstrates how to use a `UsersCache` cache in a
//! multi-threaded situation. The cache uses `RefCell`s internally, so it
//! is distinctly not thread-safe. Instead, you’ll need to place it within
//! some kind of lock in order to have threads access it one-at-a-time.
//!
//! It queries all the users it can find in the range 500..510. This is the
//! default uid range on my Apple laptop -- Linux starts counting from 1000,
//! but I can’t include both in the range! It spawns one thread per user to
//! query, with each thread accessing the same cache.
//!
//! Then, afterwards, it retrieves references to the users that had been
//! cached earlier.

// For extra fun, try uncommenting some of the lines of code below, making
// the code try to access the users cache *without* a Mutex, and see it
// spew compile errors at you.

extern crate uzers;
use uzers::{uid_t, Users, UsersCache};

extern crate env_logger;

use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;

const LO: uid_t = 500;
const HI: uid_t = 510;

fn main() {
    env_logger::init();

    // For thread-safely, our users cache needs to be within a Mutex, so
    // only one thread can access it once. This Mutex needs to be within an
    // Arc, so multiple threads can access the Mutex.
    let cache = Arc::new(Mutex::new(UsersCache::new()));
    // let cache = UsersCache::empty_cache();

    // Loop over the range and query all the users in the range. Although we
    // could use the `&User` values returned, we just ignore them.
    for uid in LO..HI {
        let cache = Arc::clone(&cache);

        thread::spawn(move || {
            let cache = cache.lock().unwrap(); // Unlock the mutex
            let _ = cache.get_user_by_uid(uid); // Query our users cache!
        });
    }

    // Wait for all the threads to finish.
    thread::sleep(Duration::from_millis(100));

    // Loop over the same range and print out all the users we find.
    // These users will be retrieved from the cache.
    for uid in LO..HI {
        let cache = cache.lock().unwrap(); // Re-unlock the mutex
        if let Some(u) = cache.get_user_by_uid(uid) {
            // Re-query our cache!
            println!("User #{} is {}", u.uid(), u.name().to_string_lossy())
        } else {
            println!("User #{} does not exist", uid);
        }
    }
}
