unit dserializer;

//
//  Generic interface for serialization/deserialization of objects and structs.
//

{$MODE FPC}
{$MODESWITCH RESULT}

interface

uses
  dansiview;

type
PSerializer = ^TSerializer;
PDeserializer = ^TDeserializer;

TSerializer = object
private
  FErrCode: PtrInt;
  FErrMsg: PAnsiChar;
protected
  function Error(Code: PtrInt; Msg: PAnsiChar): Boolean;
  procedure ResetError;
public
  constructor Init;
  destructor Done; virtual;
  function Success: Boolean; inline;
  function Failed: Boolean; inline;

// Serialization functions for primitive types
  procedure Attr(Name: PAnsiChar; var Value: Int8; Def: Int8); virtual; overload;
  procedure Attr(Name: PAnsiChar; var Value: UInt8; Def: UInt8); virtual; overload;
  procedure Attr(Name: PAnsiChar; var Value: Int16; Def: Int16); virtual; overload;
  procedure Attr(Name: PAnsiChar; var Value: UInt16; Def: UInt16); virtual; overload;
  procedure Attr(Name: PAnsiChar; var Value: Int32; Def: Int32); virtual; overload;
  procedure Attr(Name: PAnsiChar; var Value: UInt32; Def: UInt32); virtual; overload;
  procedure Attr(Name: PAnsiChar; var Value: Int64; Def: Int64); virtual; overload;
  procedure Attr(Name: PAnsiChar; var Value: UInt64; Def: UInt64); virtual; overload;
  procedure Attr(Name: PAnsiChar; var Value: Boolean; Def: Int32); virtual; overload;
  procedure Attr(Name: PAnsiChar; var Value: Single; Def: Int32); virtual; overload;
  procedure Attr(Name: PAnsiChar; var Value: Double; Def: Int32); virtual; overload;
  procedure Attr(Name: PAnsiChar; S, E: PAnsiChar; Def: Int32); virtual; overload;

// Serializing sub objects
  procedure StartObj(Name: PAnsiChar); virtual;
  procedure FinishObj; virtual;

// Serializing arrays
  procedure StartArr(Name: PAnsiChar); virtual;
  procedure FinishArr; virtual;

  property ErrCode: PtrInt read FErrCode;
  property ErrMsg: PAnsiChar read FErrMsg;
end;

TDeserializer = object
private
  FErrCode: PtrInt;
  FErrMsg: PAnsiChar;
protected
  function Error(Code: PtrInt; Msg: PAnsiChar): Boolean;
  procedure ResetError;
public
  constructor Init;
  destructor Done; virtual;
  function Success: Boolean; inline;
  function Failed: Boolean; inline;

  function Next: Boolean; virtual;
  // Moves to next attribute or element.
  function Name: TAnsiView; virtual;
  // Returns name of current attribute.

  procedure Attr(var Value: Int32; Def: Int32); virtual;

  property ErrCode: PtrInt read FErrCode;
  property ErrMsg: PAnsiChar read FErrMsg;
end;

implementation

function TSerializer.Error(Code: PtrInt; Msg: PAnsiChar): Boolean;
begin
  if FErrCode = 0 then begin
    FErrCode := Code;
    FErrMsg := Msg;
  end;
  Exit(FErrCode = 0);
end;

procedure TSerializer.ResetError;
begin
  FErrCode := 0;
  FErrMsg := '';
end;

constructor TSerializer.Init;
begin
  ResetError;
end;

destructor TSerializer.Done;
begin
end;

function TSerializer.Success: Boolean;
begin
  Exit(FErrCode = 0);
end;

function TSerializer.Failed: Boolean;
begin
  Exit(FErrCode <> 0);
end;

procedure TSerializer.Attr(Name: PAnsiChar; var Value: Int8; Def: Int8);
begin
  Error(1, 'abstract i8');
end;

procedure TSerializer.Attr(Name: PAnsiChar; var Value: UInt8; Def: UInt8);
begin
  Error(1, 'abstract u8');
end;

procedure TSerializer.Attr(Name: PAnsiChar; var Value: Int16; Def: Int16);
begin
  Error(1, 'abstract i16');
end;

procedure TSerializer.Attr(Name: PAnsiChar; var Value: UInt16; Def: UInt16);
begin
  Error(1, 'abstract u16');
end;

procedure TSerializer.Attr(Name: PAnsiChar; var Value: Int32; Def: Int32);
begin
  Error(1, 'abstract i32');
end;

procedure TSerializer.Attr(Name: PAnsiChar; var Value: UInt32; Def: UInt32);
begin
  Error(1, 'abstract u32');
end;

procedure TSerializer.Attr(Name: PAnsiChar; var Value: Int64; Def: Int64);
begin
  Error(1, 'abstract i64');
end;

procedure TSerializer.Attr(Name: PAnsiChar; var Value: UInt64; Def: UInt64);
begin
  Error(1, 'abstract u64');
end;

procedure TSerializer.Attr(Name: PAnsiChar; var Value: Boolean; Def: Int32);
begin
  Error(1, 'abstract bool');
end;

procedure TSerializer.Attr(Name: PAnsiChar; var Value: Single; Def: Int32);
begin
  Error(1, 'abstract float');
end;

procedure TSerializer.Attr(Name: PAnsiChar; var Value: Double; Def: Int32);
begin
  Error(1, 'abstract double');
end;

procedure TSerializer.Attr(Name: PAnsiChar; S, E: PAnsiChar; Def: Int32);
begin
  Error(1, 'abstract str');
end;

procedure TSerializer.StartObj(Name: PAnsiChar);
begin
  Error(1, 'abstract obj');
end;

procedure TSerializer.FinishObj;
begin
  Error(1, 'abstract finobj');
end;

procedure TSerializer.StartArr(Name: PAnsiChar);
begin
  Error(1, 'abstract arr');
end;

procedure TSerializer.FinishArr;
begin
  Error(1, 'abstract finarr');
end;

function TDeserializer.Error(Code: PtrInt; Msg: PAnsiChar): Boolean;
begin
  if FErrCode = 0 then begin
    FErrCode := Code;
    FErrMsg := Msg;
  end;
  Exit(FErrCode = 0);
end;

procedure TDeserializer.ResetError;
begin
  FErrCode := 0;
  FErrMsg := '';
end;

constructor TDeserializer.Init;
begin
end;

destructor TDeserializer.Done;
begin
end;

function TDeserializer.Success: Boolean;
begin
  Exit(FErrCode = 0);
end;

function TDeserializer.Failed: Boolean;
begin
  Exit(FErrCode <> 0);
end;

function TDeserializer.Next: Boolean;
begin
  Error(1, 'abstract Next');
  Exit(False);
end;

function TDeserializer.Name: TAnsiView;
begin
  Error(1, 'abstract Name');
  Result := '';
end;

procedure TDeserializer.Attr(var Value: Int32; Def: Int32);
begin
  Value := Def;
  Error(1, 'abstract i32');
end;

end.
