mirror of
https://github.com/gsi-upm/soil
synced 2025-07-03 03:32:22 +00:00
Treating time and conditions as the same entity was getting confusing, and it added a lot of unnecessary abstraction in a critical part (the scheduler). The scheduling queue now has the time as a floating number (faster), the agent id (for ties) and the condition, as well as the agent. The first three elements (time, id, condition) can be considered as the "key" for the event. To allow for agent execution to be "randomized" within every step, a new parameter has been added to the scheduler, which makes it add a random number to the key in order to change the ordering. `EventedAgent.received` now checks the messages before returning control to the user by default.
54 lines
1.1 KiB
Python
54 lines
1.1 KiB
Python
from .time import BaseCond
|
|
from dataclasses import dataclass, field
|
|
from typing import Any
|
|
from uuid import uuid4
|
|
|
|
class Event:
|
|
pass
|
|
|
|
@dataclass
|
|
class Message:
|
|
payload: Any
|
|
sender: Any = None
|
|
expiration: float = None
|
|
timestamp: float = None
|
|
id: int = field(default_factory=uuid4)
|
|
|
|
def expired(self, when):
|
|
return self.expiration is not None and self.expiration < when
|
|
|
|
class Reply(Message):
|
|
source: Message
|
|
|
|
|
|
class ReplyCond(BaseCond):
|
|
def __init__(self, ask, *args, **kwargs):
|
|
self._ask = ask
|
|
super().__init__(*args, **kwargs)
|
|
|
|
def ready(self, agent, time):
|
|
return self._ask.reply is not None or self._ask.expired(time)
|
|
|
|
def return_value(self, agent):
|
|
if self._ask.expired(agent.now):
|
|
raise TimedOut()
|
|
return self._ask.reply
|
|
|
|
def __repr__(self):
|
|
return f"ReplyCond({self._ask.id})"
|
|
|
|
|
|
class Ask(Message):
|
|
reply: Message = None
|
|
|
|
def replied(self, expiration=None):
|
|
return ReplyCond(self)
|
|
|
|
|
|
class Tell(Message):
|
|
pass
|
|
|
|
|
|
class TimedOut(Exception):
|
|
pass
|