// This file is part of YamlDotNet - A .NET library for YAML. // Copyright (c) Antoine Aubry and contributors // // Permission is hereby granted, free of charge, to any person obtaining a copy of // this software and associated documentation files (the "Software"), to deal in // the Software without restriction, including without limitation the rights to // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies // of the Software, and to permit persons to whom the Software is furnished to do // so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. using System; using System.Collections.Generic; using System.Diagnostics; using System.Text; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Serialization; using static YamlDotNet.Core.HashCode; namespace YamlDotNet.RepresentationModel { /// /// Represents a sequence node in the YAML document. /// [DebuggerDisplay("Count = {children.Count}")] public sealed class YamlSequenceNode : YamlNode, IEnumerable, IYamlConvertible { private readonly IList children = new List(); /// /// Gets the collection of child nodes. /// /// The children. public IList Children { get { return children; } } /// /// Gets or sets the style of the node. /// /// The style. public SequenceStyle Style { get; set; } /// /// Initializes a new instance of the class. /// internal YamlSequenceNode(IParser parser, DocumentLoadingState state) { Load(parser, state); } private void Load(IParser parser, DocumentLoadingState state) { var sequence = parser.Consume(); Load(sequence, state); Style = sequence.Style; var hasUnresolvedAliases = false; while (!parser.TryConsume(out var _)) { var child = ParseNode(parser, state); children.Add(child); hasUnresolvedAliases |= child is YamlAliasNode; } if (hasUnresolvedAliases) { state.AddNodeWithUnresolvedAliases(this); } } /// /// Initializes a new instance of the class. /// public YamlSequenceNode() { } /// /// Initializes a new instance of the class. /// public YamlSequenceNode(params YamlNode[] children) : this((IEnumerable)children) { } /// /// Initializes a new instance of the class. /// public YamlSequenceNode(IEnumerable children) { foreach (var child in children) { this.children.Add(child); } } /// /// Adds the specified child to the collection. /// /// The child. public void Add(YamlNode child) { children.Add(child); } /// /// Adds a scalar node to the collection. /// /// The child. public void Add(string child) { children.Add(new YamlScalarNode(child)); } /// /// Resolves the aliases that could not be resolved when the node was created. /// /// The state of the document. internal override void ResolveAliases(DocumentLoadingState state) { for (var i = 0; i < children.Count; ++i) { if (children[i] is YamlAliasNode) { children[i] = state.GetNode(children[i].Anchor!, children[i].Start, children[i].End); } } } /// /// Saves the current node to the specified emitter. /// /// The emitter where the node is to be saved. /// The state. internal override void Emit(IEmitter emitter, EmitterState state) { emitter.Emit(new SequenceStart(Anchor, Tag, Tag.IsEmpty, Style)); foreach (var node in children) { node.Save(emitter, state); } emitter.Emit(new SequenceEnd()); } /// /// Accepts the specified visitor by calling the appropriate Visit method on it. /// /// /// A . /// public override void Accept(IYamlVisitor visitor) { visitor.Visit(this); } /// public override bool Equals(object? obj) { var other = obj as YamlSequenceNode; var areEqual = other != null && Equals(Tag, other.Tag) && children.Count == other.children.Count; if (!areEqual) { return false; } for (var i = 0; i < children.Count; ++i) { if (!Equals(children[i], other!.children[i])) { return false; } } return true; } /// /// Serves as a hash function for a particular type. /// /// /// A hash code for the current . /// public override int GetHashCode() { var hashCode = 0; foreach (var item in children) { hashCode = CombineHashCodes(hashCode, item); } hashCode = CombineHashCodes(hashCode, Tag); return hashCode; } /// /// Recursively enumerates all the nodes from the document, starting on the current node, /// and throwing /// if is reached. /// internal override IEnumerable SafeAllNodes(RecursionLevel level) { level.Increment(); yield return this; foreach (var child in children) { foreach (var node in child.SafeAllNodes(level)) { yield return node; } } level.Decrement(); } /// /// Gets the type of node. /// public override YamlNodeType NodeType { get { return YamlNodeType.Sequence; } } /// /// Returns a that represents this instance. /// /// /// A that represents this instance. /// internal override string ToString(RecursionLevel level) { if (!level.TryIncrement()) { return MaximumRecursionLevelReachedToStringValue; } var text = new StringBuilder("[ "); foreach (var child in children) { if (text.Length > 2) { text.Append(", "); } text.Append(child.ToString(level)); } text.Append(" ]"); level.Decrement(); return text.ToString(); } #region IEnumerable Members /// public IEnumerator GetEnumerator() { return Children.GetEnumerator(); } #endregion #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion void IYamlConvertible.Read(IParser parser, Type expectedType, ObjectDeserializer nestedObjectDeserializer) { Load(parser, new DocumentLoadingState()); } void IYamlConvertible.Write(IEmitter emitter, ObjectSerializer nestedObjectSerializer) { Emit(emitter, new EmitterState()); } } }