#!/usr/bin/env python3 """ Circular Buffer - Step-by-Step Tutorial ======================================== Follow the examples or type your own commands! """ from circular_buffer import cb_init, cb_write, cb_copy_span, cb_w_abs, cb_overflows, cb_fill_bytes, cb_fill_pct, Status def show_buffer(buf, label="Buffer"): """Simple buffer visualization.""" w_abs = cb_w_abs(buf) w_overflow = cb_overflows(buf) fill_pct = cb_fill_pct(buf) fill = cb_fill_bytes(buf) pos = w_abs % buf.capacity print(f"\n {label}:") print(" ", end="") for i in range(buf.capacity): b = buf.buffer[i] if b == 0: print("[ ]", end="") else: c = chr(b) if 32 <= b < 127 else f"{b:02X}" print(f"[{c}]", end="") print(f" ← capacity={buf.capacity}") print(" ", end="") for i in range(buf.capacity): print(" ↑ " if i == pos else " ", end="") print(f" ← write position={pos}") print(f" Fill: {fill}/{buf.capacity} bytes | Total written: {w_abs} | Percent Full: {fill_pct}\n") print(f" Overflow Count : {w_overflow} \n") def tutorial_mode(): """Guided tutorial.""" print("\n" + "="*70) print(" TUTORIAL MODE - Follow Along!") print("="*70 + "\n") # Create small buffer capacity = 8 print(f"Step 1: Create buffer with capacity={capacity}") status, buf = cb_init(capacity) print(f" → Created!") show_buffer(buf, "Empty Buffer") input("Press ENTER to continue...") # Write ABC print("\nStep 2: Write 'ABC'") data = b"ABC" print(f" → cb_write(buffer, {data})") st, written = cb_write(buf, data) print(f" → Wrote {written} bytes") show_buffer(buf, "After Writing 'ABC'") input("Press ENTER to continue...") # Write more print("\nStep 3: Write 'DEFG'") data = b"DEFG" print(f" → cb_write(buffer, {data})") st, written = cb_write(buf, data) print(f" → Wrote {written} bytes") show_buffer(buf, "After Writing 'DEFG'") print(" Notice: Buffer is full! (7/8 bytes)") input("Press ENTER to continue...") # Read data print("\nStep 4: Read all data") w_abs = cb_w_abs(buf) print(f" → cb_copy_span(buffer, 0, {w_abs})") st, data = cb_copy_span(buf, 0, w_abs) print(f" → Read: {data}") print(f" → Decoded: '{data.decode()}'") show_buffer(buf, "Buffer Still Has Data") print(" Note: Reading doesn't remove data!") input("Press ENTER to continue...") # Overflow print("\nStep 5: Write more data than capacity (OVERFLOW!)") data = b"HIJKL" print(f" → cb_write(buffer, {data}) - that's 5 more bytes!") print(f" → Buffer is full, so oldest data will be overwritten...") st, written = cb_write(buf, data) print(f" → Wrote {written} bytes") show_buffer(buf, "After Overflow") print(" Notice: 'ABC' got overwritten! Oldest data lost!") print(" Buffer now has: 'DEFGHIJK' (last 8 bytes)") input("Press ENTER to continue...") # Read after overflow print("\nStep 6: Read data after overflow") w_abs = cb_w_abs(buf) start = w_abs - capacity # Only keep what fits print(f" → cb_copy_span(buffer, {start}, {w_abs})") st, data = cb_copy_span(buf, start, w_abs) print(f" → Read: {data}") print(f" → Decoded: '{data.decode()}'") print("\n ✅ This is how circular buffer works!") print(" • Fixed size (no growing)") print(" • Drop oldest when full") print(" • Keep most recent data") def playground_mode(): """Free-form playground.""" print("\n" + "="*70) print(" PLAYGROUND MODE - Type Your Own Commands!") print("="*70 + "\n") print("Commands:") print(" w - Write text (e.g., 'w HELLO')") print(" r - Read all data") print(" r - Read last n bytes") print(" s - Show status") print(" c - Clear (reset) buffer") print(" q - Quit") print() # Create buffer capacity = 12 status, buf = cb_init(capacity) print(f"Created buffer: capacity={capacity}") show_buffer(buf, "Initial State") while True: try: cmd = input("cmd> ").strip() if not cmd: continue parts = cmd.split(maxsplit=1) action = parts[0].lower() if action == 'q': print("Goodbye!\n") break elif action == 'w': if len(parts) < 2: print("Usage: w ") continue text = parts[1] data = text.encode('ascii') print(f"\nWriting: {data} ('{text}')") st, written = cb_write(buf, data) print(f"Wrote: {written} bytes") show_buffer(buf) elif action == 'r': w_abs = cb_w_abs(buf) if w_abs == 0: print("\nBuffer is empty!") continue if len(parts) > 1: try: n = int(parts[1]) start = max(0, w_abs - n) except: print("Invalid number") continue else: start = max(0, w_abs - capacity) st, data = cb_copy_span(buf, start, w_abs) print(f"\nRead: {data}") print(f"Text: '{data.decode('ascii', errors='replace')}'") elif action == 's': show_buffer(buf, "Current State") elif action == 'c': buf.buffer[:] = b'\x00' * capacity buf.write_absolute = 0 buf.overflows = 0 print("\nBuffer cleared!") show_buffer(buf) else: print(f"Unknown command: {action}") except KeyboardInterrupt: print("\n\nGoodbye!\n") break except EOFError: print("\n\nGoodbye!\n") break except Exception as e: print(f"Error: {e}") def quick_test(): """Quick automated test you can watch.""" print("\n" + "="*70) print(" QUICK TEST - Watch What Happens!") print("="*70 + "\n") import time status, buf = cb_init(10) print("Created buffer: capacity=10") show_buffer(buf) time.sleep(1) print("Writing: ABC") cb_write(buf, b"ABC") show_buffer(buf) time.sleep(1) print("Writing: DEFGH") cb_write(buf, b"DEFGH") show_buffer(buf) time.sleep(1) print("Writing: IJKLM (OVERFLOW!)") cb_write(buf, b"IJKLM") show_buffer(buf) print("Notice: Oldest data (ABC) was overwritten!") time.sleep(1) w_abs = cb_w_abs(buf) st, data = cb_copy_span(buf, w_abs - 10, w_abs) print(f"\nFinal data: {data.decode()}") print("That's the last 10 bytes written!\n") def main(): """Main menu.""" print("\n" + "="*70) print(" CIRCULAR BUFFER - LEARNING PLAYGROUND") print("="*70) print("\nChoose a mode:") print(" 1. Tutorial (step-by-step guided)") print(" 2. Playground (type your own commands)") print(" 3. Quick Test (watch automated demo)") print(" q. Quit") print() choice = input("Select [1/2/3/q]: ").strip() if choice == '1': tutorial_mode() elif choice == '2': playground_mode() elif choice == '3': quick_test() elif choice.lower() == 'q': print("\nGoodbye!\n") else: print("\nInvalid choice. Goodbye!\n") if __name__ == "__main__": main()