Guest User

Untitled

a guest
Jul 19th, 2018
110
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.00 KB | None | 0 0
  1. Deferred {
  2. var value, error, resolved=\unresolved, waitingThreads;
  3.  
  4. *new {
  5. ^super.new.init
  6. }
  7.  
  8. *using {
  9. |func, clock|
  10. var d = Deferred();
  11. ^d.using(func, clock)
  12. }
  13.  
  14. init {
  15. waitingThreads = Array(2);
  16. }
  17.  
  18. wait {
  19. |timeout|
  20. this.prWait(timeout);
  21.  
  22. if (resolved == \error) {
  23. error.throw;
  24. };
  25.  
  26. ^value
  27. }
  28.  
  29. hasValue {
  30. ^(resolved == \value)
  31. }
  32.  
  33. hasError {
  34. ^(resolved == \error)
  35. }
  36.  
  37. isResolved {
  38. ^(resolved != \unresolved);
  39. }
  40.  
  41. value {
  42. switch(resolved,
  43. \value, { ^value },
  44. \error, { error.throw },
  45. \unresolved, { AccessingDeferredValueError().throw }
  46. );
  47. }
  48.  
  49. value_{
  50. |inValue|
  51. if (resolved == \unresolved) {
  52. resolved = \value;
  53. value = inValue;
  54. this.prResume();
  55. } {
  56. ResettingDeferredValueError(value, error).throw;
  57. }
  58. }
  59.  
  60. error {
  61. // @TODO - do we want to error here if no error was provided?
  62. ^error
  63. }
  64.  
  65. error_{
  66. |inError|
  67. if (resolved == \unresolved) {
  68. resolved = \error;
  69. error = inError;
  70. this.prResume();
  71. } {
  72. ResettingDeferredValueError(value, error).throw;
  73. }
  74. }
  75.  
  76. valueCallback {
  77. ^{
  78. |value|
  79. this.value = value;
  80. }
  81. }
  82.  
  83. errorCallback {
  84. ^{
  85. |error|
  86. this.error = error;
  87. }
  88. }
  89.  
  90. using {
  91. |function, clock|
  92. // We want to catch errors that happen when function is called, but AVOID catching errors
  93. // that may occur during the this.value set operation.
  94. {
  95. var funcResult = \noValue;
  96.  
  97. try {
  98. funcResult = function.value(this);
  99.  
  100. // gotcha: returning an Exception from a function wrapped in a try effectively throws.
  101. nil;
  102. } {
  103. |error|
  104. this.error = error;
  105. };
  106.  
  107. if (funcResult != \noValue) {
  108. this.value = funcResult;
  109. }
  110. }.forkIfNeeded(clock ?? thisThread.clock);
  111. }
  112.  
  113. then {
  114. |valueFunc, errorFunc, clock|
  115. var newDeferred, result, errResult;
  116. // If not specified, just default to returning / rethrowing whatevers passed in
  117. valueFunc = valueFunc ? { |v| v };
  118. errorFunc = errorFunc ? { |v| v.throw; };
  119.  
  120. newDeferred = Deferred();
  121.  
  122. {
  123. this.prWait;
  124.  
  125. if (this.hasValue) {
  126. newDeferred.using({
  127. result = valueFunc.value(this.value);
  128.  
  129. if (result.isKindOf(Deferred)) {
  130. result = result.wait();
  131. };
  132.  
  133. result
  134. })
  135. } {
  136. // SUBTLE: If we throw in value-handling code, it's turned into an error.
  137. // If we throw during ERROR-handling code, we immediately fail and don't
  138. // continue the chain. Otherwise, Error return values are passed along
  139. // as errors, everything else as value.
  140. errResult = errorFunc.value(this.error);
  141.  
  142. newDeferred.using({
  143. if (errResult.isKindOf(Deferred)) {
  144. errResult = errResult.wait();
  145. };
  146.  
  147. if (errResult.isKindOf(Exception)) {
  148. errResult.throw;
  149. };
  150.  
  151. errResult;
  152. });
  153. }
  154. }.fork(clock ?? thisThread.clock);
  155.  
  156. ^newDeferred
  157. }
  158.  
  159. onValue {
  160. |function, clock|
  161. this.then(function, nil, clock);
  162. }
  163.  
  164. onError {
  165. |function, clock|
  166. this.then(nil, function, clock);
  167. }
  168.  
  169. prWait {
  170. |timeout|
  171. if (resolved == \unresolved) {
  172. waitingThreads = waitingThreads.add(thisThread.threadPlayer);
  173.  
  174. if (timeout.notNil) {
  175. thisThread.clock.sched(timeout, {
  176. if (resolved == \unresolved) {
  177. waitingThreads = waitingThreads.remove(thisThread.threadPlayer);
  178. DeferredTimeoutError().timeout_(timeout).throw();
  179. }
  180. })
  181. };
  182.  
  183. \hang.yield;
  184. }
  185. }
  186.  
  187. prResume {
  188. var time = thisThread.seconds;
  189. var tempWaitingThreads = waitingThreads;
  190. waitingThreads = nil;
  191. tempWaitingThreads.do {
  192. |thread|
  193. thread.clock.sched(0, thread);
  194. };
  195. }
  196.  
  197. printOn {
  198. |stream|
  199. stream << "Deferred(%)".format(this.identityHash);
  200. }
  201. }
  202.  
  203. ResettingDeferredValueError : Error {
  204. var value, error;
  205.  
  206. *new {
  207. |value, error|
  208. ^super.newCopyArgs(value, error);
  209. }
  210.  
  211. errorString {
  212. ^"Setting a Deferred value after the value has already been set. (value:%, error:%)".format(value, error)
  213. }
  214. }
  215.  
  216. AccessingDeferredValueError : Error {
  217. errorString {
  218. ^"Accessing Deferred value before the value has been set.";
  219. }
  220. }
  221.  
  222. DeferredTimeoutError : Error {
  223. var <>timeout;
  224.  
  225. *new {
  226. |timeout|
  227. ^super.newCopyArgs(timeout);
  228. }
  229.  
  230. errorString {
  231. ^"Timed out waiting for Deferred after % seconds.".format(timeout)
  232. }
  233. }
  234.  
  235. +Synth {
  236. *doNew {
  237. |...args|
  238. ^Deferred().using({
  239. var obj;
  240. obj = Synth(*args);
  241. obj.server.sync;
  242. obj;
  243. });
  244. }
  245. }
  246.  
  247. +Group {
  248. *doNew {
  249. |...args|
  250. ^Deferred().using({
  251. var obj;
  252. obj = Group(*args);
  253. obj.server.sync;
  254. obj;
  255. })
  256. }
  257. }
  258.  
  259. +SynthDef {
  260. doAdd {
  261. |...args|
  262. ^Deferred().using({
  263. this.add(*args);
  264. Server.default.sync;
  265. this;
  266. })
  267. }
  268. }
  269.  
  270. +Bus {
  271. *doNew {
  272. |...args|
  273. ^Deferred().using({
  274. var obj;
  275. obj = Bus(*args);
  276. obj.server.sync;
  277. obj;
  278. })
  279. }
  280.  
  281. doGet {
  282. var deferred = Deferred();
  283. this.get(deferred.valueCallback);
  284. ^deferred
  285. }
  286. }
  287.  
  288. +Buffer {
  289. *doAlloc {
  290. |...args|
  291. ^Deferred().using({
  292. var obj = Buffer.alloc(*args);
  293. obj.server.sync;
  294. obj;
  295. })
  296. }
  297.  
  298. *doRead {
  299. |...args|
  300. ^Deferred().using({
  301. var obj = Buffer.read(*args);
  302. obj.server.sync;
  303. obj;
  304. })
  305. }
  306. }
  307.  
  308. +Server {
  309. doBoot {
  310. |...args|
  311. var deferred = Deferred();
  312. this.waitForBoot({
  313. deferred.value = this
  314. });
  315. ^deferred
  316. }
  317. }
Add Comment
Please, Sign In to add comment