rigless 0.0.6

Virtual hardware-in-the-loop runtime: run unmodified firmware on an emulated MCU with every peripheral, chip model and unit of virtual time in Rust, and a fork of QEMU built in to execute the instructions
Documentation
// Copyright (c) 2026 Rigless Labs.
// SPDX-License-Identifier: MIT OR Apache-2.0
//! The chip end of an inter-integrated-circuit bus.

use std::any::Any;

use crate::device::DeviceContext;

/// An integrated circuit on an I²C bus: what a controller, on a part or inside another chip, addresses.
///
/// A transaction is a start carrying an address and a direction, bytes one way, and a stop. A
/// restart is another start without the stop. The controller calls this and never learns what's
/// behind it. A chip implements it and never learns there's a controller. A chip that isn't at the
/// address doesn't acknowledge the start, and the controller reads nothing from it.
///
/// `Any` so a controller with several peers on one bus can hand a board back the concrete chip it
/// hung there, the way [`crate::chip::spi::Peer`] and [`crate::chip::uart::Peer`] already do.
pub trait Peer: std::fmt::Debug + Send + Any {
    /// A start condition carrying `address` and whether the controller will read. Returns the
    /// acknowledge.
    fn start(&mut self, address: u8, read: bool, context: &DeviceContext<'_>) -> bool;

    /// One byte from the controller, after a start it acknowledged for a write. Returns the
    /// acknowledge.
    fn write(&mut self, byte: u8, context: &DeviceContext<'_>) -> bool;

    /// One byte to the controller, after a start it acknowledged for a read. `last` is the
    /// controller's not-acknowledge, which says the stop is next.
    fn read(&mut self, last: bool, context: &DeviceContext<'_>) -> u8;

    /// The stop condition.
    fn stop(&mut self, context: &DeviceContext<'_>);

    /// Every byte this peer has been written, oldest first, or nothing where it keeps no log.
    ///
    /// The far end's own record, the same job [`crate::chip::spi::Peer::received`] and
    /// [`crate::chip::uart::Peer::received`] do for their own buses: it is what says a byte reached
    /// the far end, rather than the controller's own belief that it sent one.
    fn received(&self) -> &[u8] {
        &[]
    }
}