Skip to content
This repository has been archived by the owner on Apr 10, 2024. It is now read-only.

Commit

Permalink
Add SerializableDictionary.cs and SerializedType.cs
Browse files Browse the repository at this point in the history
  • Loading branch information
uurha committed Feb 27, 2024
1 parent 0e493fe commit 6acbc62
Show file tree
Hide file tree
Showing 14 changed files with 675 additions and 32 deletions.
60 changes: 56 additions & 4 deletions Runtime/Properties/ReactiveProperty.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,21 @@

namespace Better.DataStructures.Properties
{
/// <summary>
/// A reactive property that notifies subscribers about changes to its value.
/// </summary>
/// <typeparam name="T">The type of the value.</typeparam>
[Serializable]
public class ReactiveProperty<T>
{
public event Action<T> ValueChangedEvent;
private event Action<T> ValueChangedEvent;
private ReadOnlyReactiveProperty<T> _cachedReadOnly;

[SerializeField]
protected T _value;
[SerializeField] protected T _value;

/// <summary>
/// Gets or sets the value of the property. Setting the value notifies all subscribers about the change.
/// </summary>
public T Value
{
get => _value;
Expand All @@ -21,14 +28,59 @@ public T Value
}
}

/// <summary>
/// Initializes a new instance of the ReactiveProperty class with an optional default value.
/// </summary>
/// <param name="defaultValue">The initial value of the property.</param>
public ReactiveProperty(T defaultValue = default)
{
_value = defaultValue;
}

/// <summary>
/// Notifies subscribers about a change to the property's value.
/// </summary>
public virtual void SetDirty()
{
ValueChangedEvent?.Invoke(Value);
}

/// <summary>
/// Subscribes a callback action to be invoked when the property's value changes.
/// </summary>
/// <param name="action">The callback action to invoke on value change.</param>
public virtual void Subscribe(Action<T> action)
{
ValueChangedEvent += action;
}

/// <summary>
/// Subscribes a callback action to be invoked immediately and also when the property's value changes in the future.
/// </summary>
/// <param name="action">The callback action to invoke.</param>
public virtual void SubscribeWithInvoke(Action<T> action)
{
Subscribe(action);
action?.Invoke(Value);
}

/// <summary>
/// Unsubscribes a previously subscribed callback action from being invoked when the property's value changes.
/// </summary>
/// <param name="action">The callback action to unsubscribe.</param>
public virtual void Unsubscribe(Action<T> action)
{
ValueChangedEvent -= action;
}

/// <summary>
/// Gets a read-only version of the ReactiveProperty, which can be exposed publicly to prevent external modifications.
/// </summary>
/// <returns>A ReadOnlyReactiveProperty encapsulating the read-only view of this ReactiveProperty.</returns>
public ReadOnlyReactiveProperty<T> AsReadOnly()
{
_cachedReadOnly ??= new ReadOnlyReactiveProperty<T>(this);
return _cachedReadOnly;
}
}
}
}
46 changes: 46 additions & 0 deletions Runtime/Properties/ReadOnlyReactiveProperty.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;

namespace Better.DataStructures.Properties
{
/// <summary>
/// Represents a read-only wrapper around a ReactiveProperty, allowing subscription to value changes without the ability to modify the value.
/// </summary>
/// <typeparam name="T">The type of the value.</typeparam>
[Serializable]
public sealed class ReadOnlyReactiveProperty<T>
{
private readonly ReactiveProperty<T> _source;

/// <summary>
/// Gets the current value of the underlying ReactiveProperty.
/// </summary>
public T Value => _source.Value;

/// <summary>
/// Initializes a new instance of the ReadOnlyReactiveProperty class with a ReactiveProperty as its source.
/// </summary>
/// <param name="source">The ReactiveProperty to encapsulate in a read-only manner.</param>
public ReadOnlyReactiveProperty(ReactiveProperty<T> source)
{
_source = source;
}

/// <summary>
/// Subscribes a callback action to be invoked when the underlying ReactiveProperty's value changes.
/// </summary>
/// <param name="action">The callback action to invoke on value change.</param>
public void Subscribe(Action<T> action) => _source.Subscribe(action);

/// <summary>
/// Subscribes a callback action to be invoked immediately with the current value, and also when the underlying ReactiveProperty's value changes in the future.
/// </summary>
/// <param name="action">The callback action to invoke.</param>
public void SubscribeWithInvoke(Action<T> action) => _source.SubscribeWithInvoke(action);

/// <summary>
/// Unsubscribes a previously subscribed callback action from being invoked when the underlying ReactiveProperty's value changes.
/// </summary>
/// <param name="action">The callback action to unsubscribe.</param>
public void Unsubscribe(Action<T> action) => _source.Unsubscribe(action);
}
}
3 changes: 3 additions & 0 deletions Runtime/Properties/ReadOnlyReactiveProperty.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

