| | | 1 | | // Copyright (c) ZeroC, Inc. |
| | | 2 | | |
| | | 3 | | using System.Buffers; |
| | | 4 | | using System.Collections.Immutable; |
| | | 5 | | using System.Runtime.InteropServices; |
| | | 6 | | |
| | | 7 | | namespace IceRpc.Ice.Codec; |
| | | 8 | | |
| | | 9 | | /// <summary>Provides extension methods for <see cref="IceEncoder" /> to encode sequences or dictionaries.</summary> |
| | | 10 | | public static class IceEncoderExtensions |
| | | 11 | | { |
| | | 12 | | /// <summary>Encodes a dictionary.</summary> |
| | | 13 | | /// <typeparam name="TKey">The dictionary key type.</typeparam> |
| | | 14 | | /// <typeparam name="TValue">The dictionary value type.</typeparam> |
| | | 15 | | /// <param name="encoder">The Ice encoder.</param> |
| | | 16 | | /// <param name="v">The dictionary to encode.</param> |
| | | 17 | | /// <param name="keyEncodeAction">The encode action for the keys.</param> |
| | | 18 | | /// <param name="valueEncodeAction">The encode action for the values.</param> |
| | | 19 | | public static void EncodeDictionary<TKey, TValue>( |
| | | 20 | | this ref IceEncoder encoder, |
| | | 21 | | IEnumerable<KeyValuePair<TKey, TValue>> v, |
| | | 22 | | EncodeAction<TKey> keyEncodeAction, |
| | | 23 | | EncodeAction<TValue> valueEncodeAction) |
| | | 24 | | where TKey : notnull |
| | 32 | 25 | | { |
| | 32 | 26 | | if (!v.TryGetNonEnumeratedCount(out int count)) |
| | 0 | 27 | | { |
| | 0 | 28 | | KeyValuePair<TKey, TValue>[] array = v.ToArray(); |
| | 0 | 29 | | count = array.Length; |
| | 0 | 30 | | v = array; |
| | 0 | 31 | | } |
| | 32 | 32 | | encoder.EncodeSize(count); |
| | 2902 | 33 | | foreach ((TKey key, TValue value) in v) |
| | 1403 | 34 | | { |
| | 1403 | 35 | | keyEncodeAction(ref encoder, key); |
| | 1403 | 36 | | valueEncodeAction(ref encoder, value); |
| | 1403 | 37 | | } |
| | 32 | 38 | | } |
| | | 39 | | |
| | | 40 | | /// <summary>Encodes a sequence of fixed-size numeric values, such as int or ulong.</summary> |
| | | 41 | | /// <typeparam name="T">The sequence element type.</typeparam> |
| | | 42 | | /// <param name="encoder">The Ice encoder.</param> |
| | | 43 | | /// <param name="v">The sequence of numeric values.</param> |
| | | 44 | | public static void EncodeSequence<T>(this ref IceEncoder encoder, IEnumerable<T> v) |
| | | 45 | | where T : struct |
| | 25 | 46 | | { |
| | 25 | 47 | | switch (v) |
| | | 48 | | { |
| | | 49 | | case T[] vArray: |
| | 19 | 50 | | encoder.EncodeSpan(new ReadOnlySpan<T>(vArray)); |
| | 19 | 51 | | break; |
| | | 52 | | |
| | | 53 | | case ImmutableArray<T> vImmutableArray: |
| | 2 | 54 | | encoder.EncodeSpan(vImmutableArray.AsSpan()); |
| | 2 | 55 | | break; |
| | | 56 | | |
| | | 57 | | case ArraySegment<T> vArraySegment: |
| | 2 | 58 | | encoder.EncodeSpan((ReadOnlySpan<T>)vArraySegment.AsSpan()); |
| | 2 | 59 | | break; |
| | | 60 | | |
| | | 61 | | case List<T> list: |
| | 1 | 62 | | encoder.EncodeSpan((ReadOnlySpan<T>)CollectionsMarshal.AsSpan(list)); |
| | 1 | 63 | | break; |
| | | 64 | | |
| | | 65 | | default: |
| | 1 | 66 | | encoder.EncodeSequence( |
| | 1 | 67 | | v, |
| | 257 | 68 | | (ref IceEncoder encoder, T element) => encoder.EncodeFixedSizeNumeric(element)); |
| | 1 | 69 | | break; |
| | | 70 | | } |
| | 25 | 71 | | } |
| | | 72 | | |
| | | 73 | | /// <summary>Encodes a sequence.</summary> |
| | | 74 | | /// <typeparam name="T">The type of the sequence elements. It is non-nullable except for class and proxy types. |
| | | 75 | | /// </typeparam> |
| | | 76 | | /// <param name="encoder">The Ice encoder.</param> |
| | | 77 | | /// <param name="v">The sequence to encode.</param> |
| | | 78 | | /// <param name="encodeAction">The encode action for an element.</param> |
| | | 79 | | public static void EncodeSequence<T>(this ref IceEncoder encoder, IEnumerable<T> v, EncodeAction<T> encodeAction) |
| | 1474 | 80 | | { |
| | 1474 | 81 | | if (!v.TryGetNonEnumeratedCount(out int count)) |
| | 7 | 82 | | { |
| | 7 | 83 | | var array = v.ToArray(); |
| | 7 | 84 | | count = array.Length; |
| | 7 | 85 | | v = array; |
| | 7 | 86 | | } |
| | 1474 | 87 | | encoder.EncodeSize(count); |
| | 9920 | 88 | | foreach (T item in v) |
| | 2749 | 89 | | { |
| | 2749 | 90 | | encodeAction(ref encoder, item); |
| | 2749 | 91 | | } |
| | 1474 | 92 | | } |
| | | 93 | | |
| | | 94 | | /// <summary>Encodes a span of fixed-size numeric values, such as int or ulong.</summary> |
| | | 95 | | /// <typeparam name="T">The span element type.</typeparam> |
| | | 96 | | /// <param name="encoder">The Ice encoder.</param> |
| | | 97 | | /// <param name="v">The span of numeric values represented by a <see cref="ReadOnlySpan{T}" />.</param> |
| | | 98 | | public static void EncodeSpan<T>(this ref IceEncoder encoder, ReadOnlySpan<T> v) |
| | | 99 | | where T : struct |
| | 33 | 100 | | { |
| | | 101 | | // This method works because (as long as) there is no padding in the memory representation of the ReadOnlySpan. |
| | 33 | 102 | | encoder.EncodeSize(v.Length); |
| | 33 | 103 | | if (!v.IsEmpty) |
| | 29 | 104 | | { |
| | 29 | 105 | | encoder.WriteByteSpan(MemoryMarshal.AsBytes(v)); |
| | 29 | 106 | | } |
| | 33 | 107 | | } |
| | | 108 | | |
| | | 109 | | /// <summary>Copies a sequence of bytes to the underlying buffer writer.</summary> |
| | | 110 | | /// <param name="encoder">The Ice encoder.</param> |
| | | 111 | | /// <param name="v">The sequence to copy.</param> |
| | | 112 | | public static void WriteByteSequence(this ref IceEncoder encoder, ReadOnlySequence<byte> v) |
| | 0 | 113 | | { |
| | 0 | 114 | | if (!v.IsEmpty) |
| | 0 | 115 | | { |
| | 0 | 116 | | if (v.IsSingleSegment) |
| | 0 | 117 | | { |
| | 0 | 118 | | encoder.WriteByteSpan(v.FirstSpan); |
| | 0 | 119 | | } |
| | | 120 | | else |
| | 0 | 121 | | { |
| | 0 | 122 | | foreach (ReadOnlyMemory<byte> buffer in v) |
| | 0 | 123 | | { |
| | 0 | 124 | | encoder.WriteByteSpan(buffer.Span); |
| | 0 | 125 | | } |
| | 0 | 126 | | } |
| | 0 | 127 | | } |
| | 0 | 128 | | } |
| | | 129 | | } |