package org.jruby.ext.ffi;
import java.nio.ByteOrder;
import org.jruby.Ruby;
import org.jruby.RubyClass;
import org.jruby.runtime.Block;
import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
abstract class MemoryOp {
public static final MemoryOp BOOL = new BooleanOp();
public static final MemoryOp INT8 = new Signed8();
public static final MemoryOp UINT8 = new Unsigned8();
public static final MemoryOp INT16 = new Signed16();
public static final MemoryOp UINT16 = new Unsigned16();
public static final MemoryOp INT32 = new Signed32();
public static final MemoryOp UINT32 = new Unsigned32();
public static final MemoryOp INT64 = new Signed64();
public static final MemoryOp UINT64 = new Unsigned64();
public static final MemoryOp FLOAT32 = new Float32();
public static final MemoryOp FLOAT64 = new Float64();
public static final MemoryOp INT16SWAP = new Signed16Swapped();
public static final MemoryOp UINT16SWAP = new Unsigned16Swapped();
public static final MemoryOp INT32SWAP = new Signed32Swapped();
public static final MemoryOp UINT32SWAP = new Unsigned32Swapped();
public static final MemoryOp INT64SWAP = new Signed64Swapped();
public static final MemoryOp UINT64SWAP = new Unsigned64Swapped();
public static final MemoryOp POINTER = new PointerOp();
public static MemoryOp getMemoryOp(NativeType type) {
return getMemoryOp(type, ByteOrder.nativeOrder());
}
public static MemoryOp getMemoryOp(NativeType type, ByteOrder order) {
switch (type) {
case BOOL:
return BOOL;
case CHAR:
return INT8;
case UCHAR:
return UINT8;
case SHORT:
return order.equals(ByteOrder.nativeOrder()) ? INT16 : INT16SWAP;
case USHORT:
return order.equals(ByteOrder.nativeOrder()) ? UINT16 : UINT16SWAP;
case INT:
return order.equals(ByteOrder.nativeOrder()) ? INT32 : INT32SWAP;
case UINT:
return order.equals(ByteOrder.nativeOrder()) ? UINT32 : UINT32SWAP;
case LONG_LONG:
return order.equals(ByteOrder.nativeOrder()) ? INT64 : INT64SWAP;
case ULONG_LONG:
return order.equals(ByteOrder.nativeOrder()) ? UINT64 : UINT64SWAP;
case FLOAT:
return FLOAT32;
case DOUBLE:
return FLOAT64;
case LONG:
return Platform.getPlatform().longSize() == 32
? getMemoryOp(NativeType.INT, order) : getMemoryOp(NativeType.LONG_LONG, order);
case ULONG:
return Platform.getPlatform().longSize() == 32
? getMemoryOp(NativeType.UINT, order) : getMemoryOp(NativeType.ULONG_LONG, order);
case POINTER:
return POINTER;
default:
return null;
}
}
public static MemoryOp getMemoryOp(Type type) {
return getMemoryOp(type, ByteOrder.nativeOrder());
}
public static MemoryOp getMemoryOp(Type type, ByteOrder order) {
if (type instanceof Type.Builtin) {
return getMemoryOp(type.getNativeType(), order);
} else if (type instanceof StructByValue) {
StructByValue sbv = (StructByValue) type;
return new StructOp(sbv.getStructClass());
} else if (type instanceof MappedType) {
return new Mapped(getMemoryOp(((MappedType) type).getRealType(), order), (MappedType) type);
}
return null;
}
abstract IRubyObject get(ThreadContext context, MemoryIO io, long offset);
abstract void put(ThreadContext context, MemoryIO io, long offset, IRubyObject value);
IRubyObject get(ThreadContext context, AbstractMemory ptr, long offset) {
return get(context, ptr.getMemoryIO(), offset);
}
void put(ThreadContext context, AbstractMemory ptr, long offset, IRubyObject value) {
put(context, ptr.getMemoryIO(), offset, value);
}
static abstract class PrimitiveOp extends MemoryOp {
abstract IRubyObject get(Ruby runtime, MemoryIO io, long offset);
abstract void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value);
IRubyObject get(ThreadContext context, MemoryIO io, long offset) {
return get(context.runtime, io, offset);
}
void put(ThreadContext context, MemoryIO io, long offset, IRubyObject value) {
put(context.runtime, io, offset, value);
}
}
static final class BooleanOp extends PrimitiveOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putByte(offset, (byte) (value.isTrue() ? 1 : 0));
}
public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return runtime.newBoolean(io.getByte(offset) != 0);
}
}
static final class Signed8 extends PrimitiveOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putByte(offset, Util.int8Value(value));
}
public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return Util.newSigned8(runtime, io.getByte(offset));
}
}
static final class Unsigned8 extends PrimitiveOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putByte(offset, (byte) Util.uint8Value(value));
}
public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return Util.newUnsigned8(runtime, io.getByte(offset));
}
}
static final class Signed16 extends PrimitiveOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putShort(offset, Util.int16Value(value));
}
public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return Util.newSigned16(runtime, io.getShort(offset));
}
}
static final class Signed16Swapped extends PrimitiveOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putShort(offset, Short.reverseBytes(Util.int16Value(value)));
}
public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return Util.newSigned16(runtime, Short.reverseBytes(io.getShort(offset)));
}
}
static final class Unsigned16 extends PrimitiveOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putShort(offset, (short) Util.uint16Value(value));
}
public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return Util.newUnsigned16(runtime, io.getShort(offset));
}
}
static final class Unsigned16Swapped extends PrimitiveOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putShort(offset, Short.reverseBytes((short) Util.uint16Value(value)));
}
public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return Util.newUnsigned16(runtime, Short.reverseBytes(io.getShort(offset)));
}
}
static final class Signed32 extends PrimitiveOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putInt(offset, Util.int32Value(value));
}
public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return Util.newSigned32(runtime, io.getInt(offset));
}
}
static final class Signed32Swapped extends PrimitiveOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putInt(offset, Integer.reverseBytes(Util.int32Value(value)));
}
public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return Util.newSigned32(runtime, Integer.reverseBytes(io.getInt(offset)));
}
}
static final class Unsigned32 extends PrimitiveOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putInt(offset, (int) Util.uint32Value(value));
}
public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return Util.newUnsigned32(runtime, io.getInt(offset));
}
}
static final class Unsigned32Swapped extends PrimitiveOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putInt(offset, Integer.reverseBytes((int) Util.uint32Value(value)));
}
public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return Util.newUnsigned32(runtime, Integer.reverseBytes(io.getInt(offset)));
}
}
static final class Signed64 extends PrimitiveOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putLong(offset, Util.int64Value(value));
}
public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return Util.newSigned64(runtime, io.getLong(offset));
}
}
static final class Signed64Swapped extends PrimitiveOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putLong(offset, Long.reverseBytes(Util.int64Value(value)));
}
public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return Util.newSigned64(runtime, Long.reverseBytes(io.getLong(offset)));
}
}
static final class Unsigned64 extends PrimitiveOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putLong(offset, Util.uint64Value(value));
}
public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return Util.newUnsigned64(runtime, io.getLong(offset));
}
}
static final class Unsigned64Swapped extends PrimitiveOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putLong(offset, Long.reverseBytes(Util.uint64Value(value)));
}
public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return Util.newUnsigned64(runtime, Long.reverseBytes(io.getLong(offset)));
}
}
static final class Float32 extends PrimitiveOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putFloat(offset, Util.floatValue(value));
}
public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return runtime.newFloat(io.getFloat(offset));
}
}
static final class Float64 extends PrimitiveOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putDouble(offset, Util.doubleValue(value));
}
public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return runtime.newFloat(io.getDouble(offset));
}
}
static final class PointerOp extends PrimitiveOp {
public final void put(Ruby runtime, MemoryIO io, long offset, IRubyObject value) {
io.putMemoryIO(offset, ((AbstractMemory) value).getMemoryIO());
}
public final IRubyObject get(Ruby runtime, MemoryIO io, long offset) {
return new Pointer(runtime, io.getMemoryIO(offset));
}
}
static final class StructOp extends MemoryOp {
private final RubyClass structClass;
public StructOp(RubyClass structClass) {
this.structClass = structClass;
}
@Override
IRubyObject get(ThreadContext context, MemoryIO io, long offset) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
void put(ThreadContext context, MemoryIO io, long offset, IRubyObject value) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
IRubyObject get(ThreadContext context, AbstractMemory ptr, long offset) {
return structClass.newInstance(context,
new IRubyObject[] { ptr.slice(context.runtime, offset) },
Block.NULL_BLOCK);
}
@Override
void put(ThreadContext context, AbstractMemory ptr, long offset, IRubyObject value) {
if (!(value instanceof Struct)) {
throw context.runtime.newTypeError("expected a struct");
}
Struct s = (Struct) value;
byte[] tmp = new byte[Struct.getStructSize(context.runtime, s)];
s.getMemoryIO().get(0, tmp, 0, tmp.length);
ptr.getMemoryIO().put(offset, tmp, 0, tmp.length);
}
}
static final class Mapped extends MemoryOp {
private final MemoryOp nativeOp;
private final MappedType mappedType;
public Mapped(MemoryOp nativeOp, MappedType mappedType) {
this.nativeOp = nativeOp;
this.mappedType = mappedType;
}
@Override
IRubyObject get(ThreadContext context, AbstractMemory ptr, long offset) {
return mappedType.fromNative(context, nativeOp.get(context, ptr, offset));
}
@Override
void put(ThreadContext context, AbstractMemory ptr, long offset, IRubyObject value) {
nativeOp.put(context, ptr, offset, mappedType.toNative(context, value));
}
@Override
IRubyObject get(ThreadContext context, MemoryIO io, long offset) {
return mappedType.fromNative(context, nativeOp.get(context, io, offset));
}
@Override
void put(ThreadContext context, MemoryIO io, long offset, IRubyObject value) {
nativeOp.put(context, io, offset, mappedType.toNative(context, value));
}
}
}