94 changes: 78 additions & 16 deletions Runtime/Ranges/Range.cs
Original file line number Diff line number Diff line change
@@ -1,62 +1,124 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Serialization;

namespace Better.DataStructures.Ranges
{
/// <summary>
/// Represents a range with minimum and maximum values of a generic type.
/// </summary>
/// <typeparam name="T">The type of the values defining the range.</typeparam>
[Serializable]
public class Range<T> : IEquatable<Range<T>>
{
[SerializeField] private T min;
[SerializeField] private T max;
[FormerlySerializedAs("min")] [SerializeField] private T _min;
[FormerlySerializedAs("max")] [SerializeField] private T _max;

/// <summary>
/// Initializes a new instance of the Range class with default minimum and maximum values.
/// </summary>
public Range()
{
min = default;
max = default;
_min = default;
_max = default;
}

/// <summary>
/// Initializes a new instance of the Range class by copying another range.
/// </summary>
/// <param name="range">The range to copy.</param>
public Range(Range<T> range)
{
_min = range.Min;
_max = range.Max;
}

/// <summary>
/// Initializes a new instance of the Range class with specified minimum and maximum values.
/// </summary>
/// <param name="min">The minimum value of the range.</param>
/// <param name="max">The maximum value of the range.</param>
public Range(T min, T max)
{
this.min = min;
this.max = max;
_min = min;
_max = max;
}

public T Min => min;
/// <summary>
/// Gets the minimum value of the range.
/// </summary>
public T Min => _min;

public T Max => max;
/// <summary>
/// Gets the maximum value of the range.
/// </summary>
public T Max => _max;

/// <summary>
/// Determines whether the specified Range is equal to the current Range.
/// </summary>
/// <param name="other">The Range to compare with the current Range.</param>
/// <returns>true if the specified Range is equal to the current Range; otherwise, false.</returns>
public bool Equals(Range<T> other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return EqualityComparer<T>.Default.Equals(min, other.min) && EqualityComparer<T>.Default.Equals(max, other.max);
return EqualityComparer<T>.Default.Equals(_min, other._min) && EqualityComparer<T>.Default.Equals(_max, other._max);
}

/// <summary>
/// Determines whether the specified object is equal to the current Range.
/// </summary>
/// <param name="obj">The object to compare with the current Range.</param>
/// <returns>true if the specified object is equal to the current Range; otherwise, false.</returns>
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
if (obj.GetType() != GetType()) return false;
return Equals((Range<T>)obj);
}

public Range<T> UpdateMax(T maxValue)
/// <summary>
/// Creates a new instance of the Range that is a copy of the current Range.
/// </summary>
/// <returns>A new Range instance that is a copy of this Range.</returns>
public Range<T> Copy()
{
return new Range<T>(_min, _max);
}

/// <summary>
/// Creates a new instance of the Range with the same minimum value as this instance and a new maximum value.
/// </summary>
/// <param name="maxValue">The new maximum value for the range.</param>
/// <returns>A new Range instance with the updated maximum value while retaining the original minimum value.</returns>
public Range<T> CopyWithMax(T maxValue)
{
return new Range<T>(min, maxValue);
return new Range<T>(_min, maxValue);
}

public Range<T> UpdateMin(T minValue)
/// <summary>
/// Creates a new instance of the Range with the same maximum value as this instance and a new minimum value.
/// </summary>
/// <param name="minValue">The new minimum value for the range.</param>
/// <returns>A new Range instance with the updated minimum value while retaining the original maximum value.</returns>
public Range<T> CopyWithMin(T minValue)
{
return new Range<T>(minValue, max);
return new Range<T>(minValue, _max);
}

/// <summary>
/// Serves as the default hash function.
/// </summary>
/// <returns>A hash code for the current Range.</returns>
public override int GetHashCode()
{
unchecked
{
return (EqualityComparer<T>.Default.GetHashCode(min) * 397) ^ EqualityComparer<T>.Default.GetHashCode(max);
return (EqualityComparer<T>.Default.GetHashCode(_min) * 397) ^ EqualityComparer<T>.Default.GetHashCode(_max);
}
}
}
}
}
Loading

0 comments on commit 6acbc62

Please sign in to comment.