package org.jruby;
import org.jcodings.specific.USASCIIEncoding;
import org.jruby.anno.JRubyClass;
import org.jruby.anno.JRubyMethod;
import org.jruby.compiler.Constantizable;
import org.jruby.runtime.ClassIndex;
import org.jruby.runtime.ObjectAllocator;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.runtime.marshal.MarshalStream;
import org.jruby.runtime.opto.OptoFactory;
import org.jruby.util.ByteList;
@JRubyClass(name={"TrueClass", "FalseClass"})
public class RubyBoolean extends RubyObject implements Constantizable {
private final int hashCode;
private final Object constant;
RubyBoolean(Ruby runtime, boolean value) {
super(runtime,
(value ? runtime.getTrueClass() : runtime.getFalseClass()),
false);
if (!value) flags = FALSE_F;
if (RubyInstanceConfig.CONSISTENT_HASHING_ENABLED) {
this.hashCode = value ? 155 : -48;
} else {
this.hashCode = System.identityHashCode(this);
}
constant = OptoFactory.newConstantWrapper(IRubyObject.class, this);
}
@Override
public ClassIndex getNativeClassIndex() {
return (flags & FALSE_F) == 0 ? ClassIndex.TRUE : ClassIndex.FALSE;
}
@Override
public boolean isImmediate() {
return true;
}
@Override
public RubyClass getSingletonClass() {
return metaClass;
}
@Override
public Class<?> getJavaClass() {
return boolean.class;
}
@Override
public Object constant() {
return constant;
}
public static RubyClass createFalseClass(Ruby runtime) {
RubyClass falseClass = runtime.defineClass("FalseClass", runtime.getObject(), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
runtime.setFalseClass(falseClass);
falseClass.setClassIndex(ClassIndex.FALSE);
falseClass.setReifiedClass(RubyBoolean.class);
falseClass.defineAnnotatedMethods(False.class);
falseClass.defineAnnotatedMethods(RubyBoolean.class);
falseClass.getMetaClass().undefineMethod("new");
return falseClass;
}
public static RubyClass createTrueClass(Ruby runtime) {
RubyClass trueClass = runtime.defineClass("TrueClass", runtime.getObject(), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
runtime.setTrueClass(trueClass);
trueClass.setClassIndex(ClassIndex.TRUE);
trueClass.setReifiedClass(RubyBoolean.class);
trueClass.defineAnnotatedMethods(True.class);
trueClass.defineAnnotatedMethods(RubyBoolean.class);
trueClass.getMetaClass().undefineMethod("new");
return trueClass;
}
public static RubyBoolean newBoolean(Ruby runtime, boolean value) {
return value ? runtime.getTrue() : runtime.getFalse();
}
static final ByteList FALSE_BYTES = new ByteList(new byte[] { 'f','a','l','s','e' }, USASCIIEncoding.INSTANCE);
public static class False extends RubyBoolean {
False(Ruby runtime) {
super(runtime, false);
flags = FALSE_F | FROZEN_F;
}
@JRubyMethod(name = "&")
public static IRubyObject false_and(IRubyObject fals, IRubyObject oth) {
return fals;
}
@JRubyMethod(name = "|")
public static IRubyObject false_or(ThreadContext context, IRubyObject fals, IRubyObject oth) {
return oth.isTrue() ? context.tru : fals;
}
@JRubyMethod(name = "^")
public static IRubyObject false_xor(ThreadContext context, IRubyObject fals, IRubyObject oth) {
return oth.isTrue() ? context.tru : fals;
}
@JRubyMethod(name = "to_s", alias = "inspect")
public static RubyString false_to_s(IRubyObject fals) {
return RubyString.newStringShared(fals.getRuntime(), FALSE_BYTES);
}
@Override
public <T> T toJava(Class<T> target) {
if (target.isAssignableFrom(Boolean.class) || target == boolean.class) {
return (T) Boolean.FALSE;
}
return super.toJava(target);
}
}
static final ByteList TRUE_BYTES = new ByteList(new byte[] { 't','r','u','e' }, USASCIIEncoding.INSTANCE);
public static class True extends RubyBoolean {
True(Ruby runtime) {
super(runtime, true);
flags |= FROZEN_F;
}
@JRubyMethod(name = "&")
public static IRubyObject true_and(ThreadContext context, IRubyObject tru, IRubyObject oth) {
return oth.isTrue() ? tru : context.fals;
}
@JRubyMethod(name = "|")
public static IRubyObject true_or(IRubyObject tru, IRubyObject oth) {
return tru;
}
@JRubyMethod(name = "^")
public static IRubyObject true_xor(ThreadContext context, IRubyObject tru, IRubyObject oth) {
return oth.isTrue() ? context.fals : tru;
}
@JRubyMethod(name = "to_s", alias = "inspect")
public static RubyString true_to_s(IRubyObject tru) {
return RubyString.newStringShared(tru.getRuntime(), TRUE_BYTES);
}
@Override
public <T> T toJava(Class<T> target) {
if (target.isAssignableFrom(Boolean.class) || target == boolean.class) {
return (T) Boolean.TRUE;
}
return super.toJava(target);
}
}
@JRubyMethod(name = "hash")
public RubyFixnum hash(ThreadContext context) {
return context.runtime.newFixnum(hashCode());
}
@Override
public int hashCode() {
return hashCode;
}
@Override
public RubyFixnum id() {
if ((flags & FALSE_F) == 0) {
return RubyFixnum.newFixnum(getRuntime(), 20);
} else {
return RubyFixnum.zero(getRuntime());
}
}
@Override
public IRubyObject taint(ThreadContext context) {
return this;
}
public void marshalTo(MarshalStream output) throws java.io.IOException {
output.write(isTrue() ? 'T' : 'F');
}
}