THRIFT-5591 Add uuid type to IDL and implement reference code (+ improved self-tests)
Client: compiler general, netstd, Delphi
Patch: Jens Geyer
diff --git a/lib/delphi/src/Thrift.Utils.pas b/lib/delphi/src/Thrift.Utils.pas
index 4a75af8..1226535 100644
--- a/lib/delphi/src/Thrift.Utils.pas
+++ b/lib/delphi/src/Thrift.Utils.pas
@@ -84,11 +84,34 @@
class function IsHtmlDoctype( const fourBytes : Integer) : Boolean; static;
end;
+
+ IntegerUtils = class sealed
+ strict private
+ class procedure SwapBytes( var one, two : Byte); static; inline;
+ class procedure Swap2( const pValue : Pointer); static;
+ class procedure Swap4( const pValue : Pointer); static;
+ class procedure Swap8( const pValue : Pointer); static;
+ public
+ class procedure SwapByteOrder( const pValue : Pointer; const size : Integer); overload; static;
+ end;
+
+
+ TGuidHelper = record helper for System.TGuid
+ public
+ function SwapByteOrder : TGuid;
+
+ {$IFDEF Debug}
+ class procedure SelfTest; static;
+ {$ENDIF}
+ end;
+
+
EnumUtils<T> = class sealed
public
class function ToString(const value : Integer) : string; reintroduce; static; inline;
end;
+
StringUtils<T> = class sealed
public
class function ToString(const value : T) : string; reintroduce; static; inline;
@@ -283,6 +306,97 @@
result := (UpCase(pc^) = HTML_BEGIN[3]);
end;
+{ IntegerUtils }
+
+
+class procedure IntegerUtils.SwapBytes( var one, two : Byte);
+var tmp : Byte;
+begin
+ tmp := one;
+ one := two;
+ two := tmp;
+end;
+
+
+class procedure IntegerUtils.Swap2( const pValue : Pointer);
+var pData : PByteArray absolute pValue;
+begin
+ SwapBytes( pData^[0], pData^[1]);
+end;
+
+
+class procedure IntegerUtils.Swap4( const pValue : Pointer);
+var pData : PByteArray absolute pValue;
+begin
+ SwapBytes( pData^[0], pData^[3]);
+ SwapBytes( pData^[1], pData^[2]);
+end;
+
+
+class procedure IntegerUtils.Swap8( const pValue : Pointer);
+var pData : PByteArray absolute pValue;
+begin
+ SwapBytes( pData^[0], pData^[7]);
+ SwapBytes( pData^[1], pData^[6]);
+ SwapBytes( pData^[2], pData^[5]);
+ SwapBytes( pData^[3], pData^[4]);
+end;
+
+
+class procedure IntegerUtils.SwapByteOrder( const pValue : Pointer; const size : Integer);
+begin
+ case size of
+ 2 : Swap2( pValue);
+ 4 : Swap4( pValue);
+ 8 : Swap8( pValue);
+ else
+ raise EArgumentException.Create('Unexpected size');
+ end;
+end;
+
+
+{ TGuidHelper }
+
+
+function TGuidHelper.SwapByteOrder : TGuid;
+// convert to/from network byte order
+// - https://www.ietf.org/rfc/rfc4122.txt
+// - https://stackoverflow.com/questions/10850075/guid-uuid-compatibility-issue-between-net-and-linux
+// - https://lists.gnu.org/archive/html/bug-parted/2002-01/msg00099.html
+begin
+ result := Self;
+
+ IntegerUtils.SwapByteOrder( @result.D1, SizeOf(result.D1));
+ IntegerUtils.SwapByteOrder( @result.D2, SizeOf(result.D2));
+ IntegerUtils.SwapByteOrder( @result.D3, SizeOf(result.D3));
+ //result.D4 = array of byte -> implicitly correct
+end;
+
+
+{$IFDEF Debug}
+class procedure TGuidHelper.SelfTest;
+var guid : TGuid;
+ pBytes : PByteArray;
+ i, expected : Integer;
+const TEST_GUID : TGuid = '{00112233-4455-6677-8899-aabbccddeeff}';
+begin
+ // host to network
+ guid := TEST_GUID;
+ guid := guid.SwapByteOrder;
+
+ // validate network order
+ pBytes := @guid;
+ for i := 0 to $F do begin
+ expected := i * $11;
+ ASSERT( pBytes^[i] = expected);
+ end;
+
+ // network to host and final validation
+ guid := guid.SwapByteOrder;
+ ASSERT( IsEqualGuid( guid, TEST_GUID));
+end;
+{$ENDIF}
+
{$IFDEF Win64}
@@ -378,4 +492,8 @@
end;
+begin
+ {$IFDEF Debug}
+ TGuid.SelfTest;
+ {$ENDIF}
end.