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
49KB
1K SLoC
SimRs
这是我在我的研究项目中使用的实验性离散事件模拟库。目前我不确定它对其他人有多大的价值,但我发现这里的一些东西很有趣,也许其他人也会感兴趣。
访问https://docs.rs/simrs/0.1.2/simrs/ 获取更多信息和相关文档。
如果您有任何评论、建议或批评,请随时通过直接联系我或在GitHub上提交问题来联系。
lib.rs
:
通用模拟库,提供调度器、状态、队列等机制。
注意:目前这些都是实验性的。
关键公共类型包括 State
、Scheduler
、Components
和 Simulation
。这些,以及用户定义的模拟组件(实现 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());
}));
}