Module: channels Synopsis: broadcast-calling library Author: Jason Trenouth Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND // CHANNELS // // ---*** ordering of calls to receivers in broadcasts? // ---*** multi-threading for calls to receivers in broadcasts? // ---*** use add-method to dynamically build gf for piggybacking on Dylan dispatching? // /// (internal) define class () constant slot channel-message? = unsupplied(), init-keyword: message?:; constant slot channel-receiver? = unsupplied(), init-keyword: receiver?:; constant slot channel-callback :: false-or() = #f, init-keyword: callback:; end class; /// (channels) define open class () constant slot channel-lock :: = make(); constant slot channel-receivers :: = make(
), init-keyword: receivers:; constant slot channel-mapper :: = do, init-keyword: mapper:; end class; /// (internal) define sealed class () sealed slot receiver-key :: , required-init-keyword: key:; sealed slot receiver-message-type :: = , init-keyword: message-type:; end class; /// PROTOCOLS define open generic broadcast (channel :: , message :: , #rest args); define open generic override-channel (channel :: , #rest args, #key message?, receiver?, callback, mapper) => (new-channel :: ); define open generic tune-in (channel :: , receiver-key :: , #key, #all-keys) => (); define open generic tune-out (channel :: , receiver-key :: ) => (); /// OVERRIDE-CHANNEL (channels) define method override-channel (channel :: , #rest args, #key message? = unsupplied(), receiver? = unsupplied(), callback = unsupplied(), mapper = #f) => (new-channel :: ) let override :: = make(, message?: any-supplied?(message?, channel.channel-message?), receiver?: any-supplied?(receiver?, channel.channel-receiver?), callback: any-supplied?(callback, channel.channel-callback), mapper: mapper | channel.channel-mapper, receivers: channel.channel-receivers); override end method; /// BROADCAST (channels) define method broadcast (channel :: , message :: , #rest args) local method do-receiver (receiver :: ) if (instance?(message, receiver.receiver-message-type)) let callback :: = receiver.channel-callback | channel.channel-callback | curry(error, "Missing channel callback"); let message? :: = any-supplied?(receiver.channel-message?, channel.channel-message?, #t); let receiver? :: = any-supplied?(receiver.channel-receiver?, channel.channel-receiver?, #f); let extra :: = #(); if (receiver?) extra := add!(extra, receiver.receiver-key) end if; if (message?) extra := add!(extra, message) end if; apply(callback, concatenate(extra, args)); end if; end method; let lock = channel.channel-lock; if (owned?(lock)) make(, name: "Re-entrant broadcast", function: method () apply(broadcast, channel, message, args) end) else with-lock (lock) channel.channel-mapper(do-receiver, channel.channel-receivers); end end end method; /// TUNE-IN (channels) define method tune-in (channel :: , receiver-key :: , #rest args, #key callback, #all-keys) => () let receiver :: = if (instance?(receiver-key, ) & callback = #f) apply(make, , key: receiver-key, callback: receiver-key, args); else apply(make, , key: receiver-key, args); end if; let lock = channel.channel-lock; if (owned?(lock)) make(, name: "Re-entrant tune-in", function: method () apply(tune-in, channel, receiver-key, args) end) else with-lock (lock) channel.channel-receivers[receiver-key] := receiver; end end end method; /// TUNE-OUT (channels) define method tune-out (channel :: , receiver-key :: ) => () let lock = channel.channel-lock; if (owned?(lock)) make(, name: "Re-entrant tune-out", function: method () tune-out(channel, receiver-key) end) else with-lock (lock) remove-key!(channel.channel-receivers, receiver-key); end end end method; /// ANY-SUPPLIED? (internal) define method any-supplied? (#rest values) block (return) for (v in values) if (supplied?(v)) return(v); end if; end for; return(#f); end block; end method;