-
Notifications
You must be signed in to change notification settings - Fork 69
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #334 from AvaloniaCommunity/removeSystemReactive
Remove System.Reactive dependency
- Loading branch information
Showing
11 changed files
with
316 additions
and
107 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
using System; | ||
|
||
namespace Material.Styles.Internal; | ||
|
||
/// <summary> | ||
/// Provides a set of static methods for creating <see cref="IDisposable"/> objects. | ||
/// </summary> | ||
internal static class Disposable { | ||
/// <summary> | ||
/// Gets the disposable that does nothing when disposed. | ||
/// </summary> | ||
public static IDisposable Empty => EmptyDisposable.Instance; | ||
|
||
/// <summary> | ||
/// Represents a disposable that does nothing on disposal. | ||
/// </summary> | ||
private sealed class EmptyDisposable : IDisposable { | ||
public static readonly EmptyDisposable Instance = new(); | ||
|
||
private EmptyDisposable() { } | ||
|
||
public void Dispose() { | ||
// no op | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Threading; | ||
|
||
namespace Material.Styles.Internal; | ||
|
||
/// <summary> | ||
/// Lightweight base class for observable implementations. | ||
/// </summary> | ||
/// <typeparam name="T">The observable type.</typeparam> | ||
/// <remarks> | ||
/// ObservableBase{T} is rather heavyweight in terms of allocations and memory | ||
/// usage. This class provides a more lightweight base for some internal observable types | ||
/// in the Avalonia framework. | ||
/// </remarks> | ||
internal abstract class LightweightObservableBase<T> : IObservable<T> { | ||
private Exception? _error; | ||
private List<IObserver<T>>? _observers = new(); | ||
|
||
public bool HasObservers => _observers?.Count > 0; | ||
|
||
public IDisposable Subscribe(IObserver<T> observer) { | ||
_ = observer ?? throw new ArgumentNullException(nameof(observer)); | ||
|
||
//Dispatcher.UIThread.VerifyAccess(); | ||
|
||
var first = false; | ||
|
||
for (;;) { | ||
if (Volatile.Read(ref _observers) == null) { | ||
if (_error != null) | ||
observer.OnError(_error); | ||
else | ||
observer.OnCompleted(); | ||
|
||
return Disposable.Empty; | ||
} | ||
|
||
lock (this) { | ||
if (_observers == null) continue; | ||
|
||
first = _observers.Count == 0; | ||
_observers.Add(observer); | ||
break; | ||
} | ||
} | ||
|
||
if (first) Initialize(); | ||
|
||
Subscribed(observer, first); | ||
|
||
return new RemoveObserver(this, observer); | ||
} | ||
|
||
private void Remove(IObserver<T> observer) { | ||
if (Volatile.Read(ref _observers) != null) { | ||
lock (this) { | ||
var observers = _observers; | ||
|
||
if (observers != null) { | ||
observers.Remove(observer); | ||
|
||
if (observers.Count == 0) { | ||
observers.TrimExcess(); | ||
Deinitialize(); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
protected abstract void Initialize(); | ||
protected abstract void Deinitialize(); | ||
|
||
protected void PublishNext(T value) { | ||
if (Volatile.Read(ref _observers) != null) { | ||
IObserver<T>[]? observers = null; | ||
IObserver<T>? singleObserver = null; | ||
lock (this) { | ||
if (_observers == null) return; | ||
if (_observers.Count == 1) | ||
singleObserver = _observers[0]; | ||
else | ||
observers = _observers.ToArray(); | ||
} | ||
if (singleObserver != null) | ||
singleObserver.OnNext(value); | ||
else { | ||
foreach (var observer in observers!) observer.OnNext(value); | ||
} | ||
} | ||
} | ||
|
||
protected void PublishCompleted() { | ||
if (Volatile.Read(ref _observers) != null) { | ||
IObserver<T>[] observers; | ||
|
||
lock (this) { | ||
if (_observers == null) return; | ||
observers = _observers.ToArray(); | ||
Volatile.Write(ref _observers, null); | ||
} | ||
|
||
foreach (var observer in observers) observer.OnCompleted(); | ||
|
||
Deinitialize(); | ||
} | ||
} | ||
|
||
protected void PublishError(Exception error) { | ||
if (Volatile.Read(ref _observers) != null) { | ||
|
||
IObserver<T>[] observers; | ||
|
||
lock (this) { | ||
if (_observers == null) return; | ||
|
||
_error = error; | ||
observers = _observers.ToArray(); | ||
Volatile.Write(ref _observers, null); | ||
} | ||
|
||
foreach (var observer in observers) observer.OnError(error); | ||
|
||
Deinitialize(); | ||
} | ||
} | ||
|
||
protected virtual void Subscribed(IObserver<T> observer, bool first) { } | ||
|
||
private sealed class RemoveObserver : IDisposable { | ||
private IObserver<T>? _observer; | ||
private LightweightObservableBase<T>? _parent; | ||
|
||
public RemoveObserver(LightweightObservableBase<T> parent, IObserver<T> observer) { | ||
_parent = parent; | ||
Volatile.Write(ref _observer, observer); | ||
} | ||
|
||
public void Dispose() { | ||
var observer = _observer; | ||
Interlocked.Exchange(ref _parent, null)?.Remove(observer!); | ||
_observer = null; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using System; | ||
|
||
namespace Material.Styles.Internal; | ||
|
||
internal class LightweightSubject<T> : LightweightObservableBase<T> { | ||
public void OnCompleted() { | ||
PublishCompleted(); | ||
} | ||
|
||
public void OnError(Exception error) { | ||
PublishError(error); | ||
} | ||
|
||
public void OnNext(T value) { | ||
PublishNext(value); | ||
} | ||
|
||
protected override void Initialize() { } | ||
|
||
protected override void Deinitialize() { } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
using System; | ||
using Avalonia.Reactive; | ||
|
||
namespace Material.Styles.Internal; | ||
|
||
internal static class Observable { | ||
public static IDisposable Subscribe<T>(this IObservable<T> source, Action<T> action) { | ||
return source.Subscribe(new AnonymousObserver<T>(action)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.