add basic event-driven engine and scaffolding

This commit is contained in:
gmega 2023-08-11 18:50:45 -03:00
commit f70988020b
12 changed files with 135 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
*
!*/
!*.*
nimbledeps
nimble.develop
nimble.paths

5
LICENSE.md Normal file
View File

@ -0,0 +1,5 @@
Licensed and distributed under either of
[MIT license](http://opensource.org/licenses/MIT) or
[Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0)
at your option. These files may not be copied, modified, or distributed except
according to those terms.

4
README.md Normal file
View File

@ -0,0 +1,4 @@
swarmsim
========
A simulator for experimenting with swarm protocols. There is not much to see yet. :-)

1
config.nims Normal file
View File

@ -0,0 +1 @@
switch("path", "$projectDir/src")

5
swarmsim.nim Normal file
View File

@ -0,0 +1,5 @@
# This is just an example to get you started. A typical binary package
# uses this file as the main entry point of the application.
import ./swarmsim/schedulable
import ./swarmsim/eventdrivenengine

19
swarmsim.nimble Normal file
View File

@ -0,0 +1,19 @@
# Package
version = "0.1.0"
author = "gmega"
description = "Simple swarm simulator"
license = "MIT"
srcDir = "src"
installExt = @["nim"]
bin = @["swarm_sim"]
# Dependencies
requires "nim >= 2.0.0"
# Tasks
task test, "Run unit tests":
exec "nim c -r tests/all_tests.nim"

View File

@ -0,0 +1,31 @@
import std/options
import pkg/swarmsim/types
import pkg/swarmsim/schedulable
proc current_time*(self: EventDrivenEngine): uint64 {.inline.} = self.current_time
proc schedule*(self: EventDrivenEngine, schedulable: Schedulable): EventDrivenEngine =
self.queue.push(schedulable)
self
proc scheduleAll*[T: Schedulable](self: EventDrivenEngine, schedulables: seq[T]): void =
for schedulable in schedulables:
discard self.schedule(schedulable)
proc nextStep*(self: EventDrivenEngine): Option[Schedulable] =
if len(self.queue) == 0:
return none(Schedulable)
let schedulable = self.queue.pop()
self.current_time = schedulable.time
schedulable.scheduled(engine = self)
some(schedulable)
proc run*(self: EventDrivenEngine): void =
while self.nextStep().isSome:
discard
export EventDrivenEngine
export options

9
swarmsim/schedulable.nim Normal file
View File

@ -0,0 +1,9 @@
import pkg/swarmsim/types
func `<`*(self: Schedulable, other: Schedulable): bool =
return self.time < other.time
method scheduled*(self: Schedulable, engine: EventDrivenEngine): void {.base.} =
quit "unimplemented"
export Schedulable

14
swarmsim/types.nim Normal file
View File

@ -0,0 +1,14 @@
import std/heapqueue
type
Schedulable* = ref object of RootObj
## A `Schedulable` is something that can be scheduled for execution in an
## `EventDrivenEngine`.
time*: uint64
type
EventDrivenEngine* = ref object of RootObj
current_time*: uint64
queue*: HeapQueue[Schedulable]
export heapqueue

1
tests/all_tests.nim Normal file
View File

@ -0,0 +1 @@
import ./swarmsim/eventdrivenengine

1
tests/nim.cfg Normal file
View File

@ -0,0 +1 @@
--path:".."

View File

@ -0,0 +1,39 @@
import unittest
import sequtils
import sugar
import std/algorithm
import pkg/swarmsim/schedulable
import pkg/swarmsim/eventdrivenengine
type
TimedSchedulable = ref object of Schedulable
scheduledAt: uint64
method scheduled(schedulable: TimedSchedulable, engine: EventDrivenEngine) =
schedulable.scheduledAt = engine.current_time
suite "event driven engine tests":
test "should run schedulables at the right time":
let times = @[1, 10, 5].map(time => uint64(time))
let schedulables = times.map(time => TimedSchedulable(time: time))
let engine = EventDrivenEngine()
engine.scheduleAll(schedulables)
for time in times.sorted:
let result = engine.nextStep().get()
check(result.time == time)
check(engine.nextStep().isNone)
for schedulable in schedulables:
check(schedulable.scheduledAt == schedulable.time)