| File: Language\TypeNameObject.cs | Web Access |
| Project: src\roslyn\src\Razor\src\Compiler\Microsoft.CodeAnalysis.Razor.Compiler\src\Microsoft.CodeAnalysis.Razor.Compiler.csproj (Microsoft.CodeAnalysis.Razor.Compiler) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Frozen; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using Microsoft.AspNetCore.Razor.Utilities; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.Razor; namespace Microsoft.AspNetCore.Razor.Language; internal readonly struct TypeNameObject { private readonly struct TypeNameInfo(string fullName, string? @namespace, string? name, string? alias) { public string FullName { get; } = fullName; public string? Namespace { get; } = @namespace; public string? Name { get; } = name; public string? Alias { get; } = alias; } private static readonly ImmutableArray<TypeNameInfo> s_knownTypeNames; private static readonly FrozenDictionary<string, byte> s_typeNameToIndex; private static readonly int s_booleanIndex; private static readonly int s_stringIndex; static TypeNameObject() { var knownTypeNames = ImmutableArray.CreateBuilder<TypeNameInfo>(); var typeNameToIndex = new Dictionary<string, byte>(StringComparer.Ordinal); Add<object>("object"); s_booleanIndex = Add<bool>("bool"); Add<int>("int"); Add<long>("long"); Add<short>("short"); Add<byte>("byte"); Add<sbyte>("sbyte"); Add<uint>("uint"); Add<ulong>("ulong"); Add<ushort>("ushort"); Add<float>("float"); Add<double>("double"); Add<decimal>("decimal"); Add<char>("char"); s_stringIndex = Add<string>("string"); Add<System.Globalization.CultureInfo>(); Add<Delegate>(); Add<Type>(); // Add any additional types here. s_knownTypeNames = knownTypeNames.ToImmutable(); s_typeNameToIndex = typeNameToIndex.ToFrozenDictionary(StringComparer.Ordinal); int Add<T>(string? alias = null) { Debug.Assert(knownTypeNames.Count < byte.MaxValue, "Too many known type names to fit in a byte index."); var fullName = typeof(T).FullName!; var @namespace = typeof(T).Namespace; var name = typeof(T).Name; var index = (byte)knownTypeNames.Count; knownTypeNames.Add(new(fullName, @namespace, name, alias)); typeNameToIndex.Add(fullName, index); if (alias is not null) { typeNameToIndex.Add(alias, index); } return index; } } private readonly byte? _index; private readonly TypeNameInfo? _info; public TypeNameObject(byte index) { Debug.Assert(index >= 0 && index < s_knownTypeNames.Length); _index = index; _info = null; } public TypeNameObject(string? stringValue) { Debug.Assert(stringValue is null || !s_typeNameToIndex.ContainsKey(stringValue)); _index = null; _info = new(stringValue!, @namespace: null, name: null, alias: null); } private TypeNameObject(TypeNameInfo info, byte? index) { _index = index; _info = info; } public bool IsNull => _index is null && _info is null; public byte? Index => _index; public static TypeNameObject From(string? fullName) { if (fullName is null) { return default; } return From(fullName, namespaceName: null, name: null); } public static TypeNameObject From(string fullName, string? namespaceName, string? name) { if (s_typeNameToIndex.TryGetValue(fullName, out var index)) { var info = s_knownTypeNames[index]; return new(info, index); } return new(new(fullName, namespaceName, name, alias: null), index: null); } public static TypeNameObject From<T>() => From(typeof(T)); public static TypeNameObject From(Type type) { var fullName = type.FullName!; if (s_typeNameToIndex.TryGetValue(fullName, out var index)) { var info = s_knownTypeNames[index]; return new(info, index); } var @namespace = type.Namespace; var name = type.Name; return new(new(fullName, @namespace, name, alias: null), index: null); } public static TypeNameObject From(INamedTypeSymbol namedTypeSymbol) { var fullName = namedTypeSymbol.GetFullName(); if (s_typeNameToIndex.TryGetValue(fullName, out var index)) { var info = s_knownTypeNames[index]; return new(info, index); } var @namespace = namedTypeSymbol.ContainingNamespace.GetFullName(); var name = namedTypeSymbol.Name; return new(new(fullName, @namespace, name, alias: null), index: null); } public bool IsBoolean => _index == s_booleanIndex; public bool IsString => _index == s_stringIndex; public readonly string? FullName { get { if (_info is { FullName: var fullName }) { return fullName; } if (_index is byte index) { return s_knownTypeNames[index].FullName; } return null; } } public readonly string? Namespace { get { if (_info is { Namespace: var @namespace }) { return @namespace; } if (_index is byte index) { return s_knownTypeNames[index].Namespace; } return null; } } public readonly string? Name { get { if (_info is { Name: var name }) { return name; } if (_index is byte index) { return s_knownTypeNames[index].Name; } return null; } } public void AppendToChecksum(in Checksum.Builder builder) { if (_index is byte index) { builder.Append(index); } else if (_info is TypeNameInfo info) { builder.Append(info.FullName); builder.Append(info.Namespace); builder.Append(info.Name); } else { builder.AppendNull(); } } }