/********* ** Public methods *********/ /// <summary>Construct an instance.</summary> /// <param name="provider">The underlying value provider.</param> public GenericToken(IValueProvider provider) { this.Values = provider; this.Name = TokenName.Parse(provider.Name); this.CanHaveMultipleRootValues = provider.CanHaveMultipleValues(); }
/********* ** Public methods *********/ /// <summary>Construct an instance.</summary> /// <param name="name">The token name.</param> /// <param name="values">Get the current token values.</param> /// <param name="allowedValues">The allowed values (or <c>null</c> if any value is allowed).</param> /// <param name="canHaveMultipleValues">Whether the token may contain multiple values (or <c>null</c> to set it based on the given values).</param> public ImmutableToken(TokenName name, InvariantHashSet values, InvariantHashSet allowedValues = null, bool?canHaveMultipleValues = null) : base(name, canHaveMultipleRootValues: false) { this.Values = values ?? new InvariantHashSet(); this.AllowedRootValues = allowedValues; this.CanHaveMultipleRootValues = canHaveMultipleValues ?? (this.Values.Count > 1 || this.AllowedRootValues == null || this.AllowedRootValues.Count > 1); this.EnableSubkeys(required: false, canHaveMultipleValues: false); this.IsValidInContext = true; }
/// <summary>Get the current token values.</summary> /// <param name="name">The token name to check, if applicable.</param> /// <exception cref="InvalidOperationException">The key doesn't match this token, or this token require a subkeys and <paramref name="name"/> does not specify one.</exception> public override IEnumerable <string> GetValues(TokenName name) { this.AssertTokenName(name); if (this.Values.TryGetValue(name.Subkey, out string value)) { yield return(value); } }
/********* ** Public methods *********/ /// <summary>Construct an instance.</summary> /// <param name="provider">The underlying value provider.</param> public GenericToken(IValueProvider provider) { this.Values = provider; this.Name = TokenName.Parse(provider.Name); this.CanHaveSubkeys = provider.AllowsInput; this.RequiresSubkeys = provider.RequiresInput; this.CanHaveMultipleRootValues = provider.CanHaveMultipleValues(); this.IsValidInContext = provider.IsValidInContext; }
/// <summary>Get the allowed values for a token name (or <c>null</c> if any value is allowed).</summary> /// <exception cref="InvalidOperationException">The key doesn't match this token, or the key does not respect <see cref="IToken.CanHaveSubkeys"/> or <see cref="IToken.RequiresSubkeys"/>.</exception> public override InvariantHashSet GetAllowedValues(TokenName name) { if (name.HasSubkey()) { return new InvariantHashSet { true.ToString(), false.ToString() } } ; return(this.AllowedRootValues); }
/// <summary>Get the current token values.</summary> /// <param name="name">The token name to check.</param> /// <exception cref="InvalidOperationException">The key doesn't match this token, or the key does not respect <see cref="IToken.CanHaveSubkeys"/> or <see cref="IToken.RequiresSubkeys"/>.</exception> public override IEnumerable <string> GetValues(TokenName name) { this.AssertTokenName(name); if (name.HasSubkey()) { return new[] { this.Values.Contains(name.Subkey).ToString() } } ; return(this.Values); } }
/// <summary>Get the current token values.</summary> /// <param name="name">The token name to check.</param> /// <exception cref="InvalidOperationException">The key doesn't match this token, or the key does not respect <see cref="IToken.CanHaveSubkeys"/> or <see cref="IToken.RequiresSubkeys"/>.</exception> public override IEnumerable <string> GetValues(TokenName name) { this.AssertTokenName(name); if (name.HasSubkey()) { bool hasProfession = this.TryParseEnum(name.Subkey, out Profession profession, mustBeNamed: false) && this.Professions.Contains(profession); yield return(hasProfession.ToString()); } else { foreach (Profession profession in this.Professions) { yield return(profession.ToString()); } } }
/// <summary>Get the current token values.</summary> /// <param name="name">The token name to check.</param> /// <exception cref="InvalidOperationException">The key doesn't match this token, or the key does not respect <see cref="IToken.CanHaveSubkeys"/> or <see cref="IToken.RequiresSubkeys"/>.</exception> public override IEnumerable <string> GetValues(TokenName name) { this.AssertTokenName(name); if (name.HasSubkey()) { if (this.Values.TryGetValue(name.Subkey, out string value)) { yield return(value); } } else { foreach (var pair in this.Values) { yield return($"{pair.Key}:{pair.Value}"); } } }
/// <summary>Perform custom validation on a subkey/value pair.</summary> /// <param name="name">The token name to validate.</param> /// <param name="value">The value to validate.</param> /// <param name="error">The validation error, if any.</param> /// <returns>Returns whether validation succeeded.</returns> public override bool TryValidate(TokenName name, string value, out string error) { if (!base.TryValidate(name, value, out error)) { return(false); } // validate profession IDs string profession = name.HasSubkey() ? name.Subkey : value; if (!this.TryParseEnum(profession, out Profession _, mustBeNamed: false)) { error = $"can't parse '{profession}' as a profession ID; must be one of [{string.Join(", ", Enum.GetNames(typeof(Profession)).OrderByIgnoreCase(p => p))}] or an integer ID."; return(false); } error = null; return(true); }
/// <summary>Get the current token values.</summary> /// <param name="name">The token name to check.</param> /// <exception cref="InvalidOperationException">The key doesn't match this token, or the key does not respect <see cref="IToken.CanHaveSubkeys"/> or <see cref="IToken.RequiresSubkeys"/>.</exception> public override IEnumerable <string> GetValues(TokenName name) { this.AssertTokenName(name); if (name.HasSubkey()) { if (this.TryParseEnum(name.Subkey, out Skill skill) && this.SkillLevels.TryGetValue(skill, out int level)) { yield return(level.ToString()); } } else { foreach (var pair in this.SkillLevels) { yield return($"{pair.Key}:{pair.Value}"); } } }
/// <summary>Get the current token values.</summary> /// <param name="name">The token name to check.</param> /// <exception cref="InvalidOperationException">The key doesn't match this token, or the key does not respect <see cref="IToken.CanHaveSubkeys"/> or <see cref="IToken.RequiresSubkeys"/>.</exception> public override IEnumerable <string> GetValues(TokenName name) { this.AssertTokenName(name); if (name.HasSubkey()) { bool hasItem = this.TryParseEnum(name.Subkey, out WalletItem item) && this.WalletItems[item](); yield return(hasItem.ToString()); } else { foreach (KeyValuePair <WalletItem, Func <bool> > pair in this.WalletItems) { if (pair.Value()) { yield return(pair.Key.ToString()); } } } }
/// <summary>Perform custom validation on a subkey/value pair.</summary> /// <param name="name">The token name to validate.</param> /// <param name="value">The value to validate.</param> /// <param name="error">The validation error, if any.</param> /// <returns>Returns whether validation succeeded.</returns> public virtual bool TryValidate(TokenName name, string value, out string error) { error = null; return(true); }
/// <summary>Get the allowed values for a token name (or <c>null</c> if any value is allowed).</summary> /// <exception cref="InvalidOperationException">The key doesn't match this token, or the key does not respect <see cref="IToken.CanHaveSubkeys"/> or <see cref="IToken.RequiresSubkeys"/>.</exception> public virtual InvariantHashSet GetAllowedValues(TokenName name) { return(this.Values.GetAllowedValues(name.Subkey)); }
/// <summary>Construct an instance.</summary> /// <param name="name">The token name.</param> /// <param name="canHaveMultipleValues">Whether the token may contain multiple values (or <c>null</c> to set it based on the given values).</param> /// <param name="allowedValues">The allowed values (or <c>null</c> if any value is allowed).</param> /// <param name="values">Get the current token values.</param> public ImmutableToken(string name, InvariantHashSet values, InvariantHashSet allowedValues = null, bool?canHaveMultipleValues = null) : this(TokenName.Parse(name), values, allowedValues, canHaveMultipleValues) { }
/// <summary>Get the current token values.</summary> /// <param name="name">The token name to check.</param> /// <exception cref="InvalidOperationException">The key doesn't match this token, or the key does not respect <see cref="IToken.CanHaveSubkeys"/> or <see cref="IToken.RequiresSubkeys"/>.</exception> public virtual IEnumerable <string> GetValues(TokenName name) { this.AssertTokenName(name); return(this.Values.GetValues(name.Subkey)); }
/// <summary>Whether the token may return multiple values for the given name.</summary> /// <param name="name">The token name.</param> public bool CanHaveMultipleValues(TokenName name) { return(this.Values.CanHaveMultipleValues(name.Subkey)); }
/// <summary>Get the allowed values for a token name (or <c>null</c> if any value is allowed).</summary> /// <exception cref="InvalidOperationException">The key doesn't match this token, or the key does not respect <see cref="IToken.CanHaveSubkeys"/> or <see cref="IToken.RequiresSubkeys"/>.</exception> public override InvariantHashSet GetAllowedValues(TokenName name) { return(name.HasSubkey() ? InvariantHashSet.Boolean() : this.AllowedRootValues); }
/// <summary>Whether the token may return multiple values for the given name.</summary> /// <param name="name">The token name.</param> public bool CanHaveMultipleValues(TokenName name) { return(name.HasSubkey() ? this.CanHaveMultipleSubkeyValues : this.CanHaveMultipleRootValues); }
/// <summary>Construct an instance.</summary> /// <param name="name">The token name.</param> /// <param name="canHaveMultipleRootValues">Whether the root token may contain multiple values.</param> protected BaseToken(string name, bool canHaveMultipleRootValues) : this(TokenName.Parse(name), canHaveMultipleRootValues) { }
/********* ** Public methods *********/ /// <summary>Construct an instance.</summary> /// <param name="key">The name of the token whose value to set.</param> /// <param name="value">The token value to set.</param> /// <param name="conditions">The conditions that must match to set this value.</param> public DynamicTokenValue(TokenName key, InvariantHashSet value, ConditionDictionary conditions) { this.Name = key; this.Value = value; this.Conditions = conditions; }
/// <summary>Get the current token values.</summary> /// <param name="name">The token name to check.</param> /// <exception cref="InvalidOperationException">The key doesn't match this token, or the key does not respect <see cref="IToken.CanHaveSubkeys"/> or <see cref="IToken.RequiresSubkeys"/>.</exception> public override IEnumerable <string> GetValues(TokenName name) { this.AssertTokenName(name); yield return(this.GetPathExists(name.Subkey).ToString()); }
/********* ** Public methods *********/ /// <summary>Construct an instance.</summary> /// <param name="name">The token name.</param> public DynamicToken(TokenName name) : base(new DynamicTokenValueProvider(name.Key)) { this.DynamicValues = (DynamicTokenValueProvider)base.Values; }
/// <summary>Perform custom validation.</summary> /// <param name="name">The token name to validate.</param> /// <param name="values">The values to validate.</param> /// <param name="error">The validation error, if any.</param> /// <returns>Returns whether validation succeeded.</returns> public bool TryValidate(TokenName name, InvariantHashSet values, out string error) { // parse data KeyValuePair <TokenName, string>[] pairs = this.GetSubkeyValuePairsFor(name, values).ToArray(); // restrict to allowed subkeys if (this.CanHaveSubkeys) { InvariantHashSet validKeys = this.GetAllowedSubkeys(); if (validKeys != null) { string[] invalidSubkeys = ( from pair in pairs where pair.Key.Subkey != null && !validKeys.Contains(pair.Key.Subkey) select pair.Key.Subkey ) .Distinct() .ToArray(); if (invalidSubkeys.Any()) { error = $"invalid subkeys ({string.Join(", ", invalidSubkeys)}); expected one of {string.Join(", ", validKeys)}"; return(false); } } } // restrict to allowed values { InvariantHashSet validValues = this.GetAllowedValues(name); if (validValues?.Any() == true) { string[] invalidValues = ( from pair in pairs where !validValues.Contains(pair.Value) select pair.Value ) .Distinct() .ToArray(); if (invalidValues.Any()) { error = $"invalid values ({string.Join(", ", invalidValues)}); expected one of {string.Join(", ", validValues)}"; return(false); } } } // custom validation foreach (KeyValuePair <TokenName, string> pair in pairs) { if (!this.Values.TryValidate(pair.Key.Subkey, new InvariantHashSet { pair.Value }, out error)) { return(false); } } // no issues found error = null; return(true); }
/// <summary>Get the allowed values for a token name (or <c>null</c> if any value is allowed).</summary> /// <exception cref="InvalidOperationException">The key doesn't match this token, or the key does not respect <see cref="IToken.CanHaveSubkeys"/> or <see cref="IToken.RequiresSubkeys"/>.</exception> public virtual InvariantHashSet GetAllowedValues(TokenName name) { return(null); }
/********* ** Public methods *********/ /// <summary>Construct an instance.</summary> /// <param name="name">The token name.</param> public DynamicToken(TokenName name) : base(name, canHaveMultipleRootValues: false) { this.AllowedRootValues = new InvariantHashSet(); this.EnableSubkeys(required: false, canHaveMultipleValues: false); }
/// <summary>Get the current token values.</summary> /// <param name="name">The token name to check.</param> /// <exception cref="InvalidOperationException">The key doesn't match this token, or the key does not respect <see cref="IToken.CanHaveSubkeys"/> or <see cref="IToken.RequiresSubkeys"/>.</exception> public virtual IEnumerable <string> GetValues(TokenName name) { this.AssertTokenName(name); yield break; }
/********* ** Protected methods *********/ /// <summary>Construct an instance.</summary> /// <param name="name">The token name.</param> /// <param name="canHaveMultipleRootValues">Whether the root token may contain multiple values.</param> protected BaseToken(TokenName name, bool canHaveMultipleRootValues) { this.Name = name; this.CanHaveMultipleRootValues = canHaveMultipleRootValues; }
/// <summary>Get the subkey/value pairs used in the given name and values.</summary> /// <param name="name">The token name to validate.</param> /// <param name="values">The values to validate.</param> /// <returns>Returns the subkey/value pairs found. If the <paramref name="name"/> includes a subkey, the <paramref name="values"/> are treated as values of that subkey. Otherwise if <see cref="CanHaveSubkeys"/> is true, then each value is treated as <c>subkey:value</c> (if they contain a colon) or <c>value</c> (with a null subkey).</returns> protected IEnumerable <KeyValuePair <TokenName, string> > GetSubkeyValuePairsFor(TokenName name, InvariantHashSet values) { // no subkeys in values if (!this.CanHaveSubkeys || name.HasSubkey()) { foreach (string value in values) { yield return(new KeyValuePair <TokenName, string>(name, value)); } } // possible subkeys in values else { foreach (string value in values) { string[] parts = value.Split(new[] { ':' }, 2); if (parts.Length < 2) { yield return(new KeyValuePair <TokenName, string>(name, parts[0])); } else { yield return(new KeyValuePair <TokenName, string>(new TokenName(name.Key, parts[0]), parts[1])); } } } }