Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
SubsystemInfo.cs362 linesDownload Raw Back to Subsystem
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4#nullable enable5 6using System;7using System.Collections.Generic;8using System.Collections.ObjectModel;9using System.Management.Automation.Internal;10using Microsoft.PowerShell.Telemetry;11 12namespace System.Management.Automation.Subsystem13{14    /// <summary>15    /// Class used to represent the metadata and state of a subsystem.16    /// </summary>17    public abstract class SubsystemInfo18    {19        #region "Metadata of a Subsystem (public)"20 21        /// <summary>22        /// Gets the kind of a concrete subsystem.23        /// </summary>24        public SubsystemKind Kind { get; }25 26        /// <summary>27        /// Gets the type of a concrete subsystem.28        /// </summary>29        public Type SubsystemType { get; }30 31        /// <summary>32        /// Gets a value indicating whether the subsystem allows to unregister an implementation.33        /// </summary>34        public bool AllowUnregistration { get; private set; }35 36        /// <summary>37        /// Gets a value indicating whether the subsystem allows to have multiple implementations registered.38        /// </summary>39        public bool AllowMultipleRegistration { get; private set; }40 41        /// <summary>42        /// Gets the names of the required cmdlets that have to be implemented by the subsystem implementation.43        /// </summary>44        public ReadOnlyCollection<string> RequiredCmdlets { get; private set; }45 46        /// <summary>47        /// Gets the names of the required functions that have to be implemented by the subsystem implementation.48        /// </summary>49        public ReadOnlyCollection<string> RequiredFunctions { get; private set; }50 51        // /// <summary>52        // /// A subsystem may depend on or more other subsystems.53        // /// Maybe add a 'DependsOn' member?54        // /// This can be validated when registering a subsystem implementation,55        // /// to make sure its prerequisites have already been registered.56        // /// </summary>57        // public ReadOnlyCollection<SubsystemKind> DependsOn { get; private set; }58 59        #endregion60 61        #region "State of a Subsystem (public)"62 63        /// <summary>64        /// Indicate whether there is any implementation registered to the subsystem.65        /// </summary>66        public bool IsRegistered => _cachedImplInfos.Count > 0;67 68        /// <summary>69        /// Get the information about the registered implementations.70        /// </summary>71        public ReadOnlyCollection<ImplementationInfo> Implementations => _cachedImplInfos;72 73        #endregion74 75        #region "private/internal instance members"76 77        private protected readonly object _syncObj;78        private protected ReadOnlyCollection<ImplementationInfo> _cachedImplInfos;79 80        private protected SubsystemInfo(SubsystemKind kind, Type subsystemType)81        {82            _syncObj = new object();83            _cachedImplInfos = Utils.EmptyReadOnlyCollection<ImplementationInfo>();84 85            Kind = kind;86            SubsystemType = subsystemType;87            AllowUnregistration = false;88            AllowMultipleRegistration = false;89            RequiredCmdlets = Utils.EmptyReadOnlyCollection<string>();90            RequiredFunctions = Utils.EmptyReadOnlyCollection<string>();91        }92 93        private protected abstract void AddImplementation(ISubsystem rawImpl);94 95        private protected abstract ISubsystem RemoveImplementation(Guid id);96 97        internal void RegisterImplementation(ISubsystem impl)98        {99            AddImplementation(impl);100            ApplicationInsightsTelemetry.SendUseTelemetry(ApplicationInsightsTelemetry.s_subsystemRegistration, impl.Name);101        }102 103        internal ISubsystem UnregisterImplementation(Guid id)104        {105            return RemoveImplementation(id);106        }107 108        #endregion109 110        #region "Static factory overloads"111 112        internal static SubsystemInfo Create<TConcreteSubsystem>(SubsystemKind kind)113            where TConcreteSubsystem : class, ISubsystem114        {115            return new SubsystemInfoImpl<TConcreteSubsystem>(kind);116        }117 118        internal static SubsystemInfo Create<TConcreteSubsystem>(119            SubsystemKind kind,120            bool allowUnregistration,121            bool allowMultipleRegistration) where TConcreteSubsystem : class, ISubsystem122        {123            return new SubsystemInfoImpl<TConcreteSubsystem>(kind)124            {125                AllowUnregistration = allowUnregistration,126                AllowMultipleRegistration = allowMultipleRegistration,127            };128        }129 130        internal static SubsystemInfo Create<TConcreteSubsystem>(131            SubsystemKind kind,132            bool allowUnregistration,133            bool allowMultipleRegistration,134            ReadOnlyCollection<string> requiredCmdlets,135            ReadOnlyCollection<string> requiredFunctions) where TConcreteSubsystem : class, ISubsystem136        {137            if (allowMultipleRegistration &&138                (requiredCmdlets.Count > 0 || requiredFunctions.Count > 0))139            {140                throw new ArgumentException(141                    StringUtil.Format(142                        SubsystemStrings.InvalidSubsystemInfo,143                        kind.ToString()));144            }145 146            return new SubsystemInfoImpl<TConcreteSubsystem>(kind)147            {148                AllowUnregistration = allowUnregistration,149                AllowMultipleRegistration = allowMultipleRegistration,150                RequiredCmdlets = requiredCmdlets,151                RequiredFunctions = requiredFunctions,152            };153        }154 155        #endregion156 157        #region "ImplementationInfo"158 159        /// <summary>160        /// Information about an implementation of a subsystem.161        /// </summary>162        public class ImplementationInfo163        {164            internal ImplementationInfo(SubsystemKind kind, ISubsystem implementation)165            {166                Id = implementation.Id;167                Kind = kind;168                Name = implementation.Name;169                Description = implementation.Description;170                ImplementationType = implementation.GetType();171            }172 173            /// <summary>174            /// Gets the unique identifier for a subsystem implementation.175            /// </summary>176            public Guid Id { get; }177 178            /// <summary>179            /// Gets the kind of subsystem.180            /// </summary>181            public SubsystemKind Kind { get; }182 183            /// <summary>184            /// Gets the name of a subsystem implementation.185            /// </summary>186            public string Name { get; }187 188            /// <summary>189            /// Gets the description of a subsystem implementation.190            /// </summary>191            public string Description { get; }192 193            /// <summary>194            /// Gets the implementation type.195            /// </summary>196            public Type ImplementationType { get; }197        }198 199        #endregion200    }201 202    internal sealed class SubsystemInfoImpl<TConcreteSubsystem> : SubsystemInfo203        where TConcreteSubsystem : class, ISubsystem204    {205        private ReadOnlyCollection<TConcreteSubsystem> _registeredImpls;206 207        internal SubsystemInfoImpl(SubsystemKind kind)208            : base(kind, typeof(TConcreteSubsystem))209        {210            _registeredImpls = Utils.EmptyReadOnlyCollection<TConcreteSubsystem>();211        }212 213        /// <summary>214        /// The 'add' and 'remove' operations are implemented in a way to optimize the 'reading' operation,215        /// so that reading is lock-free and allocation-free, at the cost of O(n) copy in 'add' and 'remove'216        /// ('n' is the number of registered implementations).217        /// </summary>218        /// <remarks>219        /// In the subsystem scenario, registration operations will be minimum, and in most cases, the registered220        /// implementation will never be unregistered, so optimization for reading is more important.221        /// </remarks>222        /// <param name="rawImpl">The subsystem implementation to be added.</param>223        private protected override void AddImplementation(ISubsystem rawImpl)224        {225            lock (_syncObj)226            {227                var impl = (TConcreteSubsystem)rawImpl;228 229                if (_registeredImpls.Count == 0)230                {231                    _registeredImpls = new ReadOnlyCollection<TConcreteSubsystem>(new[] { impl });232                    _cachedImplInfos = new ReadOnlyCollection<ImplementationInfo>(new[] { new ImplementationInfo(Kind, impl) });233                    return;234                }235 236                if (!AllowMultipleRegistration)237                {238                    throw new InvalidOperationException(239                        StringUtil.Format(240                            SubsystemStrings.MultipleRegistrationNotAllowed,241                            Kind.ToString()));242                }243 244                foreach (TConcreteSubsystem item in _registeredImpls)245                {246                    if (item.Id == impl.Id)247                    {248                        throw new InvalidOperationException(249                            StringUtil.Format(250                                SubsystemStrings.ImplementationAlreadyRegistered,251                                impl.Id,252                                Kind.ToString()));253                    }254                }255 256                int newCapacity = _registeredImpls.Count + 1;257                var implList = new List<TConcreteSubsystem>(newCapacity);258                implList.AddRange(_registeredImpls);259                implList.Add(impl);260 261                var implInfo = new List<ImplementationInfo>(newCapacity);262                implInfo.AddRange(_cachedImplInfos);263                implInfo.Add(new ImplementationInfo(Kind, impl));264 265                _registeredImpls = new ReadOnlyCollection<TConcreteSubsystem>(implList);266                _cachedImplInfos = new ReadOnlyCollection<ImplementationInfo>(implInfo);267            }268        }269 270        /// <summary>271        /// The 'add' and 'remove' operations are implemented in a way to optimize the 'reading' operation,272        /// so that reading is lock-free and allocation-free, at the cost of O(n) copy in 'add' and 'remove'273        /// ('n' is the number of registered implementations).274        /// </summary>275        /// <remarks>276        /// In the subsystem scenario, registration operations will be minimum, and in most cases, the registered277        /// implementation will never be unregistered, so optimization for reading is more important.278        /// </remarks>279        /// <param name="id">The id of the subsystem implementation to be removed.</param>280        /// <returns>The subsystem implementation that was removed.</returns>281        private protected override ISubsystem RemoveImplementation(Guid id)282        {283            if (!AllowUnregistration)284            {285                throw new InvalidOperationException(286                    StringUtil.Format(287                        SubsystemStrings.UnregistrationNotAllowed,288                        Kind.ToString()));289            }290 291            lock (_syncObj)292            {293                if (_registeredImpls.Count == 0)294                {295                    throw new InvalidOperationException(296                        StringUtil.Format(297                            SubsystemStrings.NoImplementationRegistered,298                            Kind.ToString()));299                }300 301                int index = -1;302                for (int i = 0; i < _registeredImpls.Count; i++)303                {304                    if (_registeredImpls[i].Id == id)305                    {306                        index = i;307                        break;308                    }309                }310 311                if (index == -1)312                {313                    throw new InvalidOperationException(314                        StringUtil.Format(315                            SubsystemStrings.ImplementationNotFound,316                            id.ToString()));317                }318 319                ISubsystem target = _registeredImpls[index];320                if (_registeredImpls.Count == 1)321                {322                    _registeredImpls = Utils.EmptyReadOnlyCollection<TConcreteSubsystem>();323                    _cachedImplInfos = Utils.EmptyReadOnlyCollection<ImplementationInfo>();324                }325                else326                {327                    int newCapacity = _registeredImpls.Count - 1;328                    var implList = new List<TConcreteSubsystem>(newCapacity);329                    var implInfo = new List<ImplementationInfo>(newCapacity);330 331                    for (int i = 0; i < _registeredImpls.Count; i++)332                    {333                        if (index == i)334                        {335                            continue;336                        }337 338                        implList.Add(_registeredImpls[i]);339                        implInfo.Add(_cachedImplInfos[i]);340                    }341 342                    _registeredImpls = new ReadOnlyCollection<TConcreteSubsystem>(implList);343                    _cachedImplInfos = new ReadOnlyCollection<ImplementationInfo>(implInfo);344                }345 346                return target;347            }348        }349 350        internal TConcreteSubsystem? GetImplementation()351        {352            var localRef = _registeredImpls;353            return localRef.Count > 0 ? localRef[localRef.Count - 1] : null;354        }355 356        internal ReadOnlyCollection<TConcreteSubsystem> GetAllImplementations()357        {358            return _registeredImpls;359        }360    }361}362