using Ryujinx.Common.Logging; using System; using System.Globalization; using System.Threading; namespace Ryujinx.Common { public class ReactiveObject { private readonly ReaderWriterLockSlim _rwLock = new(); private bool _isInitialized; private T _value; public event EventHandler> Event; public T Value { get { _rwLock.EnterReadLock(); T value = _value; _rwLock.ExitReadLock(); return value; } set { _rwLock.EnterWriteLock(); T oldValue = _value; bool oldIsInitialized = _isInitialized; _isInitialized = true; _value = value; _rwLock.ExitWriteLock(); if (!oldIsInitialized || oldValue == null || !oldValue.Equals(_value)) { Event?.Invoke(this, new ReactiveEventArgs(oldValue, value)); } } } public void LogChangesToValue(string valueName, LogClass logClass = LogClass.Configuration) => Event += (_, e) => ReactiveObjectHelper.LogValueChange(logClass, e, valueName); public static implicit operator T(ReactiveObject obj) => obj.Value; } public static class ReactiveObjectHelper { public static void LogValueChange(LogClass logClass, ReactiveEventArgs eventArgs, string valueName) { string message = string.Create(CultureInfo.InvariantCulture, $"{valueName} set to: {eventArgs.NewValue}"); Logger.Info?.Print(logClass, message); } public static void Toggle(this ReactiveObject rBoolean) => rBoolean.Value = !rBoolean.Value; } public class ReactiveEventArgs(T oldValue, T newValue) { public T OldValue { get; } = oldValue; public T NewValue { get; } = newValue; } }