diff --git a/YamlDotNet.Test/RepresentationModel/YamlStreamTests.cs b/YamlDotNet.Test/RepresentationModel/YamlStreamTests.cs index d1475c5f..3e9b4406 100644 --- a/YamlDotNet.Test/RepresentationModel/YamlStreamTests.cs +++ b/YamlDotNet.Test/RepresentationModel/YamlStreamTests.cs @@ -24,6 +24,7 @@ using System.IO; using System.Linq; using System.Text; +using System.Threading.Tasks; using FluentAssertions; using Xunit; using YamlDotNet.Core; @@ -402,6 +403,19 @@ public void Emit(ParsingEvent @event) Assert.False(scalar.IsQuotedImplicit); } + + public Task EmitAsync(ParsingEvent @event) + { + try + { + Emit(@event); + return Task.CompletedTask; + } + catch (Exception ex) + { + return Task.FromException(ex); + } + } } } } diff --git a/YamlDotNet/Core/Emitter.cs b/YamlDotNet/Core/Emitter.cs index 58a692fd..6b1dc5bb 100644 --- a/YamlDotNet/Core/Emitter.cs +++ b/YamlDotNet/Core/Emitter.cs @@ -23,8 +23,10 @@ using System.Collections.Generic; using System.Globalization; using System.IO; +using System.Linq; using System.Text; using System.Text.RegularExpressions; +using System.Threading.Tasks; using YamlDotNet.Core.Events; using YamlDotNet.Helpers; using ParsingEvent = YamlDotNet.Core.Events.ParsingEvent; @@ -168,7 +170,35 @@ public void Emit(ParsingEvent @event) { AnalyzeEvent(current); - StateMachine(current); + foreach (var val in StateMachine(current)) + { + output.Write(val); + } + } + finally + { + // Only dequeue after calling state_machine because it checks how many events are in the queue. + // Todo: well, move into StateMachine() then + events.Dequeue(); + } + } + } + + public async Task EmitAsync(ParsingEvent @event) + { + events.Enqueue(@event); + + while (!NeedMoreEvents()) + { + var current = events.Peek(); + try + { + + AnalyzeEvent(current); + foreach (var val in StateMachine(current)) + { + await output.WriteAsync(val); + } } finally { @@ -558,83 +588,65 @@ private void AnalyzeTag(TagName tag) } } - private void StateMachine(ParsingEvent evt) + private IEnumerable StateMachine(ParsingEvent evt) { if (evt is Comment comment) { - EmitComment(comment); - return; + return EmitComment(comment); } switch (state) { case EmitterState.StreamStart: - EmitStreamStart(evt); - break; + return EmitStreamStart(evt); case EmitterState.FirstDocumentStart: - EmitDocumentStart(evt, true); - break; + return EmitDocumentStart(evt, true); case EmitterState.DocumentStart: - EmitDocumentStart(evt, false); - break; + return EmitDocumentStart(evt, false); case EmitterState.DocumentContent: - EmitDocumentContent(evt); - break; + return EmitDocumentContent(evt); case EmitterState.DocumentEnd: - EmitDocumentEnd(evt); - break; + return EmitDocumentEnd(evt); case EmitterState.FlowSequenceFirstItem: - EmitFlowSequenceItem(evt, true); - break; + return EmitFlowSequenceItem(evt, true); case EmitterState.FlowSequenceItem: - EmitFlowSequenceItem(evt, false); - break; + return EmitFlowSequenceItem(evt, false); case EmitterState.FlowMappingFirstKey: - EmitFlowMappingKey(evt, true); - break; + return EmitFlowMappingKey(evt, true); case EmitterState.FlowMappingKey: - EmitFlowMappingKey(evt, false); - break; + return EmitFlowMappingKey(evt, false); case EmitterState.FlowMappingSimpleValue: - EmitFlowMappingValue(evt, true); - break; + return EmitFlowMappingValue(evt, true); case EmitterState.FlowMappingValue: - EmitFlowMappingValue(evt, false); - break; + return EmitFlowMappingValue(evt, false); case EmitterState.BlockSequenceFirstItem: - EmitBlockSequenceItem(evt, true); - break; + return EmitBlockSequenceItem(evt, true); case EmitterState.BlockSequenceItem: - EmitBlockSequenceItem(evt, false); - break; + return EmitBlockSequenceItem(evt, false); case EmitterState.BlockMappingFirstKey: - EmitBlockMappingKey(evt, true); - break; + return EmitBlockMappingKey(evt, true); case EmitterState.BlockMappingKey: - EmitBlockMappingKey(evt, false); - break; + return EmitBlockMappingKey(evt, false); case EmitterState.BlockMappingSimpleValue: - EmitBlockMappingValue(evt, true); - break; + return EmitBlockMappingValue(evt, true); case EmitterState.BlockMappingValue: - EmitBlockMappingValue(evt, false); - break; + return EmitBlockMappingValue(evt, false); case EmitterState.StreamEnd: throw new YamlException("Expected nothing after STREAM-END"); @@ -644,20 +656,26 @@ private void StateMachine(ParsingEvent evt) } } - private void EmitComment(Comment comment) + private IEnumerable EmitComment(Comment comment) { // If we're in flow mode or about to enter it: Skip comments. if (flowLevel > 0 || state == EmitterState.FlowMappingFirstKey || state == EmitterState.FlowSequenceFirstItem) { - return; + yield break; } var lines = comment.Value.Split(newLineSeparators, StringSplitOptions.None); if (comment.IsInline) { - Write(" # "); - Write(string.Join(" ", lines)); + foreach (var val in PrepareWrite(" # ")) + { + yield return val; + } + foreach (var val in PrepareWrite(string.Join(" ", lines))) + { + yield return val; + } } else { @@ -671,10 +689,22 @@ private void EmitComment(Comment comment) foreach (var line in lines) { - WriteIndent(); - Write("# "); - Write(line); - WriteBreak(); + foreach (var val in PrepareWriteIndent()) + { + yield return val; + } + foreach (var val in PrepareWrite("# ")) + { + yield return val; + } + foreach (var val in PrepareWrite(line)) + { + yield return val; + } + foreach (var val in PrepareWriteBreak()) + { + yield return val; + } } if (isFirst) @@ -689,7 +719,7 @@ private void EmitComment(Comment comment) /// /// Expect STREAM-START. /// - private void EmitStreamStart(ParsingEvent evt) + private IEnumerable EmitStreamStart(ParsingEvent evt) { if (!(evt is StreamStart)) { @@ -702,12 +732,13 @@ private void EmitStreamStart(ParsingEvent evt) isIndentation = true; state = EmitterState.FirstDocumentStart; + return Enumerable.Empty(); } /// /// Expect DOCUMENT-START or STREAM-END. /// - private void EmitDocumentStart(ParsingEvent evt, bool isFirst) + private IEnumerable EmitDocumentStart(ParsingEvent evt, bool isFirst) { if (evt is DocumentStart documentStart) { @@ -720,8 +751,14 @@ private void EmitDocumentStart(ParsingEvent evt, bool isFirst) if (!isFirst && !isDocumentEndWritten && (documentStart.Version != null || documentTagDirectives.Count > 0)) { isDocumentEndWritten = false; - WriteIndicator("...", true, false, false); - WriteIndent(); + foreach (var val in PrepareWriteIndicator("...", true, false, false)) + { + yield return val; + } + foreach (var val in PrepareWriteIndent()) + { + yield return val; + } } if (documentStart.Version != null) @@ -730,11 +767,21 @@ private void EmitDocumentStart(ParsingEvent evt, bool isFirst) var documentVersion = documentStart.Version.Version; isImplicit = false; - WriteIndicator("%YAML", true, false, false); - WriteIndicator(string.Format(CultureInfo.InvariantCulture, + foreach (var val in PrepareWriteIndicator("%YAML", true, false, false)) + { + yield return val; + } + var result = PrepareWriteIndicator(string.Format(CultureInfo.InvariantCulture, "{0}.{1}", documentVersion.Major, documentVersion.Minor), true, false, false); - WriteIndent(); + foreach (var val in result) + { + yield return val; + } + foreach (var val in PrepareWriteIndent()) + { + yield return val; + } } foreach (var tagDirective in documentTagDirectives) @@ -757,10 +804,22 @@ private void EmitDocumentStart(ParsingEvent evt, bool isFirst) foreach (var tagDirective in documentTagDirectives) { - WriteIndicator("%TAG", true, false, false); - WriteTagHandle(tagDirective.Handle); - WriteTagContent(tagDirective.Prefix, true); - WriteIndent(); + foreach (var val in PrepareWriteIndicator("%TAG", true, false, false)) + { + yield return val; + } + foreach (var val in PrepareWriteTagHandle(tagDirective.Handle)) + { + yield return val; + } + foreach (var val in PrepareWriteTagContent(tagDirective.Prefix, true)) + { + yield return val; + } + foreach (var val in PrepareWriteIndent()) + { + yield return val; + } } } @@ -771,11 +830,20 @@ private void EmitDocumentStart(ParsingEvent evt, bool isFirst) if (!isImplicit) { - WriteIndent(); - WriteIndicator("---", true, false, false); + foreach (var val in PrepareWriteIndent()) + { + yield return val; + } + foreach (var val in PrepareWriteIndicator("---", true, false, false)) + { + yield return val; + } if (isCanonical) { - WriteIndent(); + foreach (var val in PrepareWriteIndent()) + { + yield return val; + } } } @@ -837,16 +905,16 @@ private static void AppendTagDirectiveTo(TagDirective value, bool allowDuplicate /// /// Expect the root node. /// - private void EmitDocumentContent(ParsingEvent evt) + private IEnumerable EmitDocumentContent(ParsingEvent evt) { states.Push(EmitterState.DocumentEnd); - EmitNode(evt, false, false); + return EmitNode(evt, false, false); } /// /// Expect a node. /// - private void EmitNode(ParsingEvent evt, bool isMapping, bool isSimpleKey) + private IEnumerable EmitNode(ParsingEvent evt, bool isMapping, bool isSimpleKey) { isMappingContext = isMapping; isSimpleKeyContext = isSimpleKey; @@ -854,20 +922,16 @@ private void EmitNode(ParsingEvent evt, bool isMapping, bool isSimpleKey) switch (evt.Type) { case EventType.Alias: - EmitAlias(); - break; + return EmitAlias(); case EventType.Scalar: - EmitScalar(evt); - break; + return EmitScalar(evt); case EventType.SequenceStart: - EmitSequenceStart(evt); - break; + return EmitSequenceStart(evt); case EventType.MappingStart: - EmitMappingStart(evt); - break; + return EmitMappingStart(evt); default: throw new YamlException($"Expected SCALAR, SEQUENCE-START, MAPPING-START, or ALIAS, got {evt.Type}"); @@ -877,22 +941,34 @@ private void EmitNode(ParsingEvent evt, bool isMapping, bool isSimpleKey) /// /// Expect ALIAS. /// - private void EmitAlias() + private IEnumerable EmitAlias() { - ProcessAnchor(); + foreach (var val in ProcessAnchor()) + { + yield return val; + } state = states.Pop(); } /// /// Expect SCALAR. /// - private void EmitScalar(ParsingEvent evt) + private IEnumerable EmitScalar(ParsingEvent evt) { SelectScalarStyle(evt); - ProcessAnchor(); - ProcessTag(); + foreach (var val in ProcessAnchor()) + { + yield return val; + } + foreach (var val in ProcessTag()) + { + yield return val; + } IncreaseIndent(true, false); - ProcessScalar(); + foreach (var val in ProcessScalar()) + { + yield return val; + } indent = indents.Pop(); state = states.Pop(); @@ -960,29 +1036,24 @@ private void SelectScalarStyle(ParsingEvent evt) scalarData.Style = style; } - private void ProcessScalar() + private IEnumerable ProcessScalar() { switch (scalarData.Style) { case ScalarStyle.Plain: - WritePlainScalar(scalarData.Value, !isSimpleKeyContext); - break; + return PrepareWritePlainScalar(scalarData.Value, !isSimpleKeyContext); case ScalarStyle.SingleQuoted: - WriteSingleQuotedScalar(scalarData.Value, !isSimpleKeyContext); - break; + return PrepareWriteSingleQuotedScalar(scalarData.Value, !isSimpleKeyContext); case ScalarStyle.DoubleQuoted: - WriteDoubleQuotedScalar(scalarData.Value, !isSimpleKeyContext); - break; + return PrepareWriteDoubleQuotedScalar(scalarData.Value, !isSimpleKeyContext); case ScalarStyle.Literal: - WriteLiteralScalar(scalarData.Value); - break; + return PrepareWriteLiteralScalar(scalarData.Value); case ScalarStyle.Folded: - WriteFoldedScalar(scalarData.Value); - break; + return PrepareWriteFoldedScalar(scalarData.Value); default: throw new InvalidOperationException(); @@ -991,11 +1062,14 @@ private void ProcessScalar() #region Write scalar Methods - private void WritePlainScalar(string value, bool allowBreaks) + private IEnumerable PrepareWritePlainScalar(string value, bool allowBreaks) { if (!isWhitespace) { - Write(' '); + foreach (var val in PrepareWrite(' ')) + { + yield return val; + } } var previousSpace = false; @@ -1007,11 +1081,17 @@ private void WritePlainScalar(string value, bool allowBreaks) { if (allowBreaks && !previousSpace && column > bestWidth && index + 1 < value.Length && value[index + 1] != ' ') { - WriteIndent(); + foreach (var val in PrepareWriteIndent()) + { + yield return val; + } } else { - Write(character); + foreach (var val in PrepareWrite(character)) + { + yield return val; + } } previousSpace = true; } @@ -1019,9 +1099,15 @@ private void WritePlainScalar(string value, bool allowBreaks) { if (!previousBreak && character == '\n') { - WriteBreak(); + foreach (var val in PrepareWriteBreak()) + { + yield return val; + } + } + foreach (var val in PrepareWriteBreak(breakCharacter)) + { + yield return val; } - WriteBreak(breakCharacter); isIndentation = true; previousBreak = true; } @@ -1029,9 +1115,15 @@ private void WritePlainScalar(string value, bool allowBreaks) { if (previousBreak) { - WriteIndent(); + foreach (var val in PrepareWriteIndent()) + { + yield return val; + } + } + foreach (var val in PrepareWrite(character)) + { + yield return val; } - Write(character); isIndentation = false; previousSpace = false; previousBreak = false; @@ -1042,9 +1134,12 @@ private void WritePlainScalar(string value, bool allowBreaks) isIndentation = false; } - private void WriteSingleQuotedScalar(string value, bool allowBreaks) + private IEnumerable PrepareWriteSingleQuotedScalar(string value, bool allowBreaks) { - WriteIndicator("'", true, false, false); + foreach (var val in PrepareWriteIndicator("'", true, false, false)) + { + yield return val; + } var previousSpace = false; var previousBreak = false; @@ -1057,11 +1152,17 @@ private void WriteSingleQuotedScalar(string value, bool allowBreaks) if (allowBreaks && !previousSpace && column > bestWidth && index != 0 && index + 1 < value.Length && value[index + 1] != ' ') { - WriteIndent(); + foreach (var val in PrepareWriteIndent()) + { + yield return val; + } } else { - Write(character); + foreach (var val in PrepareWrite(character)) + { + yield return val; + } } previousSpace = true; } @@ -1069,9 +1170,15 @@ private void WriteSingleQuotedScalar(string value, bool allowBreaks) { if (!previousBreak && character == '\n') { - WriteBreak(); + foreach (var val in PrepareWriteBreak()) + { + yield return val; + } + } + foreach (var val in PrepareWriteBreak(breakCharacter)) + { + yield return val; } - WriteBreak(breakCharacter); isIndentation = true; previousBreak = true; } @@ -1079,28 +1186,43 @@ private void WriteSingleQuotedScalar(string value, bool allowBreaks) { if (previousBreak) { - WriteIndent(); + foreach (var val in PrepareWriteIndent()) + { + yield return val; + } } if (character == '\'') { - Write(character); + foreach (var val in PrepareWrite(character)) + { + yield return val; + } + } + foreach (var val in PrepareWrite(character)) + { + yield return val; } - Write(character); isIndentation = false; previousSpace = false; previousBreak = false; } } - WriteIndicator("'", false, false, false); + foreach (var val in PrepareWriteIndicator("'", false, false, false)) + { + yield return val; + } isWhitespace = false; isIndentation = false; } - private void WriteDoubleQuotedScalar(string value, bool allowBreaks) + private IEnumerable PrepareWriteDoubleQuotedScalar(string value, bool allowBreaks) { - WriteIndicator("\"", true, false, false); + foreach (var val in PrepareWriteIndicator("\"", true, false, false)) + { + yield return val; + } var previousSpace = false; for (var index = 0; index < value.Length; ++index) @@ -1108,83 +1230,143 @@ private void WriteDoubleQuotedScalar(string value, bool allowBreaks) var character = value[index]; if (!IsPrintable(character) || IsBreak(character, out _) || character == '"' || character == '\\') { - Write('\\'); + foreach (var val in PrepareWrite('\\')) + { + yield return val; + } switch (character) { case '\0': - Write('0'); + foreach (var val in PrepareWrite('0')) + { + yield return val; + } break; case '\x7': - Write('a'); + foreach (var val in PrepareWrite('a')) + { + yield return val; + } break; case '\x8': - Write('b'); + foreach (var val in PrepareWrite('b')) + { + yield return val; + } break; case '\x9': - Write('t'); + foreach (var val in PrepareWrite('t')) + { + yield return val; + } break; case '\xA': - Write('n'); + foreach (var val in PrepareWrite('n')) + { + yield return val; + } break; case '\xB': - Write('v'); + foreach (var val in PrepareWrite('v')) + { + yield return val; + } break; case '\xC': - Write('f'); + foreach (var val in PrepareWrite('f')) + { + yield return val; + } break; case '\xD': - Write('r'); + foreach (var val in PrepareWrite('r')) + { + yield return val; + } break; case '\x1B': - Write('e'); + foreach (var val in PrepareWrite('e')) + { + yield return val; + } break; case '\x22': - Write('"'); + foreach (var val in PrepareWrite('"')) + { + yield return val; + } break; case '\x5C': - Write('\\'); + foreach (var val in PrepareWrite('\\')) + { + yield return val; + } break; case '\x85': - Write('N'); + foreach (var val in PrepareWrite('N')) + { + yield return val; + } break; case '\xA0': - Write('_'); + foreach (var val in PrepareWrite('_')) + { + yield return val; + } break; case '\x2028': - Write('L'); + foreach (var val in PrepareWrite('L')) + { + yield return val; + } break; case '\x2029': - Write('P'); + foreach (var val in PrepareWrite('P')) + { + yield return val; + } break; default: var code = (ushort)character; if (code <= 0xFF) { - Write('x'); - Write(code.ToString("X02", CultureInfo.InvariantCulture)); + foreach (var val in PrepareWrite('x')) + { + yield return val; + } + foreach (var val in PrepareWrite(code.ToString("X02", CultureInfo.InvariantCulture))) + { + yield return val; + } } else if (IsHighSurrogate(character)) { if (index + 1 < value.Length && IsLowSurrogate(value[index + 1])) { - Write('U'); - Write(char.ConvertToUtf32(character, value[index + 1]).ToString("X08", CultureInfo.InvariantCulture)); + foreach (var val in PrepareWrite('U')) + { + yield return val; + } + foreach (var val in PrepareWrite(char.ConvertToUtf32(character, value[index + 1]).ToString("X08", CultureInfo.InvariantCulture))) + { + yield return val; + } index++; } else @@ -1194,8 +1376,14 @@ private void WriteDoubleQuotedScalar(string value, bool allowBreaks) } else { - Write('u'); - Write(code.ToString("X04", CultureInfo.InvariantCulture)); + foreach (var val in PrepareWrite('u')) + { + yield return val; + } + foreach (var val in PrepareWrite(code.ToString("X04", CultureInfo.InvariantCulture))) + { + yield return val; + } } break; } @@ -1205,38 +1393,62 @@ private void WriteDoubleQuotedScalar(string value, bool allowBreaks) { if (allowBreaks && !previousSpace && column > bestWidth && index > 0 && index + 1 < value.Length) { - WriteIndent(); + foreach (var val in PrepareWriteIndent()) + { + yield return val; + } if (value[index + 1] == ' ') { - Write('\\'); + foreach (var val in PrepareWrite('\\')) + { + yield return val; + } } } else { - Write(character); + foreach (var val in PrepareWrite(character)) + { + yield return val; + } } previousSpace = true; } else { - Write(character); + foreach (var val in PrepareWrite(character)) + { + yield return val; + } previousSpace = false; } } - WriteIndicator("\"", false, false, false); + foreach (var val in PrepareWriteIndicator("\"", false, false, false)) + { + yield return val; + } isWhitespace = false; isIndentation = false; } - private void WriteLiteralScalar(string value) + private IEnumerable PrepareWriteLiteralScalar(string value) { var previousBreak = true; - WriteIndicator("|", true, false, false); - WriteBlockScalarHints(value); - WriteBreak(); + foreach (var val in PrepareWriteIndicator("|", true, false, false)) + { + yield return val; + } + foreach (var val in PrepareWriteBlockScalarHints(value)) + { + yield return val; + } + foreach (var val in PrepareWriteBreak()) + { + yield return val; + } isIndentation = true; isWhitespace = true; @@ -1251,7 +1463,10 @@ private void WriteLiteralScalar(string value) if (IsBreak(character, out var breakCharacter)) { - WriteBreak(breakCharacter); + foreach (var val in PrepareWriteBreak(breakCharacter)) + { + yield return val; + } isIndentation = true; previousBreak = true; } @@ -1259,23 +1474,38 @@ private void WriteLiteralScalar(string value) { if (previousBreak) { - WriteIndent(); + foreach (var val in PrepareWriteIndent()) + { + yield return val; + } + } + foreach (var val in PrepareWrite(character)) + { + yield return val; } - Write(character); isIndentation = false; previousBreak = false; } } } - private void WriteFoldedScalar(string value) + private IEnumerable PrepareWriteFoldedScalar(string value) { var previousBreak = true; var leadingSpaces = true; - WriteIndicator(">", true, false, false); - WriteBlockScalarHints(value); - WriteBreak(); + foreach (var val in PrepareWriteIndicator(">", true, false, false)) + { + yield return val; + } + foreach (var val in PrepareWriteBlockScalarHints(value)) + { + yield return val; + } + foreach (var val in PrepareWriteBreak()) + { + yield return val; + } isIndentation = true; isWhitespace = true; @@ -1299,11 +1529,17 @@ private void WriteFoldedScalar(string value) } if (i + k < value.Length && !(IsBlank(value[i + k]) || IsBreak(value[i + k], out _))) { - WriteBreak(); + foreach (var val in PrepareWriteBreak()) + { + yield return val; + } } } - WriteBreak(breakCharacter); + foreach (var val in PrepareWriteBreak(breakCharacter)) + { + yield return val; + } isIndentation = true; previousBreak = true; } @@ -1311,16 +1547,25 @@ private void WriteFoldedScalar(string value) { if (previousBreak) { - WriteIndent(); + foreach (var val in PrepareWriteIndent()) + { + yield return val; + } leadingSpaces = IsBlank(character); } if (!previousBreak && character == ' ' && i + 1 < value.Length && value[i + 1] != ' ' && column > bestWidth) { - WriteIndent(); + foreach (var val in PrepareWriteIndent()) + { + yield return val; + } } else { - Write(character); + foreach (var val in PrepareWrite(character)) + { + yield return val; + } } isIndentation = false; previousBreak = false; @@ -1387,10 +1632,16 @@ private static bool IsLowSurrogate(char c) /// /// Expect SEQUENCE-START. /// - private void EmitSequenceStart(ParsingEvent evt) + private IEnumerable EmitSequenceStart(ParsingEvent evt) { - ProcessAnchor(); - ProcessTag(); + foreach (var val in ProcessAnchor()) + { + yield return val; + } + foreach (var val in ProcessTag()) + { + yield return val; + } var sequenceStart = (SequenceStart)evt; @@ -1407,10 +1658,16 @@ private void EmitSequenceStart(ParsingEvent evt) /// /// Expect MAPPING-START. /// - private void EmitMappingStart(ParsingEvent evt) + private IEnumerable EmitMappingStart(ParsingEvent evt) { - ProcessAnchor(); - ProcessTag(); + foreach (var val in ProcessAnchor()) + { + yield return val; + } + foreach (var val in ProcessTag()) + { + yield return val; + } var mappingStart = (MappingStart)evt; @@ -1424,50 +1681,82 @@ private void EmitMappingStart(ParsingEvent evt) } } - private void ProcessAnchor() + private IEnumerable ProcessAnchor() { - if (!anchorData.Anchor.IsEmpty && !skipAnchorName) + if (anchorData.Anchor.IsEmpty || skipAnchorName) + { + yield break; + } + + foreach (var val in PrepareWriteIndicator(anchorData.IsAlias ? "*" : "&", true, false, false)) + { + yield return val; + } + foreach (var val in PrepareWriteAnchor(anchorData.Anchor)) { - WriteIndicator(anchorData.IsAlias ? "*" : "&", true, false, false); - WriteAnchor(anchorData.Anchor); + yield return val; } } - private void ProcessTag() + private IEnumerable ProcessTag() { if (tagData.Handle == null && tagData.Suffix == null) { - return; + yield break; } if (tagData.Handle != null) { - WriteTagHandle(tagData.Handle); + foreach (var val in PrepareWriteTagHandle(tagData.Handle)) + { + yield return val; + } if (tagData.Suffix != null) { - WriteTagContent(tagData.Suffix, false); + foreach (var val in PrepareWriteTagContent(tagData.Suffix, false)) + { + yield return val; + } } } else { - WriteIndicator("!<", true, false, false); - WriteTagContent(tagData.Suffix!, false); - WriteIndicator(">", false, false, false); + foreach (var val in PrepareWriteIndicator("!<", true, false, false)) + { + yield return val; + } + foreach (var val in PrepareWriteTagContent(tagData.Suffix!, false)) + { + yield return val; + } + foreach (var val in PrepareWriteIndicator(">", false, false, false)) + { + yield return val; + } } } /// /// Expect DOCUMENT-END. /// - private void EmitDocumentEnd(ParsingEvent evt) + private IEnumerable EmitDocumentEnd(ParsingEvent evt) { if (evt is DocumentEnd documentEnd) { - WriteIndent(); + foreach (var val in PrepareWriteIndent()) + { + yield return val; + } if (!documentEnd.IsImplicit) { - WriteIndicator("...", true, false, false); - WriteIndent(); + foreach (var val in PrepareWriteIndicator("...", true, false, false)) + { + yield return val; + } + foreach (var val in PrepareWriteIndent()) + { + yield return val; + } isDocumentEndWritten = true; } @@ -1484,11 +1773,14 @@ private void EmitDocumentEnd(ParsingEvent evt) /// /// Expect a flow item node. /// - private void EmitFlowSequenceItem(ParsingEvent evt, bool isFirst) + private IEnumerable EmitFlowSequenceItem(ParsingEvent evt, bool isFirst) { if (isFirst) { - WriteIndicator("[", true, true, false); + foreach (var val in PrepareWriteIndicator("[", true, true, false)) + { + yield return val; + } IncreaseIndent(true, false); ++flowLevel; } @@ -1499,37 +1791,58 @@ private void EmitFlowSequenceItem(ParsingEvent evt, bool isFirst) indent = indents.Pop(); if (isCanonical && !isFirst) { - WriteIndicator(",", false, false, false); - WriteIndent(); + foreach (var val in PrepareWriteIndicator(",", false, false, false)) + { + yield return val; + } + foreach (var val in PrepareWriteIndent()) + { + yield return val; + } + } + foreach (var val in PrepareWriteIndicator("]", false, false, false)) + { + yield return val; } - WriteIndicator("]", false, false, false); state = states.Pop(); - return; + yield break; } if (!isFirst) { - WriteIndicator(",", false, false, false); + foreach (var val in PrepareWriteIndicator(",", false, false, false)) + { + yield return val; + } } if (isCanonical || column > bestWidth) { - WriteIndent(); + foreach (var val in PrepareWriteIndent()) + { + yield return val; + } } states.Push(EmitterState.FlowSequenceItem); - EmitNode(evt, false, false); + foreach (var val in EmitNode(evt, false, false)) + { + yield return val; + } } /// /// Expect a flow key node. /// - private void EmitFlowMappingKey(ParsingEvent evt, bool isFirst) + private IEnumerable EmitFlowMappingKey(ParsingEvent evt, bool isFirst) { if (isFirst) { - WriteIndicator("{", true, true, false); + foreach (var val in PrepareWriteIndicator("{", true, true, false)) + { + yield return val; + } IncreaseIndent(true, false); ++flowLevel; } @@ -1540,61 +1853,97 @@ private void EmitFlowMappingKey(ParsingEvent evt, bool isFirst) indent = indents.Pop(); if (isCanonical && !isFirst) { - WriteIndicator(",", false, false, false); - WriteIndent(); + foreach (var val in PrepareWriteIndicator(",", false, false, false)) + { + yield return val; + } + foreach (var val in PrepareWriteIndent()) + { + yield return val; + } + } + foreach (var val in PrepareWriteIndicator("}", false, false, false)) + { + yield return val; } - WriteIndicator("}", false, false, false); state = states.Pop(); - return; + yield break; } if (!isFirst) { - WriteIndicator(",", false, false, false); + foreach (var val in PrepareWriteIndicator(",", false, false, false)) + { + yield return val; + } } if (isCanonical || column > bestWidth) { - WriteIndent(); + foreach (var val in PrepareWriteIndent()) + { + yield return val; + } } if (!isCanonical && CheckSimpleKey()) { states.Push(EmitterState.FlowMappingSimpleValue); - EmitNode(evt, true, true); + foreach (var val in EmitNode(evt, true, true)) + { + yield return val; + } } else { - WriteIndicator("?", true, false, false); + foreach (var val in PrepareWriteIndicator("?", true, false, false)) + { + yield return val; + } states.Push(EmitterState.FlowMappingValue); - EmitNode(evt, true, false); + foreach (var val in EmitNode(evt, true, false)) + { + yield return val; + } } } /// /// Expect a flow value node. /// - private void EmitFlowMappingValue(ParsingEvent evt, bool isSimple) + private IEnumerable EmitFlowMappingValue(ParsingEvent evt, bool isSimple) { if (isSimple) { - WriteIndicator(":", false, false, false); + foreach (var val in PrepareWriteIndicator(":", false, false, false)) + { + yield return val; + } } else { if (isCanonical || column > bestWidth) { - WriteIndent(); + foreach (var val in PrepareWriteIndent()) + { + yield return val; + } + } + foreach (var val in PrepareWriteIndicator(":", true, false, false)) + { + yield return val; } - WriteIndicator(":", true, false, false); } states.Push(EmitterState.FlowMappingKey); - EmitNode(evt, true, false); + foreach (var val in EmitNode(evt, true, false)) + { + yield return val; + } } /// /// Expect a block item node. /// - private void EmitBlockSequenceItem(ParsingEvent evt, bool isFirst) + private IEnumerable EmitBlockSequenceItem(ParsingEvent evt, bool isFirst) { if (isFirst) { @@ -1605,20 +1954,29 @@ private void EmitBlockSequenceItem(ParsingEvent evt, bool isFirst) { indent = indents.Pop(); state = states.Pop(); - return; + yield break; } - WriteIndent(); - WriteIndicator("-", true, false, true); + foreach (var val in PrepareWriteIndent()) + { + yield return val; + } + foreach (var val in PrepareWriteIndicator("-", true, false, true)) + { + yield return val; + } states.Push(EmitterState.BlockSequenceItem); - EmitNode(evt, false, false); + foreach (var val in EmitNode(evt, false, false)) + { + yield return val; + } } /// /// Expect a block key node. /// - private void EmitBlockMappingKey(ParsingEvent evt, bool isFirst) + private IEnumerable EmitBlockMappingKey(ParsingEvent evt, bool isFirst) { if (isFirst) { @@ -1629,37 +1987,61 @@ private void EmitBlockMappingKey(ParsingEvent evt, bool isFirst) { indent = indents.Pop(); state = states.Pop(); - return; + yield break; } - WriteIndent(); + foreach (var val in PrepareWriteIndent()) + { + yield return val; + } if (CheckSimpleKey()) { states.Push(EmitterState.BlockMappingSimpleValue); - EmitNode(evt, true, true); - WriteIndicator(":", false, false, false); + foreach (var val in EmitNode(evt, true, true)) + { + yield return val; + } + foreach (var val in PrepareWriteIndicator(":", false, false, false)) + { + yield return val; + } } else { - WriteIndicator("?", true, false, true); + foreach (var val in PrepareWriteIndicator("?", true, false, true)) + { + yield return val; + } states.Push(EmitterState.BlockMappingValue); - EmitNode(evt, true, false); + foreach (var val in EmitNode(evt, true, false)) + { + yield return val; + } } } /// /// Expect a block value node. /// - private void EmitBlockMappingValue(ParsingEvent evt, bool isSimple) + private IEnumerable EmitBlockMappingValue(ParsingEvent evt, bool isSimple) { if (!isSimple) { - WriteIndent(); - WriteIndicator(":", true, false, true); + foreach (var val in PrepareWriteIndent()) + { + yield return val; + } + foreach (var val in PrepareWriteIndicator(":", true, false, true)) + { + yield return val; + } } states.Push(EmitterState.BlockMappingKey); - EmitNode(evt, true, false); + foreach (var val in EmitNode(evt, true, false)) + { + yield return val; + } } private void IncreaseIndent(bool isFlow, bool isIndentless) @@ -1789,16 +2171,19 @@ private bool CheckEmptyStructure() } #endregion - #region Write Methods + #region Write Preparation Methods - private void WriteBlockScalarHints(string value) + private IEnumerable PrepareWriteBlockScalarHints(string value) { var analyzer = new CharacterAnalyzer(new StringLookAheadBuffer(value)); if (analyzer.IsSpace() || analyzer.IsBreak()) { var indentHint = bestIndent.ToString(CultureInfo.InvariantCulture); - WriteIndicator(indentHint, false, false, false); + foreach (var val in PrepareWriteIndicator(indentHint, false, false, false)) + { + yield return val; + } } string? chompHint = null; @@ -1813,24 +2198,33 @@ private void WriteBlockScalarHints(string value) if (chompHint != null) { - WriteIndicator(chompHint, false, false, false); + foreach (var val in PrepareWriteIndicator(chompHint, false, false, false)) + { + yield return val; + } } } - private void WriteIndicator(string indicator, bool needWhitespace, bool whitespace, bool indentation) + private IEnumerable PrepareWriteIndicator(string indicator, bool needWhitespace, bool whitespace, bool indentation) { if (needWhitespace && !isWhitespace) { - Write(' '); + foreach (var val in PrepareWrite(' ')) + { + yield return val; + } } - Write(indicator); + foreach (var val in PrepareWrite(indicator)) + { + yield return val; + } isWhitespace = whitespace; isIndentation &= indentation; } - private void WriteIndent() + private IEnumerable PrepareWriteIndent() { var currentIndent = Math.Max(indent, 0); @@ -1840,47 +2234,68 @@ private void WriteIndent() if (isBreakRequired) { - WriteBreak(); + foreach (var val in PrepareWriteBreak()) + { + yield return val; + } } while (column < currentIndent) { - Write(' '); + foreach (var val in PrepareWrite(' ')) + { + yield return val; + } } isWhitespace = true; isIndentation = true; } - private void WriteAnchor(AnchorName value) + private IEnumerable PrepareWriteAnchor(AnchorName value) { - Write(value.Value); + foreach (var val in PrepareWrite(value.Value)) + { + yield return val; + } isWhitespace = false; isIndentation = false; } - private void WriteTagHandle(string value) + private IEnumerable PrepareWriteTagHandle(string value) { if (!isWhitespace) { - Write(' '); + foreach (var val in PrepareWrite(' ')) + { + yield return val; + } } - Write(value); + foreach (var val in PrepareWrite(value)) + { + yield return val; + } isWhitespace = false; isIndentation = false; } - private void WriteTagContent(string value, bool needsWhitespace) + private IEnumerable PrepareWriteTagContent(string value, bool needsWhitespace) { if (needsWhitespace && !isWhitespace) { - Write(' '); + foreach (var val in PrepareWrite(' ')) + { + yield return val; + } } - Write(UrlEncode(value)); + foreach (var val in PrepareWrite(UrlEncode(value))) + { + yield return val; + } isWhitespace = false; isIndentation = false; @@ -1900,27 +2315,27 @@ private static string UrlEncode(string text) }); } - private void Write(char value) + private IEnumerable PrepareWrite(char value) { - output.Write(value); + yield return value.ToString(); ++column; } - private void Write(string value) + private IEnumerable PrepareWrite(string value) { - output.Write(value); + yield return value; column += value.Length; } - private void WriteBreak(char breakCharacter = '\n') + private IEnumerable PrepareWriteBreak(char breakCharacter = '\n') { if (breakCharacter == '\n') { - output.Write(newLine); + yield return newLine; } else { - output.Write(breakCharacter); + yield return breakCharacter.ToString(); } column = 0; } diff --git a/YamlDotNet/Core/IEmitter.cs b/YamlDotNet/Core/IEmitter.cs index c51a06fd..b2cd188a 100644 --- a/YamlDotNet/Core/IEmitter.cs +++ b/YamlDotNet/Core/IEmitter.cs @@ -19,6 +19,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +using System.Threading.Tasks; using YamlDotNet.Core.Events; namespace YamlDotNet.Core @@ -32,5 +33,7 @@ public interface IEmitter /// Emits an event. /// void Emit(ParsingEvent @event); + + Task EmitAsync(ParsingEvent @event); } } diff --git a/YamlDotNet/Serialization/Deserializer.cs b/YamlDotNet/Serialization/Deserializer.cs index c514fa1b..2451e24d 100644 --- a/YamlDotNet/Serialization/Deserializer.cs +++ b/YamlDotNet/Serialization/Deserializer.cs @@ -21,6 +21,7 @@ using System; using System.IO; +using System.Threading.Tasks; using YamlDotNet.Core; using YamlDotNet.Core.Events; using YamlDotNet.Serialization.Utilities; @@ -77,11 +78,21 @@ public T Deserialize(TextReader input) return Deserialize(new Parser(input)); } + public async Task DeserializeAsync(TextReader input) + { + return await DeserializeAsync(new Parser(input)); + } + public T Deserialize(IParser parser) { return (T)Deserialize(parser, typeof(T))!; // We really want an exception if we are trying to deserialize null into a non-nullable type } + public async Task DeserializeAsync(IParser parser) + { + return (T)(await DeserializeAsync(parser, typeof(T)))!; + } + public object? Deserialize(string input) { return Deserialize(input, typeof(object)); @@ -92,11 +103,21 @@ public T Deserialize(IParser parser) return Deserialize(input, typeof(object)); } + public async Task DeserializeAsync(TextReader input) + { + return await DeserializeAsync(input, typeof(object)); + } + public object? Deserialize(IParser parser) { return Deserialize(parser, typeof(object)); } + public async Task DeserializeAsync(IParser parser) + { + return await DeserializeAsync(parser, typeof(object)); + } + public object? Deserialize(string input, Type type) { using var reader = new StringReader(input); @@ -108,6 +129,11 @@ public T Deserialize(IParser parser) return Deserialize(new Parser(input), type); } + public async Task DeserializeAsync(TextReader input, Type type) + { + return await DeserializeAsync(new Parser(input), type); + } + /// /// Deserializes an object of the specified type. /// @@ -150,5 +176,16 @@ public T Deserialize(IParser parser) return result; } + + /// + /// Deserializes an object of the specified type. + /// + /// The from where to deserialize the object. + /// The static type of the object to deserialize. + /// A task that contains the deserialized object on success. + public async Task DeserializeAsync(IParser parser, Type type) + { + throw new NotImplementedException(); + } } } diff --git a/YamlDotNet/Serialization/IDeserializer.cs b/YamlDotNet/Serialization/IDeserializer.cs index 6d17bfb2..64b49276 100644 --- a/YamlDotNet/Serialization/IDeserializer.cs +++ b/YamlDotNet/Serialization/IDeserializer.cs @@ -21,6 +21,7 @@ using System; using System.IO; +using System.Threading.Tasks; using YamlDotNet.Core; namespace YamlDotNet.Serialization @@ -29,13 +30,18 @@ public interface IDeserializer { T Deserialize(string input); T Deserialize(TextReader input); + Task DeserializeAsync(TextReader input); T Deserialize(IParser parser); + Task DeserializeAsync(IParser parser); object? Deserialize(string input); object? Deserialize(TextReader input); + Task DeserializeAsync(TextReader input); object? Deserialize(IParser parser); + Task DeserializeAsync(IParser parser); object? Deserialize(string input, Type type); object? Deserialize(TextReader input, Type type); + Task DeserializeAsync(TextReader reader, Type type); /// /// Deserializes an object of the specified type. @@ -44,5 +50,13 @@ public interface IDeserializer /// The static type of the object to deserialize. /// Returns the deserialized object. object? Deserialize(IParser parser, Type type); + + /// + /// Deserializes an object of the specified type. + /// + /// The from where to deserialize the object. + /// The static type of the object to deserialize. + /// A task that contains the deserialized object on success. + Task DeserializeAsync(IParser parser, Type type); } } diff --git a/YamlDotNet/Serialization/IObjectGraphTraversalStrategy.cs b/YamlDotNet/Serialization/IObjectGraphTraversalStrategy.cs index dece648f..0b3b6aaf 100644 --- a/YamlDotNet/Serialization/IObjectGraphTraversalStrategy.cs +++ b/YamlDotNet/Serialization/IObjectGraphTraversalStrategy.cs @@ -19,6 +19,8 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. +using System.Threading.Tasks; + namespace YamlDotNet.Serialization { /// @@ -33,5 +35,7 @@ public interface IObjectGraphTraversalStrategy /// An that is to be notified during the traversal. /// A that will be passed to the . void Traverse(IObjectDescriptor graph, IObjectGraphVisitor visitor, TContext context); + + Task TraverseAsync(IObjectDescriptor graph, IObjectGraphVisitor visitor, TContext context); } } diff --git a/YamlDotNet/Serialization/IObjectGraphVisitor.cs b/YamlDotNet/Serialization/IObjectGraphVisitor.cs index 87455f10..bdf597a9 100644 --- a/YamlDotNet/Serialization/IObjectGraphVisitor.cs +++ b/YamlDotNet/Serialization/IObjectGraphVisitor.cs @@ -26,6 +26,9 @@ namespace YamlDotNet.Serialization /// /// Defined the interface of a type that can be notified during an object graph traversal. /// + + // This will need to be updated to include Async versions of methods due to use in + // IObjectGraphTraversalStrategy and its implementations public interface IObjectGraphVisitor { /// diff --git a/YamlDotNet/Serialization/ISerializer.cs b/YamlDotNet/Serialization/ISerializer.cs index 10757e59..741b514a 100644 --- a/YamlDotNet/Serialization/ISerializer.cs +++ b/YamlDotNet/Serialization/ISerializer.cs @@ -21,6 +21,7 @@ using System; using System.IO; +using System.Threading.Tasks; using YamlDotNet.Core; namespace YamlDotNet.Serialization @@ -47,6 +48,14 @@ public interface ISerializer /// The object to serialize. void Serialize(TextWriter writer, object? graph); + /// + /// Serializes the specified object. + /// + /// The where to serialize the object. + /// The object to serialize. + /// A task that represents the asynchronous serialization operation + Task SerializeAsync(TextWriter writer, object? graph); + /// /// Serializes the specified object. /// @@ -55,6 +64,15 @@ public interface ISerializer /// The static type of the object to serialize. void Serialize(TextWriter writer, object? graph, Type type); + /// + /// Serializes the specified object. + /// + /// The where to serialize the object. + /// The object to serialize. + /// The static type of the object to serialize. + /// A task that represents the asynchronous serialization operation + Task SerializeAsync(TextWriter writer, object? graph, Type type); + /// /// Serializes the specified object. /// @@ -62,6 +80,14 @@ public interface ISerializer /// The object to serialize. void Serialize(IEmitter emitter, object? graph); + /// + /// Serializes the specified object. + /// + /// The where to serialize the object. + /// The object to serialize. + /// A task that represents the asynchronous serialization operation + Task SerializeAsync(IEmitter emitter, object? graph); + /// /// Serializes the specified object. /// @@ -69,5 +95,14 @@ public interface ISerializer /// The object to serialize. /// The static type of the object to serialize. void Serialize(IEmitter emitter, object? graph, Type type); + + /// + /// Serializes the specified object. + /// + /// The where to serialize the object. + /// The object to serialize. + /// The static type of the object to serialize. + /// A task that represents the asynchronous serialization operation + Task SerializeAsync(IEmitter emitter, object? graph, Type type); } } diff --git a/YamlDotNet/Serialization/IValueSerializer.cs b/YamlDotNet/Serialization/IValueSerializer.cs index a5c1ab68..552f0b16 100644 --- a/YamlDotNet/Serialization/IValueSerializer.cs +++ b/YamlDotNet/Serialization/IValueSerializer.cs @@ -20,6 +20,7 @@ // SOFTWARE. using System; +using System.Threading.Tasks; using YamlDotNet.Core; namespace YamlDotNet.Serialization @@ -27,5 +28,7 @@ namespace YamlDotNet.Serialization public interface IValueSerializer { void SerializeValue(IEmitter emitter, object? value, Type? type); + + Task SerializeValueAsync(IEmitter emitter, object? value, Type? type); } } diff --git a/YamlDotNet/Serialization/ObjectGraphTraversalStrategies/FullObjectGraphTraversalStrategy.cs b/YamlDotNet/Serialization/ObjectGraphTraversalStrategies/FullObjectGraphTraversalStrategy.cs index e5581e9c..4fb1ab0e 100644 --- a/YamlDotNet/Serialization/ObjectGraphTraversalStrategies/FullObjectGraphTraversalStrategy.cs +++ b/YamlDotNet/Serialization/ObjectGraphTraversalStrategies/FullObjectGraphTraversalStrategy.cs @@ -23,6 +23,7 @@ using System.Collections; using System.Collections.Generic; using System.Text; +using System.Threading.Tasks; using YamlDotNet.Core; using YamlDotNet.Helpers; using YamlDotNet.Serialization.Utilities; @@ -62,6 +63,11 @@ void IObjectGraphTraversalStrategy.Traverse(IObjectDescriptor graph, I Traverse("", graph, visitor, context, new Stack(maxRecursion)); } + public async Task TraverseAsync(IObjectDescriptor graph, IObjectGraphVisitor visitor, TContext context) + { + throw new NotImplementedException(); + } + protected struct ObjectPathSegment { public readonly object Name; diff --git a/YamlDotNet/Serialization/Serializer.cs b/YamlDotNet/Serialization/Serializer.cs index 4318c7f2..9b2ff4c3 100644 --- a/YamlDotNet/Serialization/Serializer.cs +++ b/YamlDotNet/Serialization/Serializer.cs @@ -21,6 +21,7 @@ using System; using System.IO; +using System.Threading.Tasks; using YamlDotNet.Core; using YamlDotNet.Core.Events; @@ -95,6 +96,11 @@ public void Serialize(TextWriter writer, object? graph) Serialize(new Emitter(writer, emitterSettings), graph); } + public async Task SerializeAsync(TextWriter writer, object? graph) + { + await SerializeAsync(new Emitter(writer, emitterSettings), graph); + } + /// /// Serializes the specified object. /// @@ -106,6 +112,11 @@ public void Serialize(TextWriter writer, object? graph, Type type) Serialize(new Emitter(writer, emitterSettings), graph, type); } + public async Task SerializeAsync(TextWriter writer, object? graph, Type type) + { + await SerializeAsync(new Emitter(writer, emitterSettings), graph, type); + } + /// /// Serializes the specified object. /// @@ -121,6 +132,16 @@ public void Serialize(IEmitter emitter, object? graph) EmitDocument(emitter, graph, null); } + public async Task SerializeAsync(IEmitter emitter, object? graph) + { + if (emitter == null) + { + throw new ArgumentNullException(nameof(emitter)); + } + + await EmitDocumentAsync(emitter, graph, null); + } + /// /// Serializes the specified object. /// @@ -142,6 +163,21 @@ public void Serialize(IEmitter emitter, object? graph, Type type) EmitDocument(emitter, graph, type); } + public async Task SerializeAsync(IEmitter emitter, object? graph, Type type) + { + if (emitter == null) + { + throw new ArgumentNullException(nameof(emitter)); + } + + if (type == null) + { + throw new ArgumentNullException(nameof(type)); + } + + await EmitDocumentAsync(emitter, graph, type); + } + private void EmitDocument(IEmitter emitter, object? graph, Type? type) { emitter.Emit(new StreamStart()); @@ -152,5 +188,16 @@ private void EmitDocument(IEmitter emitter, object? graph, Type? type) emitter.Emit(new DocumentEnd(true)); emitter.Emit(new StreamEnd()); } + + private async Task EmitDocumentAsync(IEmitter emitter, object? graph, Type? type) + { + await emitter.EmitAsync(new StreamStart()); + await emitter.EmitAsync(new DocumentStart()); + + await valueSerializer.SerializeValueAsync(emitter, graph, type); + + await emitter.EmitAsync(new DocumentEnd(true)); + await emitter.EmitAsync(new StreamEnd()); + } } } diff --git a/YamlDotNet/Serialization/SerializerBuilder.cs b/YamlDotNet/Serialization/SerializerBuilder.cs index 74b927f6..841aadcf 100755 --- a/YamlDotNet/Serialization/SerializerBuilder.cs +++ b/YamlDotNet/Serialization/SerializerBuilder.cs @@ -21,6 +21,8 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; + #if NET7_0_OR_GREATER using System.Diagnostics.CodeAnalysis; #endif @@ -732,26 +734,47 @@ LazyComponentRegistrationList PrepareEmitterVisitor(IEmitter emitter, IObjectDescriptor graph) + { var preProcessingPhaseObjectGraphVisitors = preProcessingPhaseObjectGraphVisitorFactories.BuildComponentList(typeConverters); foreach (var visitor in preProcessingPhaseObjectGraphVisitors) { traversalStrategy.Traverse(graph, visitor, default); } + // TODO: this needs to be refactored to allow an async delegate, since all emitters in the chain should be async if this is used asynchronously void NestedObjectSerializer(object? v, Type? t) => SerializeValue(emitter, v, t); var emittingVisitor = emissionPhaseObjectGraphVisitorFactories.BuildComponentChain( new EmittingObjectGraphVisitor(eventEmitter), + // TODO: the signiture of this probably needs to be modified so that async emitters in the chain can be handled correctly inner => new EmissionPhaseObjectGraphVisitorArgs(inner, eventEmitter, preProcessingPhaseObjectGraphVisitors, typeConverters, NestedObjectSerializer) ); - traversalStrategy.Traverse(graph, emittingVisitor, emitter); + return emittingVisitor; } } } diff --git a/YamlDotNet/Serialization/StaticSerializerBuilder.cs b/YamlDotNet/Serialization/StaticSerializerBuilder.cs index a0de9755..f0bfae04 100644 --- a/YamlDotNet/Serialization/StaticSerializerBuilder.cs +++ b/YamlDotNet/Serialization/StaticSerializerBuilder.cs @@ -21,6 +21,8 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; + #if NET7_0_OR_GREATER using System.Diagnostics.CodeAnalysis; #endif @@ -748,6 +750,13 @@ public void SerializeValue(IEmitter emitter, object? value, Type? type) traversalStrategy.Traverse(graph, emittingVisitor, emitter); } + + public async Task SerializeValueAsync(IEmitter emitter, object? value, Type? type) + { + // This will need to reimplement SerializeValue to call the emitter's EmitAsync + // method and the traversalStrategy's TraverseAsync instead. + throw new NotImplementedException(); + } } } }