4个版本

0.2.0 2022年6月21日
0.1.2 2021年3月28日
0.1.1 2020年12月4日
0.1.0 2020年11月9日

模拟类别中排名 147

MIT/Apache

49KB
1K SLoC

SimRs

这是我在我的研究项目中使用的实验性离散事件模拟库。目前我不确定它对其他人有多大的价值,但我发现这里的一些东西很有趣,也许其他人也会感兴趣。

访问https://docs.rs/simrs/0.1.2/simrs/ 获取更多信息和相关文档。

如果您有任何评论、建议或批评,请随时通过直接联系我或在GitHub上提交问题来联系。


lib.rs:

通用模拟库,提供调度器、状态、队列等机制。

注意:目前这些都是实验性的。

关键公共类型包括 StateSchedulerComponentsSimulation。这些,以及用户定义的模拟组件(实现 Component 特性的结构体),是模拟的构建块。让我们首先解释上述内容,然后再看一些示例。

状态

模拟必须能够修改其状态。这个功能完全委托给了 State 结构体。它可以存储、删除和修改任意类型 T: 'static 的值。它还允许我们创建队列,可以在组件之间传输数据。

值存储

State 提供了几个简单的函数来插入、访问、修改和删除值。现有值通过在插入值时生成并返回的特殊类型安全的键来操作。

let mut state = State::default();
let key = state.insert(7);
assert_eq!(state.remove(key), Some(7));

注意以下代码将因类型不匹配而无法编译

let mut state = State::default();
let int_key = state.insert(7);
let str_key = state.insert("str");
let v: i32 = state.get(str_key);

队列

队列的工作方式与存储值非常相似,但用户界面不同。访问也通过键类型完成。然而,为了清晰起见,使用不同的类型 QueueId

let mut state = State::default();
let queue_id = state.add_queue(Fifo::default());
state.send(queue_id, 1);
assert_eq!(state.len(queue_id), 1);
assert_eq!(state.recv(queue_id), Some(1));
assert_eq!(state.recv(queue_id), None);

此外,还提供了一个有界队列,当达到容量时将返回错误。

let mut state = State::default();
let queue_capacity = 1;
let queue_id = state.add_queue(Fifo::bounded(queue_capacity));
assert!(state.send(queue_id, 1).is_ok());
assert_eq!(state.len(queue_id), 1);
assert!(!state.send(queue_id, 2).is_ok());
assert_eq!(state.len(queue_id), 1);

组件

《Components》结构是一个用于存储所有已注册组件的容器。类似于状态中的值和队列,组件通过ComponentId进行标识。

struct SomeComponent {
    // ...
}
#[derive(Debug)]
enum SomeEvent {
    A,
    B,
    C,
}
impl Component for SomeComponent {
    type Event = SomeEvent;
    fn process_event(
        &self,
        self_id: ComponentId<Self::Event>,
        event: &Self::Event,
        scheduler: &mut Scheduler,
        state: &mut State,
    ) {
        // Do some work...
    }
}

let mut components = Components::default();
let component_id = components.add_component(SomeComponent::new());

调度器

调度器的主要功能是跟踪仿真时间和未来事件。事件被安排在特定组件上,并在指定的时间间隔内运行。由于事件是无类型擦除的,因此组件需要向下转型事件。为了简化,每个组件都获得了一个自动执行此操作的内部特质的泛型实现。所有这些都被封装在下面示例中的Components容器中。

let mut components = Components::default();
let mut scheduler = Scheduler::default();
let mut state = State::default();
let component_id = components.add_component(SomeComponent::new());
scheduler.schedule(
    Duration::from_secs(1), // schedule 1 second from now
    component_id,
    SomeEvent::A,
);
let event_entry = scheduler.pop().unwrap();
components.process_event_entry(event_entry, &mut scheduler, &mut state);

仿真

Simulation将所有内容聚合在一个结构中,并提供了一些额外的函数。下面是示例。

示例


#[derive(Debug)]
struct Product;

struct Producer {
    outgoing: QueueId<Fifo<Product>>,
    consumer: ComponentId<ConsumerEvent>,
    produced_count: Key<usize>,
}

struct Consumer {
    incoming: QueueId<Fifo<Product>>,
    working_on: Key<Option<Product>>,
}

#[derive(Debug)]
struct ProducerEvent;

#[derive(Debug)]
enum ConsumerEvent {
    Received,
    Finished,
}

impl Producer {
    fn produce(&self) -> Product {
        Product
    }
    fn interval(&self) -> Duration {
        Duration::from_secs(1)
    }
}

impl Consumer {
    fn interval(&self) -> Duration {
        Duration::from_secs(1)
    }
    fn log(&self, product: Product) {
        println!("{:?}", product)
    }
}

impl Component for Producer {
    type Event = ProducerEvent;

    fn process_event(
        &self,
        self_id: ComponentId<ProducerEvent>,
        _event: &ProducerEvent,
        scheduler: &mut Scheduler,
        state: &mut State,
    ) {
        let count = *state.get(self.produced_count).unwrap();
        if count < 10 {
            let _ = state.send(self.outgoing, self.produce());
            scheduler.schedule(self.interval(), self_id, ProducerEvent);
            scheduler.schedule(Duration::default(), self.consumer, ConsumerEvent::Received);
            *state.get_mut(self.produced_count).unwrap() = count + 1;
        }
    }
}

impl Component for Consumer {
    type Event = ConsumerEvent;

    fn process_event(
        &self,
        self_id: ComponentId<ConsumerEvent>,
        event: &ConsumerEvent,
        scheduler: &mut Scheduler,
        state: &mut State,
    ) {
        let busy = state.get(self.working_on).is_some();
        match event {
            ConsumerEvent::Received => {
                if busy {
                    if let Some(product) = state.recv(self.incoming) {
                        state.get_mut(self.working_on).map(|w| *w = Some(product));
                        scheduler.schedule(self.interval(), self_id, ConsumerEvent::Finished);
                    }
                }
            }
            ConsumerEvent::Finished => {
                let product = state.get_mut(self.working_on).unwrap().take().unwrap();
                self.log(product);
                if state.len(self.incoming) > 0 {
                    scheduler.schedule(Duration::default(), self_id, ConsumerEvent::Received);
                }
            }
        }
    }
}

fn main() {
    let mut simulation = Simulation::default();
    let queue = simulation.add_queue(Fifo::default());
    let working_on = simulation.state.insert::<Option<Product>>(None);
    let consumer = simulation.add_component(Consumer {
        incoming: queue,
        working_on,
    });
    let produced_count = simulation.state.insert(0_usize);
    let producer = simulation.add_component(Producer {
        outgoing: queue,
        consumer,
        produced_count,
    });
    simulation.schedule(Duration::new(0, 0), producer, ProducerEvent);
    // simulation.schedule(Duration::new(0, 0), consumer, ProducerEvent);
    // The above would fail with:                         ^^^^^^^^^^^^^ expected enum `ConsumerEvent`, found struct `ProducerEvent`
    simulation.execute(Executor::unbound().side_effect(|sim| {
        println!("{:?}", sim.scheduler.time());
    }));
}

无运行时依赖