Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Query / PlanCompiler / TypeUtils.cs
1 //---------------------------------------------------------------------
2 // <copyright file="TypeUtils.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.Diagnostics; // Please use PlanCompiler.Assert instead of Debug.Assert in this class...
13
14 // It is fine to use Debug.Assert in cases where you assert an obvious thing that is supposed
15 // to prevent from simple mistakes during development (e.g. method argument validation 
16 // in cases where it was you who created the variables or the variables had already been validated or 
17 // in "else" clauses where due to code changes (e.g. adding a new value to an enum type) the default 
18 // "else" block is chosen why the new condition should be treated separately). This kind of asserts are 
19 // (can be) helpful when developing new code to avoid simple mistakes but have no or little value in 
20 // the shipped product. 
21 // PlanCompiler.Assert *MUST* be used to verify conditions in the trees. These would be assumptions 
22 // about how the tree was built etc. - in these cases we probably want to throw an exception (this is
23 // what PlanCompiler.Assert does when the condition is not met) if either the assumption is not correct 
24 // or the tree was built/rewritten not the way we thought it was.
25 // Use your judgment - if you rather remove an assert than ship it use Debug.Assert otherwise use
26 // PlanCompiler.Assert.
27
28 using System.Globalization;
29
30 using System.Data.Common;
31 using md = System.Data.Metadata.Edm;
32
33 //
34 // This module contains a few utility functions that make it easier to operate
35 // with type metadata
36 //
37
38 namespace System.Data.Query.PlanCompiler
39 {
40     /// <summary>
41     /// This class is used as a Comparer for Types all through the PlanCompiler.
42     /// It has a pretty strict definition of type equality - which pretty much devolves
43     /// to equality of the "Identity" of the Type (not the TypeUsage).
44     /// 
45     /// NOTE: Unlike other parts of the query pipeline, record types follow 
46     /// a much stricter equality condition here - the field names must be the same, and 
47     /// the field types must be equal.
48     /// 
49     /// NOTE: Primitive types are considered equal, if their Identities are equal. This doesn't
50     /// take into account any of the facets that are represented external to the type (size, for instance). 
51     /// Again, this is different from other parts of  the query pipeline; and we're much stricter here
52     /// 
53     /// </summary>
54     sealed internal class TypeUsageEqualityComparer : IEqualityComparer<md.TypeUsage>
55     {
56         private TypeUsageEqualityComparer() { }
57         internal static readonly TypeUsageEqualityComparer Instance = new TypeUsageEqualityComparer();
58
59         #region IEqualityComparer<TypeUsage> Members
60
61         public bool Equals(System.Data.Metadata.Edm.TypeUsage x, System.Data.Metadata.Edm.TypeUsage y)
62         {
63             if (x == null || y == null)
64             {
65                 return false;
66             }
67
68             return TypeUsageEqualityComparer.Equals(x.EdmType, y.EdmType);
69         }
70
71         public int GetHashCode(System.Data.Metadata.Edm.TypeUsage obj)
72         {
73             return obj.EdmType.Identity.GetHashCode();
74         }
75
76         #endregion
77
78         internal static bool Equals(md.EdmType x, md.EdmType y)
79         {
80             return x.Identity.Equals(y.Identity);
81         }
82     }
83
84     internal static class TypeUtils
85     {
86         /// <summary>
87         /// Is this type a UDT? (ie) a structural type supported by the store
88         /// </summary>
89         /// <param name="type">the type in question</param>
90         /// <returns>true, if the type was a UDT</returns>
91         internal static bool IsUdt(md.TypeUsage type)
92         {
93             return IsUdt(type.EdmType);
94         }
95
96         /// <summary>
97         /// Is this type a UDT? (ie) a structural type supported by the store
98         /// </summary>
99         /// <param name="type">the type in question</param>
100         /// <returns>true, if the type was a UDT</returns>
101         internal static bool IsUdt(md.EdmType type)
102         {
103 #if UDT_SUPPORT
104             // Ideally this should be as simple as:
105             // return TypeUsage.HasExtendedAttribute(type, MetadataConstants.UdtAttribute);
106             // The definition below is 'Type is a ComplexType defined in the store'.
107             return (BuiltInTypeKind.ComplexType == type.BuiltInTypeKind &&
108                     TypeHelpers.HasExtendedAttribute(type, MetadataConstants.TargetAttribute));
109 #else
110             return false;
111 #endif
112         }
113
114         /// <summary>
115         /// Is this a structured type? 
116         /// Note: Structured, in this context means structured outside the server. 
117         /// UDTs for instance, are considered to be scalar types - all WinFS types,
118         /// would by this argument, be scalar types.
119         /// </summary>
120         /// <param name="type">The type to check</param>
121         /// <returns>true, if the type is a structured type</returns>
122         internal static bool IsStructuredType(md.TypeUsage type)
123         {
124             return (md.TypeSemantics.IsReferenceType(type) ||
125                     md.TypeSemantics.IsRowType(type) ||
126                     md.TypeSemantics.IsEntityType(type) ||
127                     md.TypeSemantics.IsRelationshipType(type) ||
128                     (md.TypeSemantics.IsComplexType(type) && !IsUdt(type)));
129         }
130
131         /// <summary>
132         /// Is this type a collection type?
133         /// </summary>
134         /// <param name="type">the current type</param>
135         /// <returns>true, if this is a collection type</returns>
136         internal static bool IsCollectionType(md.TypeUsage type)
137         {
138             return md.TypeSemantics.IsCollectionType(type);
139         }
140
141         /// <summary>
142         /// Is this type an enum type?
143         /// </summary>
144         /// <param name="type">the current type</param>
145         /// <returns>true, if this is an enum type</returns>
146         internal static bool IsEnumerationType(md.TypeUsage type)
147         {
148             return md.TypeSemantics.IsEnumerationType(type);
149         }
150
151         /// <summary>
152         /// Create a new collection type based on the supplied element type
153         /// </summary>
154         /// <param name="elementType">element type of the collection</param>
155         /// <returns>the new collection type</returns>
156         internal static md.TypeUsage CreateCollectionType(md.TypeUsage elementType)
157         {
158             return TypeHelpers.CreateCollectionTypeUsage(elementType);
159         }
160     }
161 }