unit w3persistent;
interface
uses
W3System;
type
EPersistent = Class(EW3Exception);
IPersistent = Interface
function objToString:String;
procedure objFromString(const aData:String);
procedure objReset;
end;
TPersistent = Class(TObject,IPersistent)
private
(* Implements:: IPersistent *)
function objToString:String;
Procedure objFromString(const aData:String);
procedure objReset;
protected
Procedure AssignTo(const aTarget:TPersistent);virtual;
public
Procedure Assign(const aSource:TPersistent);virtual;
End;
TNamedValuePair = Record
nvName: String;
nvValue: Variant;
End;
TNamedValuePairArray = Array of TNamedValuePair;
TPersistentHelper = Class helper for TPersistent
public
class function getRTTIProperties(var aPairs:TNamedValuePairArray):Integer;
class procedure setRTTIProperties(const aPairs:TNamedValuePairArray);
end;
implementation
resourcestring
CNT_ERR_TPERSISTENT_READ = 'Persistent read error [%s]';
CNT_ERR_TPERSISTENT_WRITE = 'Persistent write error [%s]';
//#############################################################################
// TPersistentHelper
//#############################################################################
class procedure TPersistentHelper.setRTTIProperties
(const aPairs:TNamedValuePairArray);
var
mRTTI: Array of TRTTIRawAttribute;
mAttrib: TRTTIRawAttribute;
mTypeId: TRTTITypeInfo;
x,y: Integer;
Begin
if aPairs.length>0 then
begin
for y:=aPairs.low to aPairs.high do
Begin
mTypeId:=TypeOf(self.classtype);
mRTTI:=RTTIRawAttributes;
if mRtti.length>0 then
Begin
for x:=mRtti.low to mRtti.high do
begin
mAttrib:=mRtti[x];
if (mAttrib.T = mTypeId)
and (mAttrib.A is RTTIPropertyAttribute) then
begin
var prop := RTTIPropertyAttribute(mAttrib.A);
if prop.name = aPairs[y].nvName then
prop.setter(variant(self),aPairs[y].nvValue);
end;
end;
end;
end;
end;
end;
class function TPersistentHelper.getRTTIProperties
(var aPairs:TNamedValuePairArray):Integer;
var
mRTTI: Array of TRTTIRawAttribute;
mAttrib: TRTTIRawAttribute;
mTypeId: TRTTITypeInfo;
x: Integer;
mPair: TNamedValuePair;
Begin
aPairs.clear;
result:=-1;
mTypeId:=TypeOf(self.classtype);
mRTTI:=RTTIRawAttributes;
if mRtti.Length>0 then
begin
for x:=mRtti.Low to mRtti.High do
begin
mAttrib:=mRtti[x];
if (mAttrib.T = mTypeId)
and (mAttrib.A is RTTIPropertyAttribute) then
begin
var prop := RTTIPropertyAttribute(mAttrib.A);
mPair.nvName:=prop.name;
mPair.nvValue:=Prop.Getter(Variant(self));
aPairs.add(mPair);
end;
end;
result:=aPairs.length;
end;
end;
//#############################################################################
// TPersistent
//#############################################################################
procedure TPersistent.objReset;
var
mData: TNamedValuePairArray;
x: Integer;
Begin
if getRTTIProperties(mData)>0 then
begin
for x:=mData.low to mData.high do
mData[x].nvValue:=undefined;
setRTTIProperties(mData);
end;
end;
function TPersistent.objToString:String;
var
mData: TNamedValuePairArray;
mCount: Integer;
x: Integer;
Begin
mCount:=getRTTIProperties(mData);
if mCount>0 then
begin
try
asm
@Result = JSON.stringify(@mData);
end;
finally
mData.clear;
end;
end
end;
Procedure TPersistent.objFromString(const aData:String);
var
mData: TNamedValuePairArray;
Begin
if length(aData)>0 then
Begin
asm
@mData = JSON.parse(@aData);
end;
if mData.length>0 then
Begin
setRTTIProperties(mData);
mData.clear;
end;
end else
objReset;
end;
Procedure TPersistent.Assign(const aSource:TPersistent);
Begin
if aSource<>NIL then
Begin
try
objFromString(aSource.objToString);
except
on e: exception do
Raise EPersistent.CreateFmt(CNT_ERR_TPERSISTENT_READ,[e.message]);
end;
end;
end;
procedure TPersistent.AssignTo(const aTarget: TPersistent);
begin
if aTarget<>NIL then
begin
try
aTarget.objFromString(objToString);
except
on e: exception do
Raise EPersistent.CreateFmt(CNT_ERR_TPERSISTENT_WRITE,[e.message]);
end;
end;
end;
end.
|