Nullable: System.Runtime.InteropServices.CustomMarshalers/WindowsRuntime (#23930)
[platform/upstream/coreclr.git] / src / System.Private.CoreLib / src / System / Runtime / InteropServices / WindowsRuntime / VectorToListAdapter.cs
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 #nullable enable
6 using System.Diagnostics;
7 using Internal.Runtime.CompilerServices;
8
9 namespace System.Runtime.InteropServices.WindowsRuntime
10 {
11     // This is a set of stub methods implementing the support for the IList`1 interface on WinRT
12     // objects that support IVector`1. Used by the interop mashaling infrastructure.
13     //
14     // The methods on this class must be written VERY carefully to avoid introducing security holes.
15     // That's because they are invoked with special "this"! The "this" object
16     // for all of these methods are not VectorToListAdapter objects. Rather, they are of type
17     // IVector<T>. No actual VectorToListAdapter object is ever instantiated. Thus, you will see
18     // a lot of expressions that cast "this" to "IVector<T>".
19     internal sealed class VectorToListAdapter
20     {
21         private VectorToListAdapter()
22         {
23             Debug.Fail("This class is never instantiated");
24         }
25
26         // T this[int index] { get }
27         internal T Indexer_Get<T>(int index)
28         {
29             if (index < 0)
30                 throw new ArgumentOutOfRangeException(nameof(index));
31
32             IVector<T> _this = Unsafe.As<IVector<T>>(this);
33             return GetAt(_this, (uint)index);
34         }
35
36         // T this[int index] { set }
37         internal void Indexer_Set<T>(int index, T value)
38         {
39             if (index < 0)
40                 throw new ArgumentOutOfRangeException(nameof(index));
41
42             IVector<T> _this = Unsafe.As<IVector<T>>(this);
43             SetAt(_this, (uint)index, value);
44         }
45
46         // int IndexOf(T item)
47         internal int IndexOf<T>(T item)
48         {
49             IVector<T> _this = Unsafe.As<IVector<T>>(this);
50
51             uint index;
52             bool exists = _this.IndexOf(item, out index);
53
54             if (!exists)
55                 return -1;
56
57             if (((uint)int.MaxValue) < index)
58             {
59                 throw new InvalidOperationException(SR.InvalidOperation_CollectionBackingListTooLarge);
60             }
61
62             return (int)index;
63         }
64
65         // void Insert(int index, T item)
66         internal void Insert<T>(int index, T item)
67         {
68             if (index < 0)
69                 throw new ArgumentOutOfRangeException(nameof(index));
70
71             IVector<T> _this = Unsafe.As<IVector<T>>(this);
72             InsertAtHelper<T>(_this, (uint)index, item);
73         }
74
75         // void RemoveAt(int index)
76         internal void RemoveAt<T>(int index)
77         {
78             if (index < 0)
79                 throw new ArgumentOutOfRangeException(nameof(index));
80
81             IVector<T> _this = Unsafe.As<IVector<T>>(this);
82             RemoveAtHelper<T>(_this, (uint)index);
83         }
84
85         // Helpers:
86
87         internal static T GetAt<T>(IVector<T> _this, uint index)
88         {
89             try
90             {
91                 return _this.GetAt(index);
92
93                 // We delegate bounds checking to the underlying collection and if it detected a fault,
94                 // we translate it to the right exception:
95             }
96             catch (Exception ex)
97             {
98                 if (HResults.E_BOUNDS == ex.HResult)
99                     throw new ArgumentOutOfRangeException(nameof(index));
100
101                 throw;
102             }
103         }
104
105         private static void SetAt<T>(IVector<T> _this, uint index, T value)
106         {
107             try
108             {
109                 _this.SetAt(index, value);
110
111                 // We deligate bounds checking to the underlying collection and if it detected a fault,
112                 // we translate it to the right exception:
113             }
114             catch (Exception ex)
115             {
116                 if (HResults.E_BOUNDS == ex.HResult)
117                     throw new ArgumentOutOfRangeException(nameof(index));
118
119                 throw;
120             }
121         }
122
123         private static void InsertAtHelper<T>(IVector<T> _this, uint index, T item)
124         {
125             try
126             {
127                 _this.InsertAt(index, item);
128
129                 // We delegate bounds checking to the underlying collection and if it detected a fault,
130                 // we translate it to the right exception:
131             }
132             catch (Exception ex)
133             {
134                 if (HResults.E_BOUNDS == ex.HResult)
135                     throw new ArgumentOutOfRangeException(nameof(index));
136
137                 throw;
138             }
139         }
140
141         internal static void RemoveAtHelper<T>(IVector<T> _this, uint index)
142         {
143             try
144             {
145                 _this.RemoveAt(index);
146
147                 // We delegate bounds checking to the underlying collection and if it detected a fault,
148                 // we translate it to the right exception:
149             }
150             catch (Exception ex)
151             {
152                 if (HResults.E_BOUNDS == ex.HResult)
153                     throw new ArgumentOutOfRangeException(nameof(index));
154
155                 throw;
156             }
157         }
158     }
159 }