Nullable: System.Runtime.InteropServices.CustomMarshalers/WindowsRuntime (#23930)
[platform/upstream/coreclr.git] / src / System.Private.CoreLib / src / System / Runtime / InteropServices / WindowsRuntime / BindableVectorToListAdapter.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 interface on WinRT
12     // objects that support IBindableVector. 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 BindableVectorToListAdapter objects. Rather, they are
17     // of type IBindableVector. No actual BindableVectorToListAdapter object is ever instantiated.
18     // Thus, you will see a lot of expressions that cast "this" to "IBindableVector".
19     internal sealed class BindableVectorToListAdapter
20     {
21         private BindableVectorToListAdapter()
22         {
23             Debug.Fail("This class is never instantiated");
24         }
25
26         // object this[int index] { get }
27         internal object? Indexer_Get(int index)
28         {
29             if (index < 0)
30                 throw new ArgumentOutOfRangeException(nameof(index));
31
32             IBindableVector _this = Unsafe.As<IBindableVector>(this);
33             return GetAt(_this, (uint)index);
34         }
35
36         // object this[int index] { set }
37         internal void Indexer_Set(int index, object value)
38         {
39             if (index < 0)
40                 throw new ArgumentOutOfRangeException(nameof(index));
41
42             IBindableVector _this = Unsafe.As<IBindableVector>(this);
43             SetAt(_this, (uint)index, value);
44         }
45
46         // int Add(object value)
47         internal int Add(object value)
48         {
49             IBindableVector _this = Unsafe.As<IBindableVector>(this);
50             _this.Append(value);
51
52             uint size = _this.Size;
53             if (((uint)int.MaxValue) < size)
54             {
55                 throw new InvalidOperationException(SR.InvalidOperation_CollectionBackingListTooLarge);
56             }
57
58             return (int)(size - 1);
59         }
60
61         // bool Contains(object item)
62         internal bool Contains(object item)
63         {
64             IBindableVector _this = Unsafe.As<IBindableVector>(this);
65
66             uint index;
67             return _this.IndexOf(item, out index);
68         }
69
70         // void Clear()
71         internal void Clear()
72         {
73             IBindableVector _this = Unsafe.As<IBindableVector>(this);
74             _this.Clear();
75         }
76
77         // bool IsFixedSize { get }
78         internal bool IsFixedSize()
79         {
80             return false;
81         }
82
83         // bool IsReadOnly { get }
84         internal bool IsReadOnly()
85         {
86             return false;
87         }
88
89         // int IndexOf(object item)
90         internal int IndexOf(object item)
91         {
92             IBindableVector _this = Unsafe.As<IBindableVector>(this);
93
94             uint index;
95             bool exists = _this.IndexOf(item, out index);
96
97             if (!exists)
98                 return -1;
99
100             if (((uint)int.MaxValue) < index)
101             {
102                 throw new InvalidOperationException(SR.InvalidOperation_CollectionBackingListTooLarge);
103             }
104
105             return (int)index;
106         }
107
108         // void Insert(int index, object item)
109         internal void Insert(int index, object item)
110         {
111             if (index < 0)
112                 throw new ArgumentOutOfRangeException(nameof(index));
113
114             IBindableVector _this = Unsafe.As<IBindableVector>(this);
115             InsertAtHelper(_this, (uint)index, item);
116         }
117
118         // bool Remove(object item)
119         internal void Remove(object item)
120         {
121             IBindableVector _this = Unsafe.As<IBindableVector>(this);
122
123             uint index;
124             bool exists = _this.IndexOf(item, out index);
125
126             if (exists)
127             {
128                 if (((uint)int.MaxValue) < index)
129                 {
130                     throw new InvalidOperationException(SR.InvalidOperation_CollectionBackingListTooLarge);
131                 }
132
133                 RemoveAtHelper(_this, index);
134             }
135         }
136
137         // void RemoveAt(int index)
138         internal void RemoveAt(int index)
139         {
140             if (index < 0)
141                 throw new ArgumentOutOfRangeException(nameof(index));
142
143             IBindableVector _this = Unsafe.As<IBindableVector>(this);
144             RemoveAtHelper(_this, (uint)index);
145         }
146
147         // Helpers:
148
149         private static object? GetAt(IBindableVector _this, uint index)
150         {
151             try
152             {
153                 return _this.GetAt(index);
154
155                 // We delegate bounds checking to the underlying collection and if it detected a fault,
156                 // we translate it to the right exception:
157             }
158             catch (Exception ex)
159             {
160                 if (HResults.E_BOUNDS == ex.HResult)
161                     throw new ArgumentOutOfRangeException(nameof(index));
162
163                 throw;
164             }
165         }
166
167         private static void SetAt(IBindableVector _this, uint index, object value)
168         {
169             try
170             {
171                 _this.SetAt(index, value);
172
173                 // We delegate bounds checking to the underlying collection and if it detected a fault,
174                 // we translate it to the right exception:
175             }
176             catch (Exception ex)
177             {
178                 if (HResults.E_BOUNDS == ex.HResult)
179                     throw new ArgumentOutOfRangeException(nameof(index));
180
181                 throw;
182             }
183         }
184
185         private static void InsertAtHelper(IBindableVector _this, uint index, object item)
186         {
187             try
188             {
189                 _this.InsertAt(index, item);
190
191                 // We delegate bounds checking to the underlying collection and if it detected a fault,
192                 // we translate it to the right exception:
193             }
194             catch (Exception ex)
195             {
196                 if (HResults.E_BOUNDS == ex.HResult)
197                     throw new ArgumentOutOfRangeException(nameof(index));
198
199                 throw;
200             }
201         }
202
203         private static void RemoveAtHelper(IBindableVector _this, uint index)
204         {
205             try
206             {
207                 _this.RemoveAt(index);
208
209                 // We delegate bounds checking to the underlying collection and if it detected a fault,
210                 // we translate it to the right exception:
211             }
212             catch (Exception ex)
213             {
214                 if (HResults.E_BOUNDS == ex.HResult)
215                     throw new ArgumentOutOfRangeException(nameof(index));
216
217                 throw;
218             }
219         }
220     }
221 }