Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Metadata / Edm / FacetDescription.cs
1 //---------------------------------------------------------------------
2 // <copyright file="FacetDescription.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // @owner       Microsoft
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
9
10 using System;
11 using System.Collections.Generic;
12 using System.Data.Common;
13 using System.Text;
14 using System.Diagnostics;
15 using System.Threading;
16
17 namespace System.Data.Metadata.Edm
18 {
19     /// <summary>
20     /// Class for representing a FacetDescription object
21     /// </summary>
22     public sealed class FacetDescription
23     {
24         #region Constructors
25
26
27
28         internal FacetDescription(string facetName,
29                                   EdmType facetType,
30                                   int? minValue,
31                                   int? maxValue,
32                                   object defaultValue,
33                                   bool isConstant,
34                                   string declaringTypeName)
35         {
36             _facetName = facetName;
37             _facetType = facetType;
38             _minValue = minValue;
39             _maxValue = maxValue;
40             
41             // this ctor doesn't allow you to set the defaultValue to null
42             if (defaultValue != null)
43             {
44                 _defaultValue = defaultValue;
45             }
46             else
47             {
48                 _defaultValue = _notInitializedSentinel;
49             }
50             _isConstant = isConstant;
51             
52             Validate(declaringTypeName);
53             if (_isConstant)
54             {
55                 UpdateMinMaxValueForConstant(_facetName, _facetType, ref _minValue, ref _maxValue, _defaultValue);
56             }
57         }
58         
59         /// <summary>
60         /// The constructor for constructing a facet description object
61         /// </summary>
62         /// <param name="facetName">The name of this facet</param>
63         /// <param name="facetType">The type of this facet</param>
64         /// <param name="minValue">The min value for this facet</param>
65         /// <param name="maxValue">The max value for this facet</param>
66         /// <param name="defaultValue">The default value for this facet</param>
67         /// <exception cref="System.ArgumentNullException">Thrown if either facetName, facetType or applicableType arguments are null</exception>
68         internal FacetDescription(string facetName,
69                                   EdmType facetType,
70                                   int? minValue,
71                                   int? maxValue,
72                                   object defaultValue)
73         {
74             EntityUtil.CheckStringArgument(facetName, "facetName");
75             EntityUtil.GenericCheckArgumentNull(facetType, "facetType");
76
77             if (minValue.HasValue || maxValue.HasValue)
78             {
79                 Debug.Assert(FacetDescription.IsNumericType(facetType), "Min and Max Values can only be specified for numeric facets");
80
81                 if (minValue.HasValue && maxValue.HasValue)
82                 {
83                     Debug.Assert(minValue != maxValue, "minValue should not be equal to maxValue");
84                 }
85             }
86
87             _facetName = facetName;
88             _facetType = facetType;
89             _minValue = minValue;
90             _maxValue = maxValue;
91             _defaultValue = defaultValue;
92         }
93
94         #endregion
95
96         #region Fields
97         private readonly string _facetName;
98         private readonly EdmType _facetType;
99         private readonly int? _minValue;
100         private readonly int? _maxValue;
101         private readonly object _defaultValue;
102         private readonly bool _isConstant;
103
104         /// <summary>A facet with the default value for this description.</summary>
105         private Facet _defaultValueFacet;
106
107         /// <summary>A facet with a null value for this description.</summary>
108         private Facet _nullValueFacet;
109
110         /// <summary>Type-dependant cache for additional values (possibly null).</summary>
111         private Facet[] _valueCache;
112
113         // we need to differentiate when the default value is null vs when the default value is not initialized
114         private static object _notInitializedSentinel = new object();
115         #endregion
116
117         #region Properties
118         /// <summary>
119         /// Gets the name of this facet
120         /// </summary>
121         public string FacetName
122         {
123             get
124             {
125                 return _facetName;
126             }
127         }
128
129         /// <summary>
130         /// Gets the type of this facet
131         /// </summary>
132         public EdmType FacetType
133         {
134             get
135             {
136                 return _facetType;
137             }
138         }
139
140         /// <summary>
141         /// Gets the lower bound a facet with this facet description can take
142         /// </summary>
143         public int? MinValue
144         {
145             get
146             {
147                 return _minValue;
148             }
149         }
150
151         /// <summary>
152         /// Gets the upper bound a facet with this facet description can take
153         /// </summary>
154         public int? MaxValue
155         {
156             get
157             {
158                 return _maxValue;
159             }
160         }
161
162         /// <summary>
163         /// Gets the default value of a facet with this facet description
164         /// </summary>
165         public object DefaultValue
166         {
167             get
168             {
169                 if (_defaultValue == _notInitializedSentinel)
170                 {
171                     return null;
172                 }
173                 return _defaultValue;
174             }
175         }
176
177         /// <summary>
178         /// Gets whether the value of this facet must be constant
179         /// </summary>
180         public bool IsConstant
181         {
182             get
183             {
184                 return _isConstant;
185             }
186         }
187
188         /// <summary>
189         /// Gets whether this facet is a required facet or not
190         /// </summary>
191         public bool IsRequired
192         {
193             get
194             {
195                 return _defaultValue == _notInitializedSentinel;
196             }
197         }
198
199         #region Internal properties
200
201         /// <summary>
202         /// Gets a facet with the default value for this description.
203         /// </summary>
204         internal Facet DefaultValueFacet
205         {
206             get
207             {
208                 if (_defaultValueFacet == null)
209                 {
210                     Facet defaultValueFacet = Facet.Create(this, this.DefaultValue, true);
211                     Interlocked.CompareExchange(ref _defaultValueFacet, defaultValueFacet, null);
212                 }
213                 return _defaultValueFacet;
214             }
215         }
216
217         /// <summary>
218         /// Gets a facet with a null value for this description.
219         /// </summary>
220         internal Facet NullValueFacet
221         {
222             get
223             {
224                 if (_nullValueFacet == null)
225                 {
226                     Facet nullValueFacet = Facet.Create(this, null, true);
227                     Interlocked.CompareExchange(ref _nullValueFacet, nullValueFacet, null);
228                 }
229                 return _nullValueFacet;
230             }
231         }
232
233         #endregion Internal properties
234
235         #endregion
236
237         #region Methods
238         /// <summary>
239         /// Overriding System.Object.ToString to provide better String representation 
240         /// for this type.
241         /// </summary>
242         public override string ToString()
243         {
244             return this.FacetName;
245         }
246
247         /// <summary>
248         /// Gets a cached facet instance with the specified boolean value.
249         /// </summary>
250         /// <param name="value">Value for the Facet result.</param>
251         /// <returns>A cached facet instance with the specified boolean value.</returns>
252         internal Facet GetBooleanFacet(bool value)
253         {
254             System.Diagnostics.Debug.Assert(this.FacetType.Identity == "Edm.Boolean");
255             if (_valueCache == null)
256             {
257                 Facet[] valueCache = new Facet[2];
258                 valueCache[0] = Facet.Create(this, true, true);
259                 valueCache[1] = Facet.Create(this, false, true);
260
261                 System.Threading.Interlocked.CompareExchange(
262                                                     ref _valueCache,
263                                                     valueCache,
264                                                     null
265                                                 );
266             }
267             return (value) ? _valueCache[0] : _valueCache[1];
268         }
269
270         /// <summary>
271         /// Returns true if the facet type is of numeric type
272         /// </summary>
273         /// <param name="facetType">Type of the facet</param>
274         /// <returns></returns>
275         internal static bool IsNumericType(EdmType facetType)
276         {
277             if (Helper.IsPrimitiveType(facetType))
278             {
279                 PrimitiveType primitiveType = (PrimitiveType)facetType;
280
281                 return primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.Byte ||
282                        primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.SByte ||
283                        primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.Int16 ||
284                        primitiveType.PrimitiveTypeKind == PrimitiveTypeKind.Int32;
285             }
286
287             return false;
288         }
289
290         private static void UpdateMinMaxValueForConstant(string facetName, EdmType facetType, ref int? minValue, ref int? maxValue, object defaultValue)
291         {
292             if (FacetDescription.IsNumericType(facetType))
293             {
294                 if (facetName == EdmProviderManifest.PrecisionFacetName ||
295                     facetName == EdmProviderManifest.ScaleFacetName)
296                 {
297                     minValue = (int?)((byte?)defaultValue);
298                     maxValue = (int?)((byte?)defaultValue);
299                 }
300                 else
301                 {
302                     minValue = (int?)defaultValue;
303                     maxValue = (int?)defaultValue;
304                 }
305             }
306         }
307
308         private void Validate(string declaringTypeName)
309         {
310             if (_defaultValue == _notInitializedSentinel)
311             {
312                 if (_isConstant)
313                 {
314                     throw EntityUtil.MissingDefaultValueForConstantFacet(_facetName, declaringTypeName);
315                 }
316             }
317             else if (FacetDescription.IsNumericType(_facetType))
318             {
319                 if (_isConstant)
320                 {
321                     // Either both of them are not specified or both of them have the same value
322                     if ((_minValue.HasValue != _maxValue.HasValue) ||
323                         (_minValue.HasValue && _minValue.Value != _maxValue.Value))
324                     {
325                         throw EntityUtil.MinAndMaxValueMustBeSameForConstantFacet(_facetName, declaringTypeName);
326                     }
327                 }
328
329                 // If its not constant, then both of the minValue and maxValue must be specified
330                 else if (!_minValue.HasValue || !_maxValue.HasValue)
331                 {
332                     throw EntityUtil.BothMinAndMaxValueMustBeSpecifiedForNonConstantFacet(_facetName, declaringTypeName);
333                 }
334                 else if (_minValue.Value == _maxValue)
335                 {
336                     throw EntityUtil.MinAndMaxValueMustBeDifferentForNonConstantFacet(_facetName, declaringTypeName);
337                 }
338                 else if (_minValue < 0 || _maxValue < 0)
339                 {
340                     throw EntityUtil.MinAndMaxMustBePositive(_facetName, declaringTypeName);
341                 }
342                 else if (_minValue > _maxValue)
343                 {
344                     throw EntityUtil.MinMustBeLessThanMax(_minValue.ToString(), _facetName, declaringTypeName);
345                 }
346             }
347         }
348
349         #endregion
350     }
351 }