From 56e68dd6194079db00c9685765fb7674ceb70c63 Mon Sep 17 00:00:00 2001 From: Oliver Booth Date: Sun, 4 Dec 2022 19:49:08 +0000 Subject: [PATCH] Use custom Optional rather than T? for optional properties --- .../VirtualParadiseModelObjectBuilder.cs | 46 ++++---- ...ualParadiseParticleEmitterObjectBuilder.cs | 96 ++++++++-------- VpSharp/src/Optional.cs | 108 ++++++++++++++++++ 3 files changed, 179 insertions(+), 71 deletions(-) create mode 100644 VpSharp/src/Optional.cs diff --git a/VpSharp/src/Entities/VirtualParadiseModelObjectBuilder.cs b/VpSharp/src/Entities/VirtualParadiseModelObjectBuilder.cs index 8fa4b4c..f3df4a0 100644 --- a/VpSharp/src/Entities/VirtualParadiseModelObjectBuilder.cs +++ b/VpSharp/src/Entities/VirtualParadiseModelObjectBuilder.cs @@ -24,19 +24,19 @@ public sealed class VirtualParadiseModelObjectBuilder : VirtualParadiseObjectBui /// Gets or sets the value of this object's Action field. /// /// The value of this object's Action field, or to leave unchanged. - public string? Action { get; set; } + public Optional Action { get; set; } /// /// Gets or sets the value of this object's Description field. /// /// The value of this object's Description field, or to leave unchanged. - public string? Description { get; set; } + public Optional Description { get; set; } /// /// Gets or sets the value of this object's Model field. /// /// The value of this object's Model field, or to leave unchanged. - public string? Model { get; set; } + public Optional Model { get; set; } /// /// Gets or sets the date and time at which this object was last modified. @@ -48,7 +48,7 @@ public sealed class VirtualParadiseModelObjectBuilder : VirtualParadiseObjectBui /// This property may only be set during an object load, and will throw at /// any other point. /// - public DateTimeOffset? ModificationTimestamp { get; set; } + public Optional ModificationTimestamp { get; set; } /// /// Gets or sets the owner of this object. @@ -58,26 +58,26 @@ public sealed class VirtualParadiseModelObjectBuilder : VirtualParadiseObjectBui /// This property may only be set during an object load, and will throw at /// any other point. /// - public VirtualParadiseUser? Owner { get; set; } + public Optional Owner { get; set; } /// /// Gets or sets the position of the object. /// /// The position of the object, or to leave unchanged. - public Vector3d? Position { get; set; } + public Optional Position { get; set; } /// /// Gets or sets the rotation of the object. /// /// The rotation of the object, or to leave unchanged. - public Quaternion? Rotation { get; set; } + public Optional Rotation { get; set; } /// /// Sets the value of this object's Action field. /// /// The new value of the Action field, or to leave unchanged. /// The current instance of this builder. - public VirtualParadiseModelObjectBuilder WithAction(string? action) + public VirtualParadiseModelObjectBuilder WithAction(Optional action) { Action = action; return this; @@ -90,7 +90,7 @@ public sealed class VirtualParadiseModelObjectBuilder : VirtualParadiseObjectBui /// The new value of the Description field, or to leave unchanged. /// /// The current instance of this builder. - public VirtualParadiseModelObjectBuilder WithDescription(string? description) + public VirtualParadiseModelObjectBuilder WithDescription(Optional description) { Description = description; return this; @@ -101,7 +101,7 @@ public sealed class VirtualParadiseModelObjectBuilder : VirtualParadiseObjectBui /// /// The new value of the Model field, or to leave unchanged. /// The current instance of this builder. - public VirtualParadiseModelObjectBuilder WithModel(string? model) + public VirtualParadiseModelObjectBuilder WithModel(Optional model) { Model = model; return this; @@ -112,13 +112,13 @@ public sealed class VirtualParadiseModelObjectBuilder : VirtualParadiseObjectBui nint handle = Client.NativeInstanceHandle; var targetObject = (VirtualParadiseModelObject)TargetObject; - vp_string_set(handle, StringAttribute.ObjectModel, Model ?? targetObject.Model); - vp_string_set(handle, StringAttribute.ObjectDescription, Description ?? targetObject.Description); - vp_string_set(handle, StringAttribute.ObjectAction, Action ?? targetObject.Action); + vp_string_set(handle, StringAttribute.ObjectModel, Model.HasValue ? Model.Value! : targetObject.Model); + vp_string_set(handle, StringAttribute.ObjectDescription, Description.HasValue ? Description.Value! : targetObject.Description); + vp_string_set(handle, StringAttribute.ObjectAction, Action.HasValue ? Action.Value! : targetObject.Action); - if (Position is { } position) + if (Position.HasValue) { - (double x, double y, double z) = position; + (double x, double y, double z) = Position.Value; _ = vp_double_set(handle, FloatAttribute.ObjectX, x); _ = vp_double_set(handle, FloatAttribute.ObjectY, y); _ = vp_double_set(handle, FloatAttribute.ObjectZ, z); @@ -135,18 +135,18 @@ public sealed class VirtualParadiseModelObjectBuilder : VirtualParadiseObjectBui _ = vp_double_set(handle, FloatAttribute.ObjectZ, z); } - if (Rotation is null && Mode == ObjectBuilderMode.Create) + if (!Rotation.HasValue && Mode == ObjectBuilderMode.Create) { Rotation = Quaternion.Identity; } - if (Rotation is { } rotation) + if (Rotation.HasValue) { (double x, double y, double z) = Vector3d.Zero; double angle = double.PositiveInfinity; - if (rotation != Quaternion.Identity) + if (Rotation.Value != Quaternion.Identity) { - rotation.ToAxisAngle(out Vector3d axis, out angle); + Rotation.Value.ToAxisAngle(out Vector3d axis, out angle); (x, y, z) = axis; } @@ -164,28 +164,28 @@ public sealed class VirtualParadiseModelObjectBuilder : VirtualParadiseObjectBui _ = vp_double_set(handle, FloatAttribute.ObjectRotationAngle, angle); } - if (ModificationTimestamp is { } modificationTimestamp) + if (ModificationTimestamp.HasValue) { if (Mode != ObjectBuilderMode.Load) { throw new InvalidOperationException("Modification timestamp can only be assigned during an object load."); } - _ = vp_int_set(handle, IntegerAttribute.ObjectTime, (int)modificationTimestamp.ToUnixTimeSeconds()); + _ = vp_int_set(handle, IntegerAttribute.ObjectTime, (int)ModificationTimestamp.Value.ToUnixTimeSeconds()); } else { _ = vp_int_set(handle, IntegerAttribute.ObjectTime, (int)targetObject.ModificationTimestamp.ToUnixTimeSeconds()); } - if (Owner is { } owner) + if (Owner.HasValue) { if (Mode != ObjectBuilderMode.Load) { throw new InvalidOperationException("Owner can only be assigned during an object load."); } - _ = vp_int_set(handle, IntegerAttribute.ObjectUserId, owner.Id); + _ = vp_int_set(handle, IntegerAttribute.ObjectUserId, Owner.Value!.Id); } else { diff --git a/VpSharp/src/Entities/VirtualParadiseParticleEmitterObjectBuilder.cs b/VpSharp/src/Entities/VirtualParadiseParticleEmitterObjectBuilder.cs index d8d7983..4b02dcc 100644 --- a/VpSharp/src/Entities/VirtualParadiseParticleEmitterObjectBuilder.cs +++ b/VpSharp/src/Entities/VirtualParadiseParticleEmitterObjectBuilder.cs @@ -29,7 +29,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// The maximum acceleration, or to leave unchanged. [SerializationKey("acceleration_max")] [ValueConverter(typeof(Vector3dConverter))] - public Vector3d? AccelerationMax { get; set; } + public Optional AccelerationMax { get; set; } /// /// Gets or sets the minimum acceleration. @@ -37,7 +37,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// The minimum acceleration, or to leave unchanged. [SerializationKey("acceleration_min")] [ValueConverter(typeof(Vector3dConverter))] - public Vector3d? AccelerationMin { get; set; } + public Optional AccelerationMin { get; set; } /// /// Gets or sets the blend mode. @@ -45,7 +45,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// The blend mode, or to leave unchanged. [SerializationKey("blend")] [ValueConverter(typeof(StringToEnumConverter))] - public ParticleBlendMode? BlendMode { get; set; } + public Optional BlendMode { get; set; } /// /// Gets or sets the maximum color. @@ -53,7 +53,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// The maximum color, or to leave unchanged. [SerializationKey("color_max")] [ValueConverter(typeof(HexToColorConverter))] - public Color? ColorMax { get; set; } + public Optional ColorMax { get; set; } /// /// Gets or sets the minimum color. @@ -61,7 +61,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// The minimum color, or to leave unchanged. [SerializationKey("color_min")] [ValueConverter(typeof(HexToColorConverter))] - public Color? ColorMin { get; set; } + public Optional ColorMin { get; set; } /// /// Gets or sets the emitter lifespan. @@ -69,7 +69,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// The emitter lifespan, or to leave unchanged. [SerializationKey("emitter_lifespan")] [ValueConverter(typeof(MillisecondToTimeSpanConverter))] - public TimeSpan? EmitterLifespan { get; set; } + public Optional EmitterLifespan { get; set; } /// /// Gets or sets a value indicating whether this emitter interpolates its values. @@ -80,14 +80,14 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// [SerializationKey("interpolate")] [ValueConverter(typeof(IntToBoolConverter))] - public bool? Interpolate { get; set; } + public Optional Interpolate { get; set; } /// /// Gets or sets the opacity. /// /// The opacity, or to leave unchanged. [SerializationKey("opacity")] - public double? Opacity { get; set; } + public Optional Opacity { get; set; } /// /// Gets or sets the particle lifespan. @@ -95,7 +95,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// The particle lifespan, or to leave unchanged. [SerializationKey("particle_lifespan")] [ValueConverter(typeof(MillisecondToTimeSpanConverter))] - public TimeSpan? ParticleLifespan { get; set; } + public Optional ParticleLifespan { get; set; } /// /// Gets or sets the particle type. @@ -103,14 +103,14 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// The particle type, or to leave unchanged. [SerializationKey("particle_type")] [ValueConverter(typeof(StringToEnumConverter))] - public ParticleType? ParticleType { get; set; } + public Optional ParticleType { get; set; } /// /// Gets or sets the release count. /// /// The release count, or to leave unchanged. [SerializationKey("release_count")] - public int? ReleaseCount { get; set; } + public Optional ReleaseCount { get; set; } /// /// Gets or sets the release time. @@ -118,7 +118,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// The release time, or to leave unchanged. [SerializationKey("release_time")] [ValueConverter(typeof(MillisecondToTimeSpanConverter))] - public TimeSpan? ReleaseTime { get; set; } + public Optional ReleaseTime { get; set; } /// /// Gets or sets the maximum size. @@ -126,7 +126,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// The maximum size, or to leave unchanged. [SerializationKey("size_max")] [ValueConverter(typeof(Vector3dConverter))] - public Vector3d? SizeMax { get; set; } + public Optional SizeMax { get; set; } /// /// Gets or sets the minimum size. @@ -134,7 +134,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// The minimum size, or to leave unchanged. [SerializationKey("size_min")] [ValueConverter(typeof(Vector3dConverter))] - public Vector3d? SizeMin { get; set; } + public Optional SizeMin { get; set; } /// /// Gets or sets the maximum speed. @@ -142,7 +142,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// The maximum speed, or to leave unchanged. [SerializationKey("speed_max")] [ValueConverter(typeof(Vector3dConverter))] - public Vector3d? SpeedMax { get; set; } + public Optional SpeedMax { get; set; } /// /// Gets or sets the minimum speed. @@ -150,7 +150,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// The minimum speed, or to leave unchanged. [SerializationKey("speed_min")] [ValueConverter(typeof(Vector3dConverter))] - public Vector3d? SpeedMin { get; set; } + public Optional SpeedMin { get; set; } /// /// Gets or sets the maximum spin. @@ -158,7 +158,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// The maximum spin, or to leave unchanged. [SerializationKey("spin_max")] [ValueConverter(typeof(Vector3dConverter))] - public Vector3d? SpinMax { get; set; } + public Optional SpinMax { get; set; } /// /// Gets or sets the minimum spin. @@ -166,7 +166,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// The minimum spin, or to leave unchanged. [SerializationKey("spin_min")] [ValueConverter(typeof(Vector3dConverter))] - public Vector3d? SpinMin { get; set; } + public Optional SpinMin { get; set; } /// /// Gets or sets the maximum start angle. @@ -174,7 +174,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// The maximum start angle, or to leave unchanged. [SerializationKey("start_angle_max")] [ValueConverter(typeof(Vector3dConverter))] - public Vector3d? StartAngleMax { get; set; } + public Optional StartAngleMax { get; set; } /// /// Gets or sets the minimum start angle. @@ -182,7 +182,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// The minimum start angle, or to leave unchanged. [SerializationKey("start_angle_min")] [ValueConverter(typeof(Vector3dConverter))] - public Vector3d? StartAngleMin { get; set; } + public Optional StartAngleMin { get; set; } /// /// Gets or sets the maximum volume. @@ -190,7 +190,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// The maximum volume, or to leave unchanged. [SerializationKey("volume_max")] [ValueConverter(typeof(Vector3dConverter))] - public Vector3d? VolumeMax { get; set; } + public Optional VolumeMax { get; set; } /// /// Gets or sets the minimum volume. @@ -198,28 +198,28 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// The minimum volume, or to leave unchanged. [SerializationKey("volume_min")] [ValueConverter(typeof(Vector3dConverter))] - public Vector3d? VolumeMin { get; set; } + public Optional VolumeMin { get; set; } /// /// Gets or sets the tag. /// /// The tag, or to leave unchanged. [SerializationKey("tag")] - public string? Tag { get; set; } + public Optional Tag { get; set; } /// /// Gets or sets the texture. /// /// The texture, or to leave unchanged. [SerializationKey("texture")] - public string? Texture { get; set; } + public Optional Texture { get; set; } /// /// Sets the maximum volume. /// /// The maximum volume, or to leave unchanged. /// The current instance. - public VirtualParadiseParticleEmitterObjectBuilder WithAccelerationMax(Vector3d? value) + public VirtualParadiseParticleEmitterObjectBuilder WithAccelerationMax(Optional value) { AccelerationMax = value; return this; @@ -230,7 +230,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// /// The minimum acceleration, or to leave unchanged. /// The current instance. - public VirtualParadiseParticleEmitterObjectBuilder WithAccelerationMin(Vector3d? value) + public VirtualParadiseParticleEmitterObjectBuilder WithAccelerationMin(Optional value) { AccelerationMin = value; return this; @@ -241,7 +241,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// /// The blend mode, or to leave unchanged. /// The current instance. - public VirtualParadiseParticleEmitterObjectBuilder WithBlendMode(ParticleBlendMode? value) + public VirtualParadiseParticleEmitterObjectBuilder WithBlendMode(Optional value) { BlendMode = value; return this; @@ -252,7 +252,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// /// The maximum color, or to leave unchanged. /// The current instance. - public VirtualParadiseParticleEmitterObjectBuilder WithColorMax(Color? value) + public VirtualParadiseParticleEmitterObjectBuilder WithColorMax(Optional value) { ColorMax = value; return this; @@ -263,7 +263,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// /// The minimum color, or to leave unchanged. /// The current instance. - public VirtualParadiseParticleEmitterObjectBuilder WithColorMin(Color? value) + public VirtualParadiseParticleEmitterObjectBuilder WithColorMin(Optional value) { ColorMin = value; return this; @@ -274,7 +274,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// /// The emitter lifespan, or to leave unchanged. /// The current instance. - public VirtualParadiseParticleEmitterObjectBuilder WithEmitterLifespan(TimeSpan? value) + public VirtualParadiseParticleEmitterObjectBuilder WithEmitterLifespan(Optional value) { EmitterLifespan = value; return this; @@ -288,7 +288,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// to leave unchanged. /// /// The current instance. - public VirtualParadiseParticleEmitterObjectBuilder WithInterpolation(bool? value) + public VirtualParadiseParticleEmitterObjectBuilder WithInterpolation(Optional value) { Interpolate = value; return this; @@ -299,7 +299,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// /// The opacity, or to leave unchanged. /// The current instance. - public VirtualParadiseParticleEmitterObjectBuilder WithOpacity(double? value) + public VirtualParadiseParticleEmitterObjectBuilder WithOpacity(Optional value) { Opacity = value; return this; @@ -310,7 +310,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// /// The particle lifespan, or to leave unchanged. /// The current instance. - public VirtualParadiseParticleEmitterObjectBuilder WithParticleLifespan(TimeSpan? value) + public VirtualParadiseParticleEmitterObjectBuilder WithParticleLifespan(Optional value) { ParticleLifespan = value; return this; @@ -321,7 +321,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// /// The particle type, or to leave unchanged. /// The current instance. - public VirtualParadiseParticleEmitterObjectBuilder WithParticleType(ParticleType? value) + public VirtualParadiseParticleEmitterObjectBuilder WithParticleType(Optional value) { ParticleType = value; return this; @@ -332,7 +332,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// /// The release count, or to leave unchanged. /// The current instance. - public VirtualParadiseParticleEmitterObjectBuilder WithReleaseCount(int? value) + public VirtualParadiseParticleEmitterObjectBuilder WithReleaseCount(Optional value) { ReleaseCount = value; return this; @@ -343,7 +343,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// /// The release time, or to leave unchanged. /// The current instance. - public VirtualParadiseParticleEmitterObjectBuilder WithReleaseTime(TimeSpan? value) + public VirtualParadiseParticleEmitterObjectBuilder WithReleaseTime(Optional value) { ReleaseTime = value; return this; @@ -354,7 +354,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// /// The maximum size, or to leave unchanged. /// The current instance. - public VirtualParadiseParticleEmitterObjectBuilder WithSizeMax(Vector3d? value) + public VirtualParadiseParticleEmitterObjectBuilder WithSizeMax(Optional value) { SizeMax = value; return this; @@ -365,7 +365,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// /// The minimum size, or to leave unchanged. /// The current instance. - public VirtualParadiseParticleEmitterObjectBuilder WithSizeMin(Vector3d? value) + public VirtualParadiseParticleEmitterObjectBuilder WithSizeMin(Optional value) { SizeMin = value; return this; @@ -376,7 +376,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// /// The maximum speed, or to leave unchanged. /// The current instance. - public VirtualParadiseParticleEmitterObjectBuilder WithSpeedMax(Vector3d? value) + public VirtualParadiseParticleEmitterObjectBuilder WithSpeedMax(Optional value) { SpeedMax = value; return this; @@ -387,7 +387,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// /// The minimum speed, or to leave unchanged. /// The current instance. - public VirtualParadiseParticleEmitterObjectBuilder WithSpeedMin(Vector3d? value) + public VirtualParadiseParticleEmitterObjectBuilder WithSpeedMin(Optional value) { SpeedMin = value; return this; @@ -398,7 +398,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// /// The maximum spin, or to leave unchanged. /// The current instance. - public VirtualParadiseParticleEmitterObjectBuilder WithSpinMax(Vector3d? value) + public VirtualParadiseParticleEmitterObjectBuilder WithSpinMax(Optional value) { SpinMax = value; return this; @@ -409,7 +409,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// /// The minimum spin, or to leave unchanged. /// The current instance. - public VirtualParadiseParticleEmitterObjectBuilder WithSpinMin(Vector3d? value) + public VirtualParadiseParticleEmitterObjectBuilder WithSpinMin(Optional value) { SpinMin = value; return this; @@ -420,7 +420,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// /// The maximum start angle, or to leave unchanged. /// The current instance. - public VirtualParadiseParticleEmitterObjectBuilder WithStartAngleMax(Vector3d? value) + public VirtualParadiseParticleEmitterObjectBuilder WithStartAngleMax(Optional value) { StartAngleMax = value; return this; @@ -431,7 +431,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// /// The minimum start angle, or to leave unchanged. /// The current instance. - public VirtualParadiseParticleEmitterObjectBuilder WithStartAngleMin(Vector3d? value) + public VirtualParadiseParticleEmitterObjectBuilder WithStartAngleMin(Optional value) { StartAngleMin = value; return this; @@ -442,7 +442,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// /// The maximum volume, or to leave unchanged. /// The current instance. - public VirtualParadiseParticleEmitterObjectBuilder WithVolumeMax(Vector3d? value) + public VirtualParadiseParticleEmitterObjectBuilder WithVolumeMax(Optional value) { VolumeMax = value; return this; @@ -453,7 +453,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// /// The minimum volume, or to leave unchanged. /// The current instance. - public VirtualParadiseParticleEmitterObjectBuilder WithVolumeMin(Vector3d? value) + public VirtualParadiseParticleEmitterObjectBuilder WithVolumeMin(Optional value) { VolumeMin = value; return this; @@ -464,7 +464,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// /// The tag, or to leave unchanged. /// The current instance. - public VirtualParadiseParticleEmitterObjectBuilder WithTag(string? value) + public VirtualParadiseParticleEmitterObjectBuilder WithTag(Optional value) { Tag = value; return this; @@ -475,7 +475,7 @@ public sealed class VirtualParadiseParticleEmitterObjectBuilder : VirtualParadis /// /// The texture, or to leave unchanged. /// The current instance. - public VirtualParadiseParticleEmitterObjectBuilder WithTexture(string? value) + public VirtualParadiseParticleEmitterObjectBuilder WithTexture(Optional value) { Texture = value; return this; diff --git a/VpSharp/src/Optional.cs b/VpSharp/src/Optional.cs new file mode 100644 index 0000000..1a9fe55 --- /dev/null +++ b/VpSharp/src/Optional.cs @@ -0,0 +1,108 @@ +namespace VpSharp; + +#pragma warning disable CA1716 +#pragma warning disable CA2225 + +/// +/// Represents an optional value. +/// +/// The type of the value. +public readonly struct Optional : IEquatable> +{ + private readonly T? _value; + + /// + /// Initializes a new instance of the struct. + /// + /// + public Optional(T? value) + { + HasValue = true; + _value = value; + } + + /// + /// Gets a value indicating whether this has a value. + /// + /// if a value is defined; otherwise, . + public bool HasValue { get; } + + /// + /// Gets the underlying value of this optional. + /// + /// The value. + public T? Value + { + get + { + if (!HasValue) + { + throw new InvalidOperationException("Cannot access the value of a valueless optional."); + } + + return _value; + } + } + + /// + /// Returns a value indicating whether two instances of are equal. + /// + /// The first . + /// The second . + /// if the two instances are equal; otherwise, . + public static bool operator ==(Optional left, Optional right) + { + return left.Equals(right); + } + + /// + /// Returns a value indicating whether two instances of are not equal. + /// + /// The first . + /// The second . + /// if the two instances are not equal; otherwise, . + public static bool operator !=(Optional left, Optional right) + { + return !left.Equals(right); + } + + /// + /// Implicitly converts a value to a new instance of . + /// + /// A new instance of , wrapping . + public static implicit operator Optional(T? value) + { + return new Optional(value); + } + + /// + /// Implicitly converts a value to a new instance of . + /// + /// A new instance of , wrapping . + public static explicit operator T?(Optional value) + { + return value.Value; + } + + /// + /// Returns a value indicating whether this and another are equal. + /// + /// The other . + /// if the two instances are equal; otherwise, . + public bool Equals(Optional other) + { + return HasValue == other.HasValue && EqualityComparer.Default.Equals(Value, other._value); + } + + /// + public override bool Equals(object? obj) + { + return obj is Optional other && Equals(other); + } + + /// + public override int GetHashCode() + { + return HashCode.Combine(HasValue, Value); + } +}