//! ============================================================================ //! LEARNING GUIDE - PART 1: Basic Usage //! ============================================================================ //! //! WHAT YOU'LL LEARN: //! - How to create an announcement channel //! - How to announce a value //! - How to check for values without blocking (try_listen) //! - Basic synchronous usage patterns //! //! PREREQUISITES: //! - None - start here! //! //! KEY CONCEPTS: //! - Announcement channel: One sender (Announcer), many receivers (Listeners) //! - Oneshot semantics: Can only announce ONCE //! - Non-blocking checks: Use try_listen() to check without waiting //! //! Run with: cargo run --example 01_basic_usage use announcement::Announcement; fn main() { println!("=== Basic Announcement Usage ===\n"); // STEP 1: Create an announcement channel // ======================================== // The new() method returns TWO things: // - announcer: Used ONCE to broadcast a value // - announcement: Used to create listeners that receive the value // // IMPORTANT: The announcer is NOT Clone - you can only use it once! // This enforces the "oneshot" semantics at compile time. let (announcer, announcement) = Announcement::::new(); println!("Step 1: Created announcement channel"); println!(" - announcer: Will send the value (used once)"); println!(" - announcement: Creates listeners (can create many)\n"); // STEP 2: Create a listener BEFORE announcing // ============================================ // Listeners can be created at any time - before OR after the value is announced. // Each listener is independent and will receive the same value. // // NOTE: Creating a listener is very cheap (~20ns, just 2 Arc clones). let listener1 = announcement.listener(); println!("Step 2: Created first listener"); println!(" - Listener created BEFORE value is announced\n"); // STEP 3: Try to listen (non-blocking check) // =========================================== // try_listen() checks if a value has been announced WITHOUT waiting. // Returns: // - Some(value) if announced // - None if not yet announced // // IMPORTANT: This is a lock-free operation (~5-10ns), very fast! match listener1.try_listen() { Some(value) => { println!("Step 3: Got value: {}", value); } None => { println!("Step 3: No value yet (as expected)"); println!(" - try_listen() returns None when nothing announced\n"); } } // STEP 4: Check if announced (alternative pattern) // ================================================= // The announcement itself can check if a value was announced. // This is useful in the sending/coordinating code. if !announcement.is_announced() { println!("Step 4: Confirmed - nothing announced yet\n"); } // STEP 5: Announce the value // =========================== // This is the ONESHOT broadcast operation. // - Stores the value in shared memory (Arc) // - Wakes up any waiting listeners (we don't have any waiting yet) // - Can only be called ONCE (enforced by consuming the announcer) // // PERFORMANCE: ~10-40ns, completely non-blocking println!("Step 5: Announcing value 42..."); announcer.announce(42).unwrap(); println!(" - Value 42 broadcasted to all listeners\n"); // NOTE: At this point, the announcer has been consumed. // We can't announce again - the compiler prevents it! // Try uncommenting this line to see the error: // announcer.announce(99).unwrap(); // ERROR: value used after move // STEP 6: Verify announcement happened // ===================================== if announcement.is_announced() { println!("Step 6: Confirmed - value has been announced\n"); } // STEP 7: Retrieve the value // =========================== // Now try_listen() will return Some(value) immediately. // The value is cloned from shared storage. // // IMPORTANT: For expensive-to-clone types, wrap in Arc (see example 04). match listener1.try_listen() { Some(value) => { println!("Step 7: Listener 1 received: {}", value); println!(" - try_listen() now returns Some(42)\n"); } None => { println!("ERROR: This shouldn't happen!"); } } // STEP 8: Create additional listeners AFTER announcing // ===================================================== // Listeners can be created even after the value is announced. // They'll get the value immediately when they check. // // This is a KEY FEATURE - late joiners still get the value! let listener2 = announcement.listener(); let listener3 = announcement.listener(); println!("Step 8: Created TWO more listeners AFTER announcing"); println!(" - These 'late joiners' still get the value\n"); // STEP 9: All listeners receive the same value // ============================================= // Every listener, no matter when created, gets the same value. // This is the "broadcast" part of oneshot broadcast. println!("Step 9: All listeners can retrieve the value:"); println!(" - Listener 1: {:?}", listener1.try_listen()); println!(" - Listener 2: {:?}", listener2.try_listen()); println!(" - Listener 3: {:?}", listener3.try_listen()); println!("\n All received Some(42)!\n"); // STEP 10: Listeners can be called multiple times // ================================================ // Calling try_listen() multiple times on the same listener // returns the value each time (cloning it). // // TIP: This is safe but clones the value each time. // For large types, use Arc to avoid repeated cloning (see example 04). println!("Step 10: Calling try_listen() again:"); println!(" - First call: {:?}", listener1.try_listen()); println!(" - Second call: {:?}", listener1.try_listen()); println!(" - Third call: {:?}", listener1.try_listen()); println!("\n Same value every time!\n"); // SUMMARY // ======= println!("=== Summary ==="); println!("✓ Created announcement channel (announcer + announcement)"); println!("✓ Created listeners before AND after announcing"); println!("✓ Used try_listen() to check non-blocking"); println!("✓ Announced value ONCE (oneshot semantics)"); println!("✓ All listeners received the same value"); println!("\nNEXT: See example 02 for async listening with .await"); // EXPECTED OUTPUT: // ================ // You should see all steps execute in order, showing: // - try_listen() returns None before announcing // - try_listen() returns Some(42) after announcing // - All listeners get the value, even late joiners // - Multiple calls to try_listen() return the same value }