unit uByteArray;

interface

uses
{$IFDEF LINUX}
  Types,
{$ENDIF}
{$IFDEF MSWINDOWS}
  Windows,
{$ENDIF}
  SysUtils,
  Rubies;

var
  cByteArray: Tvalue;

function ap_cByteArray: Tvalue;
function ap_pByteArray(p: PByteArray): Tvalue;
procedure Init_ByteArray;

implementation

uses uPhi, uConv;

function ap_cByteArray: Tvalue;
begin
  result := cByteArray;
end;

function ap_pByteArray(p: PByteArray): Tvalue;
begin
  result := rb_data_object_alloc(cByteArray, p, nil, nil);
end;

function ByteArray_size(This: Tvalue): Tvalue; cdecl;
begin
  result := ap_Integer(SizeOf(TByteArray));
end;

function ByteArray_aref(This, v: Tvalue): Tvalue; cdecl;
var
  p: PByteArray;
  i: Integer;
begin
  p := ap_data_get_struct(This);
  case RTYPE(v) of
  T_FIXNUM:
    begin
      i := dl_Integer(v);
      if i >= SizeOf(p^) then
        ap_raise(ap_eIndexError, sOut_of_range);
      result := ap_Integer(p[i]);
    end;
  else
    ap_raise(ap_eArgError, sWrong_arg_type);
    result := Qnil; // avoid warning
  end;
end;

function ByteArray_aset(This, v, num: Tvalue): Tvalue; cdecl;
var
  p: PByteArray;
  i: Integer;
  c: Byte;
begin
  p := ap_data_get_struct(This);
  c := Byte(dl_Integer(num));
  case RTYPE(v) of
  T_FIXNUM:
    begin
      i := dl_Integer(v);
      if i >= SizeOf(p^) then
        ap_raise(ap_eIndexError, sOut_of_range);
      p[i] := c;
    end;
  else
    ap_raise(ap_eArgError, sWrong_arg_type);
  end;
  result := num;
end;

procedure Init_ByteArray;
begin
  cByteArray := rb_define_class_under(mPhi, 'ByteArray', ap_cObject);
  rb_define_method(cByteArray, 'size', @ByteArray_size, 0);
  rb_define_method(cByteArray, '[]', @ByteArray_aref, 1);
  rb_define_method(cByteArray, '[]=', @ByteArray_aset, 2);
end;

end.
