Defines all code for code generation in threadbutler. All names of generated types are inferred from the name they are being registered with. All names of fields and enum kinds are inferred based on the data registered.
Procs
proc asSignalVar(name: ThreadName): NimNode {....raises: [], tags: [], forbids: [].}
-
Generates a global variable containing the signal for name:
var <name>Signal*: ThreadSignalPtr
Source Edit proc asThreadVar(name: ThreadName): NimNode {....raises: [], tags: [], forbids: [].}
-
Generates a global variable containing the thread for name:
var <name>ButlerThread*: Thread[Server[<name>Message]]
Source Edit proc enumName(name: ThreadName): string {....raises: [], tags: [], forbids: [].}
- Infers the name of the enum-type associated with name from name Source Edit
proc firstParamName(node: NimNode): string {....raises: [ValueError], tags: [], forbids: [].}
- Extracts the name of the first parameter of a proc Source Edit
proc genDestroyChannelHubProc(): NimNode {....raises: [], tags: [], forbids: [].}
-
Generates a proc destroy for destroying a ChannelHub.
Closes each channel stored in the hub as part of that. Uses variantName to infer the name Message-object-variant-type. The proc is generated based on the registered threadnames according to this pattern:
proc destroy\*(hub: ChannelHub) = --- Repeat per threadname - start --- hub.getChannel(<variantName>).close() --- Repeat per threadname - end ---
Source Edit proc generateCode(name: ThreadName): NimNode {....raises: [ValueError], tags: [], forbids: [].}
-
Generates all types and procs needed for message-passing for name.
This proc should only be used by macros in this and other integration modules.
Source Edit proc genInitServerProc(name: ThreadName): NimNode {....raises: [ValueError], tags: [], forbids: [].}
-
Generates a proc initServer(hub: ChannelHub, typ: typedesc[<name>Message]): Server[<name>Message].
These procs instantiate a threadServer object which can then be run, which starts the server.
Source Edit proc genMessageRouter(name: ThreadName; routes: seq[NimNode]; types: seq[NimNode]): NimNode {....raises: [ValueError], tags: [], forbids: [].}
-
Generates a proc routeMessage for unpacking the object variant type for name and calling a handler proc with the unpacked value. The variantTypeName is inferred from name, see the proc variantName. The name of the killKind is inferred from name, see the proc killKindName. The name of msgField is inferred from type, see the proc fieldName. The proc is generated based on the registered routes according to this pattern:
proc routeMessage\*(msg: <variantTypeName>, hub: ChannelHub) = case msg.kind: --- Repeat per route - start --- of <enumKind>: <handlerProc>(msg.<msgField>, hub) # if sync handlerProc asyncSpawn <handlerProc>(msg.<msgField>, hub) # if async handlerProc --- Repeat per route - end --- of <killKind>: shutDownServer()
This proc should only be used by macros in this and other integration modules. Source Edit proc genNewChannelHubProc(): NimNode {....raises: [], tags: [], forbids: [].}
-
Generates a proc new for instantiating a ChannelHub with a channel to send messages to each thread.
Uses channelHub: addChannel to instantiate, open and add a channel. Uses variantName to infer the name Message-object-variant-type. The proc is generated based on the registered threadnames according to this pattern:
proc new\*(t: typedesc[ChannelHub], capacity: int = 500): ChannelHub = result = ChannelHub(channels: initTable[pointer, pointer]()) --- Repeat per threadname - start --- result.addChannel(<variantName>) --- Repeat per threadname - end ---
Source Edit proc genSendKillMessageProc(name: ThreadName): NimNode {....raises: [], tags: [], forbids: [].}
-
Generates a proc sendKillMessage.
These procs send a message that triggers the graceful shutdown of a thread. The thread to send the message to is inferred based on the object-variant for messages to that thread. The name of the object-variant is inferred from name via variantName.
Source Edit proc getSections(body: NimNode): Table[Section, NimNode] {....raises: [ValueError], tags: [], forbids: [].}
- Source Edit
proc killKindName(name: ThreadName): string {....raises: [], tags: [], forbids: [].}
- Infers the name of the enum-kind for a message that kills the thread associated with name from name. Source Edit
proc signalName(name: ThreadName): string {....raises: [], tags: [], forbids: [].}
- Infers the name of the thread-signal used to wake up the thread from sleeping Source Edit
proc threadVariableName(name: ThreadName): string {....raises: [], tags: [], forbids: [].}
- Infers the name of the variable containing the Thread that runs the server from name Source Edit
proc variantName(name: ThreadName): string {....raises: [], tags: [], forbids: [].}
- Infers the name of the Message-object-variant-type associated with name from name Source Edit
Macros
macro prepareServers()
-
Generates the remaining code that can only be provided once all threadServers have been defined and are known by threadButler.
The generated procs are:
- A routing proc for every registered thread. See genMessageRouter for specifics.
- A new(ChannelHub) proc to instantiate a ChannelHub
- A destroy proc to destroy a ChannelHub
macro threadServer(name: static string; body: untyped)
-
Defines a threadServer called name and registers it and its contents in body with threadButler.
The body may declare any of these 3 sections:
- properties
- messageTypes
- handlers
procs in the handler sections must have the shape:
proc <procName>(msg: <YourMsgType>, hub: ChannelHub)
Generates all types and procs needed for message-passing for name:
- An enum based representing all different types of messages that can be sent to the thread name.
- An object variant that wraps any message to be sent through a channel to the thread name.
- Generic sendMessage procs for sending messages to name by:
- receiving a message-type
- wrapping it in the object variant from 2)
- sending that to a channel to the thread name.
- Specific sendKillMessage procs for sending a "kill" message to name
- An (internal) initServer proc to create a Server
- A global variable that contains the thread that name runs on
Note, this does not include all generated code. See prepareServers for the remaining code that should be called after all threadServers have been declared.
Source Edit macro toThreadVariable(name: static string): untyped
- Generates the identifier for the global variable containing the thread for name. Source Edit
macro toVariantType(name: static string): untyped
- Generate the typedesc identifier for the message-wrapper-type Source Edit