1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Runtime.CompilerServices;
6 using System.Runtime.InteropServices;
7 using Xunit;
8 
9 using static System.Buffers.Binary.BinaryPrimitives;
10 
11 namespace System.Buffers.Binary.Tests
12 {
13     public class BinaryReaderUnitTests
14     {
15         [Fact]
SpanRead()16         public void SpanRead()
17         {
18             Assert.True(BitConverter.IsLittleEndian);
19 
20             ulong value = 0x8877665544332211; // [11 22 33 44 55 66 77 88]
21             Span<byte> span;
22             unsafe
23             {
24                 span = new Span<byte>(&value, 8);
25             }
26 
27             Assert.Equal<byte>(0x11, ReadMachineEndian<byte>(span));
28             Assert.True(TryReadMachineEndian(span, out byte byteValue));
29             Assert.Equal(0x11, byteValue);
30 
31             Assert.Equal<sbyte>(0x11, ReadMachineEndian<sbyte>(span));
32             Assert.True(TryReadMachineEndian(span, out byte sbyteValue));
33             Assert.Equal(0x11, byteValue);
34 
35             Assert.Equal<ushort>(0x1122, ReadUInt16BigEndian(span));
36             Assert.True(TryReadUInt16BigEndian(span, out ushort ushortValue));
37             Assert.Equal(0x1122, ushortValue);
38 
39             Assert.Equal<ushort>(0x2211, ReadUInt16LittleEndian(span));
40             Assert.True(TryReadUInt16LittleEndian(span, out ushortValue));
41             Assert.Equal(0x2211, ushortValue);
42 
43             Assert.Equal<short>(0x1122, ReadInt16BigEndian(span));
44             Assert.True(TryReadInt16BigEndian(span, out short shortValue));
45             Assert.Equal(0x1122, shortValue);
46 
47             Assert.Equal<short>(0x2211, ReadInt16LittleEndian(span));
48             Assert.True(TryReadInt16LittleEndian(span, out shortValue));
49             Assert.Equal(0x2211, ushortValue);
50 
51             Assert.Equal<uint>(0x11223344, ReadUInt32BigEndian(span));
52             Assert.True(TryReadUInt32BigEndian(span, out uint uintValue));
53             Assert.Equal<uint>(0x11223344, uintValue);
54 
55             Assert.Equal<uint>(0x44332211, ReadUInt32LittleEndian(span));
56             Assert.True(TryReadUInt32LittleEndian(span, out uintValue));
57             Assert.Equal<uint>(0x44332211, uintValue);
58 
59             Assert.Equal<int>(0x11223344, ReadInt32BigEndian(span));
60             Assert.True(TryReadInt32BigEndian(span, out int intValue));
61             Assert.Equal<int>(0x11223344, intValue);
62 
63             Assert.Equal<int>(0x44332211, ReadInt32LittleEndian(span));
64             Assert.True(TryReadInt32LittleEndian(span, out intValue));
65             Assert.Equal<int>(0x44332211, intValue);
66 
67             Assert.Equal<ulong>(0x1122334455667788, ReadUInt64BigEndian(span));
68             Assert.True(TryReadUInt64BigEndian(span, out ulong ulongValue));
69             Assert.Equal<ulong>(0x1122334455667788, ulongValue);
70 
71             Assert.Equal<ulong>(0x8877665544332211, ReadUInt64LittleEndian(span));
72             Assert.True(TryReadUInt64LittleEndian(span, out ulongValue));
73             Assert.Equal<ulong>(0x8877665544332211, ulongValue);
74 
75             Assert.Equal<long>(0x1122334455667788, ReadInt64BigEndian(span));
76             Assert.True(TryReadInt64BigEndian(span, out long longValue));
77             Assert.Equal<long>(0x1122334455667788, longValue);
78 
79             Assert.Equal<long>(unchecked((long)0x8877665544332211), ReadInt64LittleEndian(span));
80             Assert.True(TryReadInt64LittleEndian(span, out longValue));
81             Assert.Equal<long>(unchecked((long)0x8877665544332211), longValue);
82         }
83 
84         [Fact]
ReadOnlySpanRead()85         public void ReadOnlySpanRead()
86         {
87             Assert.True(BitConverter.IsLittleEndian);
88 
89             ulong value = 0x8877665544332211; // [11 22 33 44 55 66 77 88]
90             ReadOnlySpan<byte> span;
91             unsafe
92             {
93                 span = new ReadOnlySpan<byte>(&value, 8);
94             }
95 
96             Assert.Equal<byte>(0x11, ReadMachineEndian<byte>(span));
97             Assert.True(TryReadMachineEndian(span, out byte byteValue));
98             Assert.Equal(0x11, byteValue);
99 
100             Assert.Equal<sbyte>(0x11, ReadMachineEndian<sbyte>(span));
101             Assert.True(TryReadMachineEndian(span, out byte sbyteValue));
102             Assert.Equal(0x11, byteValue);
103 
104             Assert.Equal<ushort>(0x1122, ReadUInt16BigEndian(span));
105             Assert.True(TryReadUInt16BigEndian(span, out ushort ushortValue));
106             Assert.Equal(0x1122, ushortValue);
107 
108             Assert.Equal<ushort>(0x2211, ReadUInt16LittleEndian(span));
109             Assert.True(TryReadUInt16LittleEndian(span, out ushortValue));
110             Assert.Equal(0x2211, ushortValue);
111 
112             Assert.Equal<short>(0x1122, ReadInt16BigEndian(span));
113             Assert.True(TryReadInt16BigEndian(span, out short shortValue));
114             Assert.Equal(0x1122, shortValue);
115 
116             Assert.Equal<short>(0x2211, ReadInt16LittleEndian(span));
117             Assert.True(TryReadInt16LittleEndian(span, out shortValue));
118             Assert.Equal(0x2211, ushortValue);
119 
120             Assert.Equal<uint>(0x11223344, ReadUInt32BigEndian(span));
121             Assert.True(TryReadUInt32BigEndian(span, out uint uintValue));
122             Assert.Equal<uint>(0x11223344, uintValue);
123 
124             Assert.Equal<uint>(0x44332211, ReadUInt32LittleEndian(span));
125             Assert.True(TryReadUInt32LittleEndian(span, out uintValue));
126             Assert.Equal<uint>(0x44332211, uintValue);
127 
128             Assert.Equal<int>(0x11223344, ReadInt32BigEndian(span));
129             Assert.True(TryReadInt32BigEndian(span, out int intValue));
130             Assert.Equal<int>(0x11223344, intValue);
131 
132             Assert.Equal<int>(0x44332211, ReadInt32LittleEndian(span));
133             Assert.True(TryReadInt32LittleEndian(span, out intValue));
134             Assert.Equal<int>(0x44332211, intValue);
135 
136             Assert.Equal<ulong>(0x1122334455667788, ReadUInt64BigEndian(span));
137             Assert.True(TryReadUInt64BigEndian(span, out ulong ulongValue));
138             Assert.Equal<ulong>(0x1122334455667788, ulongValue);
139 
140             Assert.Equal<ulong>(0x8877665544332211, ReadUInt64LittleEndian(span));
141             Assert.True(TryReadUInt64LittleEndian(span, out ulongValue));
142             Assert.Equal<ulong>(0x8877665544332211, ulongValue);
143 
144             Assert.Equal<long>(0x1122334455667788, ReadInt64BigEndian(span));
145             Assert.True(TryReadInt64BigEndian(span, out long longValue));
146             Assert.Equal<long>(0x1122334455667788, longValue);
147 
148             Assert.Equal<long>(unchecked((long)0x8877665544332211), ReadInt64LittleEndian(span));
149             Assert.True(TryReadInt64LittleEndian(span, out longValue));
150             Assert.Equal<long>(unchecked((long)0x8877665544332211), longValue);
151         }
152 
153         [Fact]
SpanReadFail()154         public void SpanReadFail()
155         {
156             Span<byte> span = new byte[] { 1 };
157 
158             Assert.Equal<byte>(1, ReadMachineEndian<byte>(span));
159             Assert.True(TryReadMachineEndian(span, out byte byteValue));
160             Assert.Equal(1, byteValue);
161 
162             TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => ReadMachineEndian<short>(_span));
163             Assert.False(TryReadMachineEndian(span, out short shortValue));
164             TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => ReadMachineEndian<int>(_span));
165             Assert.False(TryReadMachineEndian(span, out int intValue));
166             TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => ReadMachineEndian<long>(_span));
167             Assert.False(TryReadMachineEndian(span, out long longValue));
168 
169             TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => ReadMachineEndian<ushort>(_span));
170             Assert.False(TryReadMachineEndian(span, out ushort ushortValue));
171             TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => ReadMachineEndian<uint>(_span));
172             Assert.False(TryReadMachineEndian(span, out uint uintValue));
173             TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => ReadMachineEndian<ulong>(_span));
174             Assert.False(TryReadMachineEndian(span, out ulong ulongValue));
175 
176             Span<byte> largeSpan = new byte[100];
177             TestHelpers.AssertThrows<ArgumentException, byte>(largeSpan, (_span) => ReadMachineEndian<TestHelpers.TestValueTypeWithReference>(_span));
178             TestHelpers.AssertThrows<ArgumentException, byte>(largeSpan, (_span) => TryReadMachineEndian(_span, out TestHelpers.TestValueTypeWithReference stringValue));
179         }
180 
181         [Fact]
ReadOnlySpanReadFail()182         public void ReadOnlySpanReadFail()
183         {
184             ReadOnlySpan<byte> span = new byte[] { 1 };
185 
186             Assert.Equal<byte>(1, ReadMachineEndian<byte>(span));
187             Assert.True(TryReadMachineEndian(span, out byte byteValue));
188             Assert.Equal(1, byteValue);
189 
190             TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => ReadMachineEndian<short>(_span));
191             Assert.False(TryReadMachineEndian(span, out short shortValue));
192             TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => ReadMachineEndian<int>(_span));
193             Assert.False(TryReadMachineEndian(span, out int intValue));
194             TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => ReadMachineEndian<long>(_span));
195             Assert.False(TryReadMachineEndian(span, out long longValue));
196 
197             TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => ReadMachineEndian<ushort>(_span));
198             Assert.False(TryReadMachineEndian(span, out ushort ushortValue));
199             TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => ReadMachineEndian<uint>(_span));
200             Assert.False(TryReadMachineEndian(span, out uint uintValue));
201             TestHelpers.AssertThrows<ArgumentOutOfRangeException, byte>(span, (_span) => ReadMachineEndian<ulong>(_span));
202             Assert.False(TryReadMachineEndian(span, out ulong ulongValue));
203 
204             ReadOnlySpan<byte> largeSpan = new byte[100];
205             TestHelpers.AssertThrows<ArgumentException, byte>(largeSpan, (_span) => ReadMachineEndian<TestHelpers.TestValueTypeWithReference>(_span));
206             TestHelpers.AssertThrows<ArgumentException, byte>(largeSpan, (_span) => TryReadMachineEndian(_span, out TestHelpers.TestValueTypeWithReference stringValue));
207         }
208 
209         [Fact]
ReverseByteDoesNothing()210         public void ReverseByteDoesNothing()
211         {
212             byte valueMax = byte.MaxValue;
213             byte valueMin = byte.MinValue;
214             sbyte signedValueMax = sbyte.MaxValue;
215             sbyte signedValueMin = sbyte.MinValue;
216 
217             Assert.Equal(valueMax, ReverseEndianness(valueMax));
218             Assert.Equal(valueMin, ReverseEndianness(valueMin));
219             Assert.Equal(signedValueMax, ReverseEndianness(signedValueMax));
220             Assert.Equal(signedValueMin, ReverseEndianness(signedValueMin));
221         }
222 
223         [Fact]
SpanWriteAndReadBigEndianHeterogeneousStruct()224         public void SpanWriteAndReadBigEndianHeterogeneousStruct()
225         {
226             Assert.True(BitConverter.IsLittleEndian);
227 
228             Span<byte> spanBE = new byte[Unsafe.SizeOf<TestStruct>()];
229 
230             WriteInt16BigEndian(spanBE, s_testStruct.S0);
231             WriteInt32BigEndian(spanBE.Slice(2), s_testStruct.I0);
232             WriteInt64BigEndian(spanBE.Slice(6), s_testStruct.L0);
233             WriteUInt16BigEndian(spanBE.Slice(14), s_testStruct.US0);
234             WriteUInt32BigEndian(spanBE.Slice(16), s_testStruct.UI0);
235             WriteUInt64BigEndian(spanBE.Slice(20), s_testStruct.UL0);
236             WriteInt16BigEndian(spanBE.Slice(28), s_testStruct.S1);
237             WriteInt32BigEndian(spanBE.Slice(30), s_testStruct.I1);
238             WriteInt64BigEndian(spanBE.Slice(34), s_testStruct.L1);
239             WriteUInt16BigEndian(spanBE.Slice(42), s_testStruct.US1);
240             WriteUInt32BigEndian(spanBE.Slice(44), s_testStruct.UI1);
241             WriteUInt64BigEndian(spanBE.Slice(48), s_testStruct.UL1);
242 
243             ReadOnlySpan<byte> readOnlySpanBE = new ReadOnlySpan<byte>(spanBE.ToArray());
244 
245             var readStruct = new TestStruct
246             {
247                 S0 = ReadInt16BigEndian(spanBE),
248                 I0 = ReadInt32BigEndian(spanBE.Slice(2)),
249                 L0 = ReadInt64BigEndian(spanBE.Slice(6)),
250                 US0 = ReadUInt16BigEndian(spanBE.Slice(14)),
251                 UI0 = ReadUInt32BigEndian(spanBE.Slice(16)),
252                 UL0 = ReadUInt64BigEndian(spanBE.Slice(20)),
253                 S1 = ReadInt16BigEndian(spanBE.Slice(28)),
254                 I1 = ReadInt32BigEndian(spanBE.Slice(30)),
255                 L1 = ReadInt64BigEndian(spanBE.Slice(34)),
256                 US1 = ReadUInt16BigEndian(spanBE.Slice(42)),
257                 UI1 = ReadUInt32BigEndian(spanBE.Slice(44)),
258                 UL1 = ReadUInt64BigEndian(spanBE.Slice(48))
259             };
260 
261             var readStructFromReadOnlySpan = new TestStruct
262             {
263                 S0 = ReadInt16BigEndian(readOnlySpanBE),
264                 I0 = ReadInt32BigEndian(readOnlySpanBE.Slice(2)),
265                 L0 = ReadInt64BigEndian(readOnlySpanBE.Slice(6)),
266                 US0 = ReadUInt16BigEndian(readOnlySpanBE.Slice(14)),
267                 UI0 = ReadUInt32BigEndian(readOnlySpanBE.Slice(16)),
268                 UL0 = ReadUInt64BigEndian(readOnlySpanBE.Slice(20)),
269                 S1 = ReadInt16BigEndian(readOnlySpanBE.Slice(28)),
270                 I1 = ReadInt32BigEndian(readOnlySpanBE.Slice(30)),
271                 L1 = ReadInt64BigEndian(readOnlySpanBE.Slice(34)),
272                 US1 = ReadUInt16BigEndian(readOnlySpanBE.Slice(42)),
273                 UI1 = ReadUInt32BigEndian(readOnlySpanBE.Slice(44)),
274                 UL1 = ReadUInt64BigEndian(readOnlySpanBE.Slice(48))
275             };
276 
277             Assert.Equal(s_testStruct, readStruct);
278             Assert.Equal(s_testStruct, readStructFromReadOnlySpan);
279         }
280 
281         [Fact]
SpanWriteAndReadLittleEndianHeterogeneousStruct()282         public void SpanWriteAndReadLittleEndianHeterogeneousStruct()
283         {
284             Assert.True(BitConverter.IsLittleEndian);
285 
286             Span<byte> spanLE = new byte[Unsafe.SizeOf<TestStruct>()];
287 
288             WriteInt16LittleEndian(spanLE, s_testStruct.S0);
289             WriteInt32LittleEndian(spanLE.Slice(2), s_testStruct.I0);
290             WriteInt64LittleEndian(spanLE.Slice(6), s_testStruct.L0);
291             WriteUInt16LittleEndian(spanLE.Slice(14), s_testStruct.US0);
292             WriteUInt32LittleEndian(spanLE.Slice(16), s_testStruct.UI0);
293             WriteUInt64LittleEndian(spanLE.Slice(20), s_testStruct.UL0);
294             WriteInt16LittleEndian(spanLE.Slice(28), s_testStruct.S1);
295             WriteInt32LittleEndian(spanLE.Slice(30), s_testStruct.I1);
296             WriteInt64LittleEndian(spanLE.Slice(34), s_testStruct.L1);
297             WriteUInt16LittleEndian(spanLE.Slice(42), s_testStruct.US1);
298             WriteUInt32LittleEndian(spanLE.Slice(44), s_testStruct.UI1);
299             WriteUInt64LittleEndian(spanLE.Slice(48), s_testStruct.UL1);
300 
301             ReadOnlySpan<byte> readOnlySpanLE = new ReadOnlySpan<byte>(spanLE.ToArray());
302 
303             var readStruct = new TestStruct
304             {
305                 S0 = ReadInt16LittleEndian(spanLE),
306                 I0 = ReadInt32LittleEndian(spanLE.Slice(2)),
307                 L0 = ReadInt64LittleEndian(spanLE.Slice(6)),
308                 US0 = ReadUInt16LittleEndian(spanLE.Slice(14)),
309                 UI0 = ReadUInt32LittleEndian(spanLE.Slice(16)),
310                 UL0 = ReadUInt64LittleEndian(spanLE.Slice(20)),
311                 S1 = ReadInt16LittleEndian(spanLE.Slice(28)),
312                 I1 = ReadInt32LittleEndian(spanLE.Slice(30)),
313                 L1 = ReadInt64LittleEndian(spanLE.Slice(34)),
314                 US1 = ReadUInt16LittleEndian(spanLE.Slice(42)),
315                 UI1 = ReadUInt32LittleEndian(spanLE.Slice(44)),
316                 UL1 = ReadUInt64LittleEndian(spanLE.Slice(48))
317             };
318 
319             var readStructFromReadOnlySpan = new TestStruct
320             {
321                 S0 = ReadInt16LittleEndian(readOnlySpanLE),
322                 I0 = ReadInt32LittleEndian(readOnlySpanLE.Slice(2)),
323                 L0 = ReadInt64LittleEndian(readOnlySpanLE.Slice(6)),
324                 US0 = ReadUInt16LittleEndian(readOnlySpanLE.Slice(14)),
325                 UI0 = ReadUInt32LittleEndian(readOnlySpanLE.Slice(16)),
326                 UL0 = ReadUInt64LittleEndian(readOnlySpanLE.Slice(20)),
327                 S1 = ReadInt16LittleEndian(readOnlySpanLE.Slice(28)),
328                 I1 = ReadInt32LittleEndian(readOnlySpanLE.Slice(30)),
329                 L1 = ReadInt64LittleEndian(readOnlySpanLE.Slice(34)),
330                 US1 = ReadUInt16LittleEndian(readOnlySpanLE.Slice(42)),
331                 UI1 = ReadUInt32LittleEndian(readOnlySpanLE.Slice(44)),
332                 UL1 = ReadUInt64LittleEndian(readOnlySpanLE.Slice(48))
333             };
334 
335             Assert.Equal(s_testStruct, readStruct);
336             Assert.Equal(s_testStruct, readStructFromReadOnlySpan);
337         }
338 
339         [Fact]
ReadingStructFieldByFieldOrReadAndReverseEndianness()340         public void ReadingStructFieldByFieldOrReadAndReverseEndianness()
341         {
342             Assert.True(BitConverter.IsLittleEndian);
343             Span<byte> spanBE = new byte[Unsafe.SizeOf<TestHelpers.TestStructExplicit>()];
344 
345             var testExplicitStruct = new TestHelpers.TestStructExplicit
346             {
347                 S0 = short.MaxValue,
348                 I0 = int.MaxValue,
349                 L0 = long.MaxValue,
350                 US0 = ushort.MaxValue,
351                 UI0 = uint.MaxValue,
352                 UL0 = ulong.MaxValue,
353                 S1 = short.MinValue,
354                 I1 = int.MinValue,
355                 L1 = long.MinValue,
356                 US1 = ushort.MinValue,
357                 UI1 = uint.MinValue,
358                 UL1 = ulong.MinValue
359             };
360 
361             WriteInt16BigEndian(spanBE, testExplicitStruct.S0);
362             WriteInt32BigEndian(spanBE.Slice(2), testExplicitStruct.I0);
363             WriteInt64BigEndian(spanBE.Slice(6), testExplicitStruct.L0);
364             WriteUInt16BigEndian(spanBE.Slice(14), testExplicitStruct.US0);
365             WriteUInt32BigEndian(spanBE.Slice(16), testExplicitStruct.UI0);
366             WriteUInt64BigEndian(spanBE.Slice(20), testExplicitStruct.UL0);
367             WriteInt16BigEndian(spanBE.Slice(28), testExplicitStruct.S1);
368             WriteInt32BigEndian(spanBE.Slice(30), testExplicitStruct.I1);
369             WriteInt64BigEndian(spanBE.Slice(34), testExplicitStruct.L1);
370             WriteUInt16BigEndian(spanBE.Slice(42), testExplicitStruct.US1);
371             WriteUInt32BigEndian(spanBE.Slice(44), testExplicitStruct.UI1);
372             WriteUInt64BigEndian(spanBE.Slice(48), testExplicitStruct.UL1);
373 
374             Assert.Equal(56, spanBE.Length);
375 
376             ReadOnlySpan<byte> readOnlySpanBE = new ReadOnlySpan<byte>(spanBE.ToArray());
377 
378             TestHelpers.TestStructExplicit readStructAndReverse = ReadMachineEndian<TestHelpers.TestStructExplicit>(spanBE);
379             if (BitConverter.IsLittleEndian)
380             {
381                 readStructAndReverse.S0 = ReverseEndianness(readStructAndReverse.S0);
382                 readStructAndReverse.I0 = ReverseEndianness(readStructAndReverse.I0);
383                 readStructAndReverse.L0 = ReverseEndianness(readStructAndReverse.L0);
384                 readStructAndReverse.US0 = ReverseEndianness(readStructAndReverse.US0);
385                 readStructAndReverse.UI0 = ReverseEndianness(readStructAndReverse.UI0);
386                 readStructAndReverse.UL0 = ReverseEndianness(readStructAndReverse.UL0);
387                 readStructAndReverse.S1 = ReverseEndianness(readStructAndReverse.S1);
388                 readStructAndReverse.I1 = ReverseEndianness(readStructAndReverse.I1);
389                 readStructAndReverse.L1 = ReverseEndianness(readStructAndReverse.L1);
390                 readStructAndReverse.US1 = ReverseEndianness(readStructAndReverse.US1);
391                 readStructAndReverse.UI1 = ReverseEndianness(readStructAndReverse.UI1);
392                 readStructAndReverse.UL1 = ReverseEndianness(readStructAndReverse.UL1);
393             }
394 
395             var readStructFieldByField = new TestHelpers.TestStructExplicit
396             {
397                 S0 = ReadInt16BigEndian(spanBE),
398                 I0 = ReadInt32BigEndian(spanBE.Slice(2)),
399                 L0 = ReadInt64BigEndian(spanBE.Slice(6)),
400                 US0 = ReadUInt16BigEndian(spanBE.Slice(14)),
401                 UI0 = ReadUInt32BigEndian(spanBE.Slice(16)),
402                 UL0 = ReadUInt64BigEndian(spanBE.Slice(20)),
403                 S1 = ReadInt16BigEndian(spanBE.Slice(28)),
404                 I1 = ReadInt32BigEndian(spanBE.Slice(30)),
405                 L1 = ReadInt64BigEndian(spanBE.Slice(34)),
406                 US1 = ReadUInt16BigEndian(spanBE.Slice(42)),
407                 UI1 = ReadUInt32BigEndian(spanBE.Slice(44)),
408                 UL1 = ReadUInt64BigEndian(spanBE.Slice(48))
409             };
410 
411             TestHelpers.TestStructExplicit readStructAndReverseFromReadOnlySpan = ReadMachineEndian<TestHelpers.TestStructExplicit>(readOnlySpanBE);
412             if (BitConverter.IsLittleEndian)
413             {
414                 readStructAndReverseFromReadOnlySpan.S0 = ReverseEndianness(readStructAndReverseFromReadOnlySpan.S0);
415                 readStructAndReverseFromReadOnlySpan.I0 = ReverseEndianness(readStructAndReverseFromReadOnlySpan.I0);
416                 readStructAndReverseFromReadOnlySpan.L0 = ReverseEndianness(readStructAndReverseFromReadOnlySpan.L0);
417                 readStructAndReverseFromReadOnlySpan.US0 = ReverseEndianness(readStructAndReverseFromReadOnlySpan.US0);
418                 readStructAndReverseFromReadOnlySpan.UI0 = ReverseEndianness(readStructAndReverseFromReadOnlySpan.UI0);
419                 readStructAndReverseFromReadOnlySpan.UL0 = ReverseEndianness(readStructAndReverseFromReadOnlySpan.UL0);
420                 readStructAndReverseFromReadOnlySpan.S1 = ReverseEndianness(readStructAndReverseFromReadOnlySpan.S1);
421                 readStructAndReverseFromReadOnlySpan.I1 = ReverseEndianness(readStructAndReverseFromReadOnlySpan.I1);
422                 readStructAndReverseFromReadOnlySpan.L1 = ReverseEndianness(readStructAndReverseFromReadOnlySpan.L1);
423                 readStructAndReverseFromReadOnlySpan.US1 = ReverseEndianness(readStructAndReverseFromReadOnlySpan.US1);
424                 readStructAndReverseFromReadOnlySpan.UI1 = ReverseEndianness(readStructAndReverseFromReadOnlySpan.UI1);
425                 readStructAndReverseFromReadOnlySpan.UL1 = ReverseEndianness(readStructAndReverseFromReadOnlySpan.UL1);
426             }
427 
428             var readStructFieldByFieldFromReadOnlySpan = new TestHelpers.TestStructExplicit
429             {
430                 S0 = ReadInt16BigEndian(readOnlySpanBE),
431                 I0 = ReadInt32BigEndian(readOnlySpanBE.Slice(2)),
432                 L0 = ReadInt64BigEndian(readOnlySpanBE.Slice(6)),
433                 US0 = ReadUInt16BigEndian(readOnlySpanBE.Slice(14)),
434                 UI0 = ReadUInt32BigEndian(readOnlySpanBE.Slice(16)),
435                 UL0 = ReadUInt64BigEndian(readOnlySpanBE.Slice(20)),
436                 S1 = ReadInt16BigEndian(readOnlySpanBE.Slice(28)),
437                 I1 = ReadInt32BigEndian(readOnlySpanBE.Slice(30)),
438                 L1 = ReadInt64BigEndian(readOnlySpanBE.Slice(34)),
439                 US1 = ReadUInt16BigEndian(readOnlySpanBE.Slice(42)),
440                 UI1 = ReadUInt32BigEndian(readOnlySpanBE.Slice(44)),
441                 UL1 = ReadUInt64BigEndian(readOnlySpanBE.Slice(48))
442             };
443 
444             Assert.Equal(testExplicitStruct, readStructAndReverse);
445             Assert.Equal(testExplicitStruct, readStructFieldByField);
446 
447             Assert.Equal(testExplicitStruct, readStructAndReverseFromReadOnlySpan);
448             Assert.Equal(testExplicitStruct, readStructFieldByFieldFromReadOnlySpan);
449         }
450 
451         private static TestStruct s_testStruct = new TestStruct
452         {
453             S0 = short.MaxValue,
454             I0 = int.MaxValue,
455             L0 = long.MaxValue,
456             US0 = ushort.MaxValue,
457             UI0 = uint.MaxValue,
458             UL0 = ulong.MaxValue,
459             S1 = short.MinValue,
460             I1 = int.MinValue,
461             L1 = long.MinValue,
462             US1 = ushort.MinValue,
463             UI1 = uint.MinValue,
464             UL1 = ulong.MinValue
465         };
466 
467         [StructLayout(LayoutKind.Sequential)]
468         private struct TestStruct
469         {
470             public short S0;
471             public int I0;
472             public long L0;
473             public ushort US0;
474             public uint UI0;
475             public ulong UL0;
476             public short S1;
477             public int I1;
478             public long L1;
479             public ushort US1;
480             public uint UI1;
481             public ulong UL1;
482         }
483     }
484 }
485