You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

206 lines
7.4 KiB

  1. unit uutlVariantEnum;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, variants,
  6. uutlGenerics;
  7. function VarEnum: TVarType; inline;
  8. function VarIsEnum(const aValue: Variant): Boolean; inline;
  9. function VarAsEnum(const aValue: Variant): Variant; inline;
  10. function VarMakeEnum(const aValue: Integer): Variant;
  11. function VarMakeEnum(const aValue: Integer; const aHelper: TutlEnumHelperBaseClass): Variant;
  12. function VarGetEnumHelper(const aValue: Variant): TutlEnumHelperBaseClass;
  13. implementation
  14. type
  15. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  16. PEnumVarData = ^TEnumVarData;
  17. TEnumVarData = packed record
  18. vType: TVarType;
  19. case Integer of
  20. 0: (
  21. vValue: Integer;
  22. vHelper: TutlEnumHelperBaseClass;
  23. );
  24. 1: (vBytes : array[0..13] of byte);
  25. end;
  26. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  27. TutlVariantEnum = class(TCustomVariantType)
  28. public
  29. procedure Cast (var Dest: TVarData; const Source: TVarData); override;
  30. procedure CastTo(var Dest: TVarData; const Source: TVarData; const aVarType: TVarType); override;
  31. procedure Copy (var Dest: TVarData; const Source: TVarData; const Indirect: Boolean); override;
  32. procedure Clear (var V: TVarData); override;
  33. end;
  34. var
  35. VariantEnum: TutlVariantEnum;
  36. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  37. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  38. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  39. function VarEnum: TVarType;
  40. begin
  41. result := VariantEnum.VarType;
  42. end;
  43. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  44. function VarIsEnum(const aValue: Variant): Boolean;
  45. begin
  46. result := (VarType(aValue) = VariantEnum.VarType);
  47. end;
  48. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  49. function VarAsEnum(const aValue: Variant): Variant;
  50. begin
  51. if not VarIsEnum(aValue)
  52. then VarCast(result, aValue, VarEnum)
  53. else result := aValue;
  54. end;
  55. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  56. function VarMakeEnum(const aValue: Integer): Variant;
  57. begin
  58. result := VarMakeEnum(aValue, nil);
  59. end;
  60. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  61. function VarMakeEnum(const aValue: Integer; const aHelper: TutlEnumHelperBaseClass): Variant;
  62. begin
  63. with PEnumVarData(@TVarData(result))^ do begin
  64. vType := VariantEnum.VarType;
  65. vValue := aValue;
  66. vHelper := aHelper;
  67. end;
  68. end;
  69. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  70. function VarGetEnumHelper(const aValue: Variant): TutlEnumHelperBaseClass;
  71. begin
  72. if not VarIsEnum(aValue) then
  73. VarBadTypeError;
  74. result := PEnumVarData(@TVarData(aValue))^.vHelper;
  75. end;
  76. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  77. //TutlVariantEnum///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  78. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  79. procedure TutlVariantEnum.Cast(var Dest: TVarData; const Source: TVarData);
  80. function CheckValue(const aValue: Integer): Boolean;
  81. var
  82. i: Integer;
  83. begin
  84. with PEnumVarData(@Dest)^ do begin
  85. result := true;
  86. if not Assigned(vHelper) then
  87. exit;
  88. for i in vHelper.IntValues do
  89. if (i = aValue) then
  90. exit;
  91. result := false;
  92. end;
  93. end;
  94. var
  95. LSource: TVarData;
  96. begin
  97. if (Dest.vtype <> VariantEnum.VarType) then
  98. RaiseCastError;
  99. VarDataInit(LSource{%H-});
  100. try
  101. VarDataCopyNoInd(LSource, Source);
  102. case LSource.vtype of
  103. varsmallint,
  104. varinteger,
  105. vardecimal,
  106. varshortint,
  107. varbyte,
  108. varword,
  109. varlongword,
  110. varint64,
  111. varqword: with PEnumVarData(@Dest)^ do begin
  112. if not CheckValue(Variant(LSource)) then
  113. RaiseCastError;
  114. vValue := Variant(Source);
  115. end;
  116. else
  117. with PEnumVarData(@Dest)^ do begin
  118. if not Assigned(vHelper) then
  119. RaiseCastError;
  120. if not vHelper.TryToEnum(Variant(LSource), vValue, true) then
  121. RaiseCastError;
  122. end;
  123. end;
  124. finally
  125. VarDataClear(LSource);
  126. end;
  127. end;
  128. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  129. procedure TutlVariantEnum.CastTo(var Dest: TVarData; const Source: TVarData; const aVarType: TVarType);
  130. var
  131. tmp: TVarData;
  132. begin
  133. if (Source.vtype <> VarType) then
  134. RaiseCastError;
  135. with PEnumVarData(@Source)^ do begin
  136. case aVarType of
  137. varolestr:
  138. if Assigned(vHelper) then begin
  139. VarDataFromOleStr(Dest, WideString(vHelper.ToString(vValue, true)));
  140. exit;
  141. end;
  142. varstring:
  143. if Assigned(vHelper) then begin
  144. VarDataFromStr(Dest, vHelper.ToString(vValue, true));
  145. exit;
  146. end;
  147. end;
  148. VarDataInit(tmp{%H-});
  149. try
  150. tmp.vtype := varinteger;
  151. tmp.vinteger := vValue;
  152. VarDataCastTo(Dest, tmp, aVarType);
  153. finally
  154. VarDataClear(tmp);
  155. end;
  156. end;
  157. end;
  158. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  159. procedure TutlVariantEnum.Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean);
  160. var
  161. src, dst: PEnumVarData;
  162. begin
  163. if (Dest.vtype <> varempty) and (Dest.vtype <> Source.vtype) then
  164. RaiseInvalidOp;
  165. src := PEnumVarData(@Source);
  166. dst := PEnumVarData(@Dest);
  167. dst^ := src^;
  168. end;
  169. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  170. procedure TutlVariantEnum.Clear(var V: TVarData);
  171. begin
  172. // DUMMY
  173. end;
  174. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  175. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  176. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  177. initialization
  178. VariantEnum := TutlVariantEnum.Create;
  179. finalization
  180. FreeAndNil(VariantEnum);
  181. end.