Added callbacks to TagReader class to permit user-handled parsing

This commit is contained in:
ForeverZer0 2021-08-25 00:55:43 -04:00
parent 778d15f44b
commit a3e5ce5f5a
4 changed files with 122 additions and 8 deletions

View File

@ -0,0 +1,34 @@
using System;
using JetBrains.Annotations;
namespace SharpNBT
{
/// <summary>
/// Arguments supplied with tag-related events.
/// </summary>
public class TagEventArgs : EventArgs
{
/// <summary>
/// Gets a constant describing the basic NBT type of the tag.
/// </summary>
public TagType Type { get; }
/// <summary>
/// Gets the parsed <see cref="Tag"/> instance.
/// </summary>
[NotNull]
public Tag Tag { get; }
/// <summary>
/// Creates a new instance of the <see cref="TagEventArgs"/> class.
/// </summary>
/// <param name="type">A constant describing the basic NBT type of the tag.</param>
/// <param name="tag">The parsed <see cref="Tag"/> instance.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="tag"/> is <see langword="null"/>.</exception>
public TagEventArgs(TagType type, [NotNull] Tag tag)
{
Type = type;
Tag = tag ?? throw new ArgumentNullException(nameof(tag));
}
}
}

View File

@ -0,0 +1,52 @@
using System;
using System.ComponentModel;
using System.IO;
using JetBrains.Annotations;
namespace SharpNBT
{
/// <summary>
/// Arguments supplied when an event that can be handled by an event subscriber.
/// </summary>
public class TagHandledEventArgs : HandledEventArgs
{
/// <summary>
/// Gets a constant describing the basic NBT type of the tag.
/// </summary>
public TagType Type { get; }
/// <summary>
/// Gets flag indicating if this tag is named, only <see langowrd="false"/> when a tag is a direct child of a <see cref="ListTag"/>.
/// </summary>
public bool IsNamed { get; }
/// <summary>
/// Gets the stream being read from, positioned at the beginning of the tag payload.
/// <para/>
/// When handling this event, the stream position must be moved to the end of the payload, ready for the next tag to be parsed.
/// </summary>
[NotNull]
public Stream Stream { get; }
/// <summary>
/// Gets or sets the resulting tag from this event being handled.
/// </summary>
/// <remarks>This property <b>must</b> set to a non-null value when <see cref="HandledEventArgs.Handled"/> is <see langword="true"/>.</remarks>
[CanBeNull]
public Tag Result { get; set; }
/// <summary>
/// Creates a new instance of the <see cref="TagHandledEventArgs"/> class.
/// </summary>
/// <param name="type">A constant describing the basic NBT type of the tag.</param>
/// <param name="isNamed">Flag indicating if this tag is named, only <see langowrd="false"/> when a tag is a direct child of a <see cref="ListTag"/>.</param>
/// <param name="stream">The stream being read from, positioned at the beginning of the tag payload.</param>
/// <exception cref="ArgumentNullException">Thrown when <paramref name="stream"/> is <see langword="null"/>.</exception>
public TagHandledEventArgs(TagType type, bool isNamed, [NotNull] Stream stream)
{
Type = type;
IsNamed = isNamed;
Stream = stream ?? throw new ArgumentNullException(nameof(stream));
}
}
}

View File

@ -0,0 +1,12 @@
using System;
namespace SharpNBT
{
/// <summary>
/// Handler for events used with the <see cref="TagReader"/> class.
/// </summary>
/// <typeparam name="T">A type derived from <see cref="EventArgs"/>.</typeparam>
/// <param name="reader">The <see cref="TagReader"/> instance invoking the event.</param>
/// <param name="args">Any relevant args to be supplied with the callback,</param>
public delegate void TagReaderCallback<in T>(TagReader reader, T args) where T : EventArgs;
}

View File

@ -7,12 +7,7 @@ using JetBrains.Annotations;
namespace SharpNBT namespace SharpNBT
{ {
/// <summary>
/// Delegate type for tag-related events that can occur within the <see cref="TagReader"/> class.
/// </summary>
/// <seealso cref="TagReader.TagRead"/>
public delegate void TagReadCallback(TagReader reader, TagType type, Tag tag);
/// <summary> /// <summary>
/// Provides methods for reading NBT data from a stream. /// Provides methods for reading NBT data from a stream.
/// </summary> /// </summary>
@ -22,7 +17,9 @@ namespace SharpNBT
/// <summary> /// <summary>
/// Occurs when a tag has been fully deserialized from the stream. /// Occurs when a tag has been fully deserialized from the stream.
/// </summary> /// </summary>
public event TagReadCallback TagRead; public event TagReaderCallback<TagEventArgs> TagRead;
public event TagReaderCallback<TagHandledEventArgs> TagEncountered;
/// <summary> /// <summary>
/// Gets the underlying stream this <see cref="TagReader"/> is operating on. /// Gets the underlying stream this <see cref="TagReader"/> is operating on.
@ -351,6 +348,13 @@ namespace SharpNBT
[NotNull] [NotNull]
private Tag ReadTag(TagType type, bool named) private Tag ReadTag(TagType type, bool named)
{ {
var result = OnTagEncountered(type, named);
if (result != null)
{
OnTagRead(result);
return result;
}
Tag tag = type switch Tag tag = type switch
{ {
TagType.End => new EndTag(), TagType.End => new EndTag(),
@ -447,7 +451,19 @@ namespace SharpNBT
/// Invokes the <see cref="TagRead"/> event when a tag has been fully deserialized from the <see cref="BaseStream"/>. /// Invokes the <see cref="TagRead"/> event when a tag has been fully deserialized from the <see cref="BaseStream"/>.
/// </summary> /// </summary>
/// <param name="tag">The deserialized <see cref="Tag"/> instance.</param> /// <param name="tag">The deserialized <see cref="Tag"/> instance.</param>
protected virtual void OnTagRead(Tag tag) => TagRead?.Invoke(this, tag.Type, tag); protected virtual void OnTagRead(Tag tag) => TagRead?.Invoke(this, new TagEventArgs(tag.Type, tag));
[CanBeNull]
protected virtual Tag OnTagEncountered(TagType type, bool named)
{
// Early out if no subscribers.
if (TagEncountered is null)
return null;
var args = new TagHandledEventArgs(type, named, BaseStream);
TagEncountered.Invoke(this, args);
return args.Handled ? args.Result : null;
}
} }
} }