1 /***** BEGIN LICENSE BLOCK****
2 * Version: CPL 1.0/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Common Public
5 * License Version 1.0 (the "License"); you may not use this file
6 * except in compliance with the License. You may obtain a copy of
7 * the License at http://www.eclipse.org/legal/cpl-v10.html
9 * Software distributed under the License is distributed on an "AS
10 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11 * implied. See the License for the specific language governing
12 * rights and limitations under the License.
14 * Copyright (C) 2007 MenTaLguY <mental@rydia.net>
16 * Alternatively, the contents of this file may be used under the terms of
17 * either of the GNU General Public License Version 2 or later (the "GPL"),
18 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
19 * in which case the provisions of the GPL or the LGPL are applicable instead
20 * of those above. If you wish to allow use of your version of this file only
21 * under the terms of either the GPL or the LGPL, and not to allow others to
22 * use your version of this file under the terms of the CPL, indicate your
23 * decision by deleting the provisions above and replace them with the notice
24 * and other provisions required by the GPL or the LGPL. If you do not delete
25 * the provisions above, a recipient may use your version of this file under
26 * the terms of any one of the CPL, the GPL or the LGPL.
27 ***** END LICENSE BLOCK *****/
31 import java
.io
.IOException
;
32 import java
.util
.Iterator
;
35 import org
.jruby
.IRuby
;
36 import org
.jruby
.RubyArray
;
37 import org
.jruby
.RubyClass
;
38 import org
.jruby
.RubyException
;
39 import org
.jruby
.RubyFixnum
;
40 import org
.jruby
.RubyFloat
;
41 import org
.jruby
.RubyInteger
;
42 import org
.jruby
.RubyModule
;
43 import org
.jruby
.RubyString
;
44 import org
.jruby
.ast
.Node
;
45 import org
.jruby
.exceptions
.RaiseException
;
46 import org
.jruby
.runtime
.Block
;
47 import org
.jruby
.runtime
.CallbackFactory
;
48 import org
.jruby
.runtime
.callback
.Callback
;
49 import org
.jruby
.runtime
.CallType
;
50 import org
.jruby
.runtime
.ObjectAllocator
;
51 import org
.jruby
.runtime
.ThreadContext
;
52 import org
.jruby
.runtime
.load
.BasicLibraryService
;
53 import org
.jruby
.runtime
.builtin
.IRubyObject
;
55 public class FuturesService
implements BasicLibraryService
{
56 public boolean basicLoad(final IRuby runtime
) throws IOException
{
61 public static class Thunk
implements IRubyObject
{
62 private IRuby runtime
;
63 private RubyClass klass
;
64 private IRubyObject source
;
65 private IRubyObject value
;
67 Thunk(IRuby runtime
, RubyClass klass
, IRubyObject source
) {
68 this.runtime
= runtime
;
74 public static IRubyObject
newInstance(IRubyObject recv
, IRubyObject source
) {
75 return new Thunk(recv
.getRuntime(), (RubyClass
)recv
, source
);
78 public static void setup(final IRuby runtime
) throws IOException
{
79 RubyClass cThunk
= runtime
.getOrCreateModule("Concurrent").defineModuleUnder("Futures").defineClassUnder("Thunk", null, ObjectAllocator
.NOT_ALLOCATABLE_ALLOCATOR
);
80 CallbackFactory cb
= runtime
.callbackFactory(Thunk
.class);
81 cThunk
.getMetaClass().defineMethod("new", cb
.getSingletonMethod("newInstance", IRubyObject
.class));
82 cThunk
.defineMethod("value", cb
.getSingletonMethod("value", IRubyObject
.class));
85 public static IRubyObject
thunkValue(IRubyObject obj
, boolean evaluate
) {
86 IRubyObject original
=obj
;
88 while (obj
instanceof Thunk
) {
89 Thunk thunk
=(Thunk
)obj
;
91 synchronized (thunk
) {
92 if ( thunk
.source
!= null ) {
94 thunk
.value
= thunk
.source
.callMethod(thunk
.source
.getRuntime().getCurrentContext(), "value");
98 if ( obj
!= original
) {
99 Thunk original_thunk
= (Thunk
)original
;
100 synchronized (original_thunk
) {
101 original_thunk
.value
= thunk
.value
;
117 public static IRubyObject
evalThunk(IRubyObject obj
) {
119 return thunkValue(obj
, true);
120 } catch (RaiseException e
) {
121 RubyClass cAsyncError
= obj
.getRuntime().getModule("Concurrent").defineModuleUnder("Futures").getClass("AsyncError");
122 RubyException e2
= (RubyException
)cAsyncError
.callMethod(obj
.getRuntime().getCurrentContext(), "new", e
.getException());
123 throw new RaiseException(e2
);
127 public static IRubyObject
value(IRubyObject recv
, IRubyObject obj
) {
128 return thunkValue(obj
, true);
131 public int getNativeTypeIndex() {
132 return evalThunk(this).getNativeTypeIndex();
135 public Map
safeGetInstanceVariables() {
136 return evalThunk(this).safeGetInstanceVariables();
139 public boolean safeHasInstanceVariables() {
140 return evalThunk(this).safeHasInstanceVariables();
143 public IRubyObject
getInstanceVariable(String name
) {
144 return evalThunk(this).getInstanceVariable(name
);
147 public IRubyObject
setInstanceVariable(String name
, IRubyObject value
) {
148 return evalThunk(this).setInstanceVariable(name
, value
);
151 public Map
getInstanceVariables() {
152 return evalThunk(this).getInstanceVariables();
155 public Map
getInstanceVariablesSnapshot() {
156 return evalThunk(this).getInstanceVariablesSnapshot();
159 public IRubyObject
callMethod(ThreadContext context
, RubyModule rubyclass
, String name
, IRubyObject
[] args
, CallType callType
, Block block
) {
160 return evalThunk(this).callMethod(context
, rubyclass
, name
, args
, callType
, block
);
163 public IRubyObject
callMethod(ThreadContext context
, RubyModule rubyclass
, byte switchValue
, String name
, IRubyObject
[] args
, CallType callType
) {
164 return evalThunk(this).callMethod(context
, rubyclass
, switchValue
, name
, args
, callType
);
167 public IRubyObject
callMethod(ThreadContext context
, byte switchValue
, String name
, IRubyObject
[] args
, CallType callType
, Block block
) {
168 return evalThunk(this).callMethod(context
, switchValue
, name
, args
, callType
, block
);
171 public IRubyObject
callMethod(ThreadContext context
, String name
, IRubyObject
[] args
, CallType callType
) {
172 return evalThunk(this).callMethod(context
, name
, args
, callType
);
175 public IRubyObject
callMethod(ThreadContext context
, String name
, IRubyObject
[] args
, CallType callType
, Block block
) {
176 return evalThunk(this).callMethod(context
, name
, args
, callType
, block
);
179 public IRubyObject
callMethod(ThreadContext context
, String name
) {
180 return evalThunk(this).callMethod(context
, name
);
183 public IRubyObject
callMethod(ThreadContext context
, String name
, Block block
) {
184 return evalThunk(this).callMethod(context
, name
, block
);
187 public IRubyObject
callMethod(ThreadContext context
, String name
, IRubyObject arg
) {
188 return evalThunk(this).callMethod(context
, name
, arg
);
191 public IRubyObject
callMethod(ThreadContext context
, String name
, IRubyObject
[] args
) {
192 return evalThunk(this).callMethod(context
, name
, args
);
195 public IRubyObject
callMethod(ThreadContext context
, String name
, IRubyObject
[] args
, Block block
) {
196 return evalThunk(this).callMethod(context
, name
, args
, block
);
199 public boolean isNil() {
200 return evalThunk(this).isNil();
203 public boolean isTrue() {
204 return evalThunk(this).isTrue();
207 public boolean isTaint() {
208 return evalThunk(this).isTaint();
211 public boolean isFrozen() {
212 return evalThunk(this).isFrozen();
215 public boolean isImmediate() {
216 return evalThunk(this).isImmediate();
219 public RubyClass
getMetaClass() {
220 return evalThunk(this).getMetaClass();
223 public void setMetaClass(RubyClass metaClass
) {
224 evalThunk(this).setMetaClass(metaClass
);
227 public RubyClass
getSingletonClass() {
228 return evalThunk(this).getSingletonClass();
231 public RubyClass
getType() {
232 return evalThunk(this).getType();
235 public boolean isKindOf(RubyModule rubyClass
) {
236 return evalThunk(this).isKindOf(rubyClass
);
239 public boolean respondsTo(String method
) {
240 return evalThunk(this).respondsTo(method
);
243 public IRuby
getRuntime() {
247 public Class
getJavaClass() {
248 return evalThunk(this).getJavaClass();
251 public IRubyObject
eval(Node iNode
) {
252 return evalThunk(this).eval(iNode
);
255 public IRubyObject
evalWithBinding(ThreadContext context
, IRubyObject evalString
, IRubyObject binding
, String file
) {
256 return evalThunk(this).evalWithBinding(context
, evalString
, binding
, file
);
259 public IRubyObject
evalSimple(ThreadContext context
, IRubyObject evalString
, String file
) {
260 return evalThunk(this).evalSimple(context
, evalString
, file
);
263 public void extendObject(RubyModule rubyModule
) {
264 evalThunk(this).extendObject(rubyModule
);
267 public String
asSymbol() {
268 return evalThunk(this).asSymbol();
271 public RubyArray
convertToArray() {
272 return evalThunk(this).convertToArray();
274 public RubyFloat
convertToFloat() {
275 return evalThunk(this).convertToFloat();
277 public RubyInteger
convertToInteger() {
278 return evalThunk(this).convertToInteger();
280 public RubyString
convertToString() {
281 return evalThunk(this).convertToString();
284 public IRubyObject
convertToType(String targetType
, String convertMethod
, boolean raiseOnError
) {
285 return evalThunk(this).convertToType(targetType
, convertMethod
, raiseOnError
);
288 public IRubyObject
convertToTypeWithCheck(String targetType
, String convertMethod
) {
289 return evalThunk(this).convertToTypeWithCheck(targetType
, convertMethod
);
292 public void setTaint(boolean b
) {
293 evalThunk(this).setTaint(b
);
296 public void checkSafeString() {
297 evalThunk(this).checkSafeString();
300 public IRubyObject
convertType(Class type
, String string
, String string1
) {
301 return evalThunk(this).convertType(type
, string
, string1
);
304 public IRubyObject
dup() {
305 return evalThunk(this).dup();
308 public void initCopy(IRubyObject original
) {
309 evalThunk(this).initCopy(original
);
312 public void setFrozen(boolean b
) {
313 evalThunk(this).setFrozen(b
);
316 public IRubyObject
inspect() {
317 return evalThunk(this).inspect();
320 public int checkArgumentCount(IRubyObject
[] arguments
, int minimum
, int maximum
) {
321 return evalThunk(this).checkArgumentCount(arguments
, minimum
, maximum
);
324 public IRubyObject
rbClone() {
325 return evalThunk(this).rbClone();
328 public void callInit(IRubyObject
[] args
, Block block
) {
329 evalThunk(this).callInit(args
, block
);
332 public void defineSingletonMethod(String name
, Callback callback
) {
333 evalThunk(this).defineSingletonMethod(name
, callback
);
336 public boolean singletonMethodsAllowed() {
337 return evalThunk(this).singletonMethodsAllowed();
340 public boolean isSingleton() {
341 return evalThunk(this).isSingleton();
344 public Iterator
instanceVariableNames() {
345 return evalThunk(this).instanceVariableNames();
348 public IRubyObject
[] scanArgs(IRubyObject
[] args
, int required
, int optional
) {
349 return evalThunk(this).scanArgs(args
, required
, optional
);
352 public void dataWrapStruct(Object obj
) {
353 evalThunk(this).dataWrapStruct(obj
);
356 public Object
dataGetStruct() {
357 return evalThunk(this).dataGetStruct();
360 public RubyFixnum
id() {
361 return evalThunk(this).id();
364 public IRubyObject
anyToString() {
365 return evalThunk(this).anyToString();
368 public IRubyObject
checkStringType() {
369 return evalThunk(this).checkStringType();