commit f70988020bb420458232def99ed1291b396a6dd6 Author: gmega Date: Fri Aug 11 18:50:45 2023 -0300 add basic event-driven engine and scaffolding diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c74c5e0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +* +!*/ +!*.* +nimbledeps +nimble.develop +nimble.paths \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..966d4c4 --- /dev/null +++ b/LICENSE.md @@ -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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..4fb749e --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +swarmsim +======== + +A simulator for experimenting with swarm protocols. There is not much to see yet. :-) \ No newline at end of file diff --git a/config.nims b/config.nims new file mode 100644 index 0000000..0a0c126 --- /dev/null +++ b/config.nims @@ -0,0 +1 @@ +switch("path", "$projectDir/src") \ No newline at end of file diff --git a/swarmsim.nim b/swarmsim.nim new file mode 100644 index 0000000..560bc73 --- /dev/null +++ b/swarmsim.nim @@ -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 diff --git a/swarmsim.nimble b/swarmsim.nimble new file mode 100644 index 0000000..cbfc26f --- /dev/null +++ b/swarmsim.nimble @@ -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" \ No newline at end of file diff --git a/swarmsim/eventdrivenengine.nim b/swarmsim/eventdrivenengine.nim new file mode 100644 index 0000000..7de51c5 --- /dev/null +++ b/swarmsim/eventdrivenengine.nim @@ -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 \ No newline at end of file diff --git a/swarmsim/schedulable.nim b/swarmsim/schedulable.nim new file mode 100644 index 0000000..8d2da7a --- /dev/null +++ b/swarmsim/schedulable.nim @@ -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 \ No newline at end of file diff --git a/swarmsim/types.nim b/swarmsim/types.nim new file mode 100644 index 0000000..3c5c487 --- /dev/null +++ b/swarmsim/types.nim @@ -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 \ No newline at end of file diff --git a/tests/all_tests.nim b/tests/all_tests.nim new file mode 100644 index 0000000..e5a8080 --- /dev/null +++ b/tests/all_tests.nim @@ -0,0 +1 @@ +import ./swarmsim/eventdrivenengine \ No newline at end of file diff --git a/tests/nim.cfg b/tests/nim.cfg new file mode 100644 index 0000000..0f840a1 --- /dev/null +++ b/tests/nim.cfg @@ -0,0 +1 @@ +--path:".." diff --git a/tests/swarmsim/eventdrivenengine.nim b/tests/swarmsim/eventdrivenengine.nim new file mode 100644 index 0000000..018936b --- /dev/null +++ b/tests/swarmsim/eventdrivenengine.nim @@ -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) + + + +