Git Product home page Git Product logo

r3's People

Contributors

aetos382 avatar aixacode avatar aneuf-tech avatar c3-hoge-fuga-piyo avatar chocola-mint avatar enue avatar github-actions[bot] avatar guitarrapc avatar hadashia avatar itn3000 avatar karthikr-vti avatar kochounoyume avatar maxkatz6 avatar mayuki avatar michaelstonis avatar neuecc avatar torisoup avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

r3's Issues

The behavior of `ThrottleFirst`/`ThrottleFirstFrame` is not consistent with UniRx

I found that the behavior of ThrottleFirst/ThrottleFirstFrame is not consistent with UniRx.

ThrottleFirst/ThrottleFirstFrame of R3 does not emit a value until timeSpan/frameCount has elapsed, even if it is the first value, while those of UniRx does not wait for timeSpan/frameCount when emitting the first value.

var startingTime = DateTime.Now;
Observable.Timer(TimeSpan.FromMilliseconds(100), TimeSpan.FromMilliseconds(100))
    .ThrottleFirst(TimeSpan.FromSeconds(2))
    .Subscribe(_ => Console.WriteLine((DateTime.Now - startingTime).TotalSeconds));

// 2.0087288
// 4.005542
// 6.0163164
// ...

The related test also assumes this behavior, and is this the expected?

This behavior makes it difficult to use for purpose that, for example, prevent double UI input...

ReactiveProperty<T>.SetValue() is missing?

I'm currently trying out R3 by replacing UniRx in my existing Unity project.

The project has a class that inherits from ReactiveProperty<T> as follows.
In R3, I cannot implement this because there is no way to set currentValue from a child class.

/// <summary>
/// ReactiveProperty whose set value is clamped in the range of [min, max].
/// </summary>
public sealed class ClampedReactiveProperty<T> : ReactiveProperty<T> where T : IComparable<T>
{
    private readonly T min, max;

    public ClampedReactiveProperty(T initialValue, T min, T max) : base(initialValue)
    {
        this.min = min;
        this.max = max;
    }

    // XXX: I cannot override this in R3!!!
    protected override void SetValue(T value)
    {
        if (Comparer.Compare(value, min) < 0) base.SetValue(min);
        else if (Comparer.Compare(value, max) > 0) base.SetValue(max);
        else base.SetValue(value);
    }

    private static IComparer<T> Comparer { get; } = Comparer<T>.Default;
}

By the way, do you plan to implment abstract ReactiveProperty<T> to substitute UniRx's IReactiveProperty<T>?
It would allow me to implement my own ClampedReactiveProperty even if ReactiveProperty<T>.SetValue() is missing.

My project contains several classes that implement IReadOnlyReactiveProperty<T> and I have successfully replaced them all with ReadOnlyReactiveProperty<T>.
Is there any reason why there is no abstract ReactiveProperty<T>?

Bug: Unity Enter Play Mode Options

When I use Enter Play Mode Options and run following code error is throwed on play mode ends.

 Observable.Interval(TimeSpan.FromSeconds(1)).Timeout(TimeSpan.FromSeconds(5))
      .Subscribe(x =>
      {
          Debug.Log("Time:" + time);
      });
ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
System.Span`1[T]..ctor (R3.IFrameRunnerWorkItem[] array, System.Int32 start, System.Int32 length) (at <17d9ce77f27a4bd2afb5ba32c9bea976>:0)
System.MemoryExtensions.AsSpan[T] (T[] array, System.Int32 start, System.Int32 length) (at <17d9ce77f27a4bd2afb5ba32c9bea976>:0)
R3.Collections.FreeListCore`1[T].Clear (System.Boolean removeArray) (at <2193946fd82a4f61aea525782e26cd9d>:0)
R3.UnityFrameProvider.Clear () (at ./Library/PackageCache/com.cysharp.r3@050f4f78fe/Runtime/UnityFrameProvider.cs:73)
R3.PlayerLoopHelper+<>c__DisplayClass8_0.<InsertRunner>b__0 (UnityEditor.PlayModeStateChange state) (at ./Library/PackageCache/com.cysharp.r3@050f4f78fe/Runtime/PlayerLoopHelper.cs:121)
UnityEditor.EditorApplication.Internal_PlayModeStateChanged (UnityEditor.PlayModeStateChange state) (at <5e6ebaa7d75c4d5399dc81ecead6b43f>:0)

Then, if I restart PlayMode again, following error is throwed every frame.

ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
System.Span`1[T]..ctor (R3.IFrameRunnerWorkItem[] array, System.Int32 start, System.Int32 length) (at <17d9ce77f27a4bd2afb5ba32c9bea976>:0)
System.MemoryExtensions.AsSpan[T] (T[] array, System.Int32 start, System.Int32 length) (at <17d9ce77f27a4bd2afb5ba32c9bea976>:0)
R3.Collections.FreeListCore`1[T].AsSpan () (at <2193946fd82a4f61aea525782e26cd9d>:0)
R3.UnityFrameProvider.Run () (at ./Library/PackageCache/com.cysharp.r3@050f4f78fe/Runtime/UnityFrameProvider.cs:45)

ReactiveCollection

UniRx had a class called ReactiveCollection. Does or will R3 have this as well?

Delta time in R3.Godot

In Godot, there is no direct equivalent to Unity's Time.deltaTime, and we use the delta parameter of the _Process or _PhysicsProcess method.

Currently, in R3, there is no straightforward way to access delta.

GodotFrameProvider and FrameProviderDispatcher store the value as StrongBox<double>, and I would appreciate it being exposed through some means.

Feedback: ReadOnlyReactiveProperty<T> is a fairly long name

I was toying with adopting a reactive style using R3, and I found myself using reactive properties everywhere. To ensure encapsulation we need to use the read only variant. For something used so often, I found that "ReadOnlyReactiveProperty" is an uncomfortably long name.

Since R3 uses abstract base classes, it becomes tricky to wrap it in something like "ICell" or "IReactive" without losing all the extension methods.

This is just a personal observation from someone trying to adopt R3. I don't know the correct approach to this problem. Keeping the descriptive name makes sense for many reasons, but as as user I wish we could have something shorter.

[Request] Alternative implementation of AsyncReactiveCommand

This may overlap with the story #86 , but I would like to do the simultaneous control of multiple UIs in R3, which was possible with the use of AsyncReactiveCommand in UniRx.

Drop for SelectAwait/WhereAwait/SubscribeAwait is basically a recognition that controls a single Observable, which is also useful, but falls one step short of the functionality we want.

AsyncReactiveCommand which exists in UniRx was implemented in the form of returning IObservable, but I personally hope that R3, which is highly compatible with async/await, will be implemented with a structure using async/await.

Wrapping ReactiveProperty throws "InvalidOperationException: Disposable is already assigned" when subscribing

I was prototyping some ideas and wanted write a ReadOnlyReactiveProperty variant that can be overridden (a sort of public setter). Since in R3 we have no interfaces, I needed to inherit from ReadOnlyReactiveProperty while wrapping another ReactiveProperty as shown in the code beneath.

When trying to subscribe to Overridable, it throws "InvalidOperationException: Disposable is already assigned". Are we not meant to wrap the classes, or is this a bug?

public sealed class Overridable<T> : ReadOnlyReactiveProperty<T>, IOverridable<T>
    {
        public override T CurrentValue => _property.CurrentValue;

        private readonly ReactiveProperty<T> _property;
        private readonly T _baseValue;
        private readonly List<OverrideEntry> _overrides;

        private class OverrideEntry
        {
            public int Priority { get; }
            public Func<T, T> Func { get; }
            public int InsertionOrder { get; }

            public OverrideEntry(int priority, Func<T, T> func, int insertionOrder)
            {
                Priority = priority;
                Func = func;
                InsertionOrder = insertionOrder;
            }
        }

        public Overridable(T value)
        {
            _baseValue = value;
            _property = new ReactiveProperty<T>(value);
            _overrides = new List<OverrideEntry>();
        }

        protected override IDisposable SubscribeCore(Observer<T> observer)
        {
            return _property.Subscribe(observer);
        }

        public override void Dispose()
        {
            _property.Dispose();
        }

        public IDisposable Override(Func<T, T> func, int priority = 0)
        {
            var insertionOrder = _overrides.Any() ? _overrides.Max(o => o.InsertionOrder) + 1 : 0;
            var entry = new OverrideEntry(priority, func, insertionOrder);
            _overrides.Add(entry);
            _overrides.Sort((x, y) => x.Priority != y.Priority ? x.Priority.CompareTo(y.Priority) : x.InsertionOrder.CompareTo(y.InsertionOrder));
            UpdateCurrentValue();

            return Disposable.Create(() =>
            {
                _overrides.Remove(entry);
                UpdateCurrentValue();
            });
        }

        private T CalculateCurrentValue()
        {
            return _overrides.Aggregate(_baseValue, (current, entry) => entry.Func(current));
        }

        private void UpdateCurrentValue()
        {
            _property.Value = CalculateCurrentValue();
        }
    }

Error Log:

InvalidOperationException: Disposable is already assigned.

R3.SingleAssignmentDisposableCore.ThrowAlreadyAssignment () (at <9e98c8d55c734e6b90c287e63a55ae85>:0)

R3.SingleAssignmentDisposableCore.set_Disposable (System.IDisposable value) (at <9e98c8d55c734e6b90c287e63a55ae85>:0)

R3.Observable`1[T].Subscribe (R3.Observer`1[T] observer) (at <9e98c8d55c734e6b90c287e63a55ae85>:0)

R3.ObservableSubscribeExtensions.Subscribe[T] (R3.Observable`1[T] source, System.Action`1[T] onNext) (at <9e98c8d55c734e6b90c287e63a55ae85>:0)

Not working releasing event subscription of Observable.Amb()

We noticed this behavior while working with Unity, but since the problem was not specifically dependent on a package for Unity, we prepared the sample code in pure C#.

(Forgive me if I've written this in a messy way.)

using R3;

public static class Test
{
    public static event Action OnTest1ed;

    public static Observable<Unit> Test1Observable()
        => Observable.FromEvent(h => OnTest1ed += h, h => OnTest1ed -= h);

    public static event Action OnTest2ed;

    public static Observable<Unit> Test2Observable()
        => Observable.FromEvent(h => OnTest2ed += h, h => OnTest2ed -= h);

    public static void Main()
    {
        Observable.Amb(
                Test1Observable().Do(_ => Console.WriteLine("Test1ed")).Select(_ => 1),
                Test2Observable().Do(_ => Console.WriteLine("Test2ed")).Select(_ => 2))
            .Take(1)
            .Subscribe(value => Console.WriteLine($"Subscription:{value}"));

        OnTest2ed?.Invoke();
        OnTest2ed?.Invoke();
    }
}

The results of this program are as follows:

Test2ed       
Subscription:2
Test2ed  

Indeed, the subscription process itself is executed only once, as specified, but the process specified in Do remains in the event.

SelectMany does not notify OnCompleted

Tested Ver.0.1.14 with .NET 8.0:

using R3;

Console.WriteLine("start");

Observable.Range(1, 2)
    .SelectMany(i => Observable.Return(i * 2))
    .Subscribe(onNext: Console.WriteLine,
               onCompleted: _ => Console.WriteLine("onCompleted"));

Console.WriteLine("end");

Output:

start
2
4
end

`SerializableReactiveProperty<T>` OnNext call in `OnAfterDeserialize` is problematic

Calling OnNext in OnAfterDeserialize causes issues because many Unity operations cannot be called from that execution path. For example:

UnityException: SetFloatImpl is not allowed to be called during serialization, call it from OnEnable instead.

or

UnityException: set_localRotation is not allowed to be called during serialization, call it from OnEnable instead. 

Implement Operators

dotnet/reactive

  • Aggregate
  • All
  • Amb
    - [ ] And
  • Any
  • Append
  • AsObservable
    - [ ] AutoConnect
  • Average
  • Buffer -> Chunk
    - [ ] Case
  • Cast
  • Catch
    - [ ] Chunkify
    - [ ] Collect
  • CombineLatest
  • Concat
  • Contains
  • Count(CountAsync)
  • Create
  • DefaultIfEmpty
  • Defer
    - [ ] DeferAsync
  • Delay
  • DelaySubscription
  • Dematerialize
  • Distinct
  • DistinctUntilChanged
  • Do
    - [ ] DoWhile
  • ElementAt
  • ElementAtOrDefault
  • Empty
    - [ ] Finally
  • First
  • FirstAsync
  • FirstOrDefault
  • FirstOrDefaultAsync
    - [ ] For
    - [ ] ForEach
  • ForEachAsync
    - [ ] FromAsync
    - [ ] FromAsyncPattern
  • FromEvent
  • FromEventPattern
    - [ ] Generate
    - [ ] GetAwaiter
    - [ ] GetEnumerator
    - [ ] GroupBy
    - [ ] GroupByUntil
    - [ ] GroupJoin
    - [ ] If
  • IgnoreElements
  • Interval
  • IsEmpty
    - [ ] Join
  • Last
  • LastAsync
  • LastOrDefault
  • LastOrDefaultAsync
    - [ ] Latest
  • LongCount
  • Materialize
  • Max
  • MaxBy
  • Merge
  • Min
  • MinBy
    - [ ] MostRecent
  • Multicast
  • Never
    - [ ] Next
  • ObserveOn
  • OfType
    - [ ] OnErrorResumeNext
  • Prepend
  • Publish
    - [ ] PublishLast
  • Range
  • RefCount
  • Repeat
    - [ ] RepeatWhen
  • Replay
    - [ ] Retry
    - [ ] RetryWhen
  • Return
    - [ ] RunAsync
  • Sample
  • Scan
  • Select
  • SelectMany
  • SequenceEqual
  • Single
  • SingleAsync
  • SingleOrDefault
  • SingleOrDefaultAsync
  • Skip
  • SkipLast
  • SkipUntil
  • SkipWhile
    - [ ] Start
    - [ ] StartAsync
    - [ ] StartWith
  • Subscribe
  • SubscribeOn
  • Sum
  • Switch
  • Synchronize
  • Take
  • TakeLast
    - [ ] TakeLastBuffer
  • TakeUntil
  • TakeWhile
    - [ ] Then
  • Throttle
  • Throw
    - [ ] TimeInterval
  • Timeout
  • Timer
    - [ ] Timestamp
  • ToArray
    - [ ] ToAsync
  • ToDictionary
    - [ ] ToEnumerable
    - [ ] ToEvent
    - [ ] ToEventPattern
  • ToList
  • ToLookup
  • ToObservable
    - [ ] Using
    - [ ] Wait
    - [ ] When
  • Where
    - [ ] While
    - [ ] Window
  • WithLatestFrom
  • Zip

UniRx

- [ ] AsSingleUnitObservable

  • AsUnitObservable
    - [ ] BatchFrame
    - [ ] CatchIgnore
    - [ ] ContinueWith
    - [ ] CreateSafe
    - [ ] CreateWithState
  • DelayFrame
  • DelayFrameSubscription
    - [ ] DoOnCancel
    - [ ] DoOnCompleted
    - [ ] DoOnError
    - [ ] DoOnSubscribe
    - [ ] DoOnTerminate
    - [ ] EveryAfterUpdate
    - [ ] EveryApplicationFocus
    - [ ] EveryApplicationPause
    - [ ] EveryEndOfFrame
    - [ ] EveryFixedUpdate
    - [ ] EveryGameObjectUpdate
    - [ ] EveryLateUpdate
  • EveryUpdate
    - [ ] FrameInterval
    - [ ] FrameTimeInterval
    - [ ] FromCoroutine
    - [ ] FromCoroutineValue
    - [ ] FromMicroCoroutine
  • IntervalFrame
  • NextFrame
    - [ ] ObserveOnMainThread
    - [ ] OnceApplicationQuit
    - [ ] OnErrorRetry
  • Pairwise
    - [ ] RepeatSafe
    - [ ] RepeatUntilDestroy
    - [ ] RepeatUntilDisable
  • ReturnUnit
  • SampleFrame
  • Share
    - [ ] StartAsCoroutine
    - [ ] SubscribeOnMainThread
    - [ ] TakeUntilDestroy
    - [ ] TakeUntilDisable
  • ThrottleFirst
  • ThrottleFirstFrame
  • ThrottleFrame
  • TimeoutFrame
  • TimerFrame
    - [ ] ToAwaitableEnumerator
    - [ ] ToYieldInstruction
    - [ ] WhenAll
  • ObserveEveryValueChanged
  • ZipLatest

Maybe GC optimization in Unity?

Happy to see R3 created.I have used UniRx years.UniRx use Gc a lot.How about reduce the memory usage or make some thing pooled?
I have a simple solution but not been test and validated,it still a toy.see BoysheO.Extensions/src/UnityReactive.Core

What's it design?
"event object whitch is oop"

  1. The IObserver.OnError is not very useful in practice. In situations where handling errors is a common requirement, such as dealing with network-related issues, using UniTask is more beneficial and easier to debug. IObserver appears more as an alternative to C#'s events, providing abstract capabilities that events lack. Personally, my implementation leans towards removing the OnError interface. If an event source wants to push an error notification, it is advisable to consider wrapping the error within an element, for instance, returning something like OneOf{Exception, Element}.

2.The IObservable.Subscribe method currently returns an IDisposable object, which can be prone to consuming garbage collection resources. I believe designing the interface as IObservable.Subscribe + IObservable.Unsubscribe is appropriate. However, a challenge arises if Subscribe is called multiple times, as IObservable.Unsubscribe might struggle to distinguish which listener to operate on. Perhaps changing the IDisposable returned by IObservable.Subscribe to return a value object could be a suitable solution. This way, it would only require maintaining an ID table internally within the Observable object.Certainly, my approach is more aggressive. I use a Manager class to maintain all the ID tables, instead of maintaining them within the Observable.

3.An event dispatched to be published elsewhere should have tracking information. My approach is to simply add a trackingMessage to the Observable. I believe this would be immensely helpful for debugging. Otherwise, when an IObserver throws an error, we can only see the stack trace printed from the scheduler.

4.After developing my UnityReactive library to address the aforementioned issues, I've encountered a dilemma. Using Linq inevitably creates a class of objects like "middlewares," leading to increased garbage collection (GC) overhead. This poses a challenge for UnityReactive managed by UnityReactiveManager. Perhaps I should implement a parsing language similar to SQL or create a separate Manager for each operator to manage their respective states. I haven't decided which approach to take yet; it seems both have their drawbacks and may not be ideal.

Although it might sound repetitive, I want to emphasize the GC issue. In Unity, this is crucial. Striking the optimal balance between GC and usability is a must.

Package Manager support for Unity

Currently the installation mechanism requires going through NuGet and manually changing the csproj for language settings. This is is somewhat heavy compared with UniRx which had only needed a scoped registry. Do you expect simpler package manager dependency to be possible at all ? Only in future versions of Unity with the required C# features ?

R3 and MessagePipe are not compatible?

After installing MessagePipe and R3 I got the following errors:

Library/PackageCache/com.cysharp.r3@ec1e91b2c0/Editor/ObservableTrackerWindow.cs(44,29): error CS0122: 'SplitterGUILayout' is inaccessible due to its protection level

Library/PackageCache/com.cysharp.r3@ec1e91b2c0/Editor/ObservableTrackerWindow.cs(59,13): error CS0122: 'SplitterGUILayout' is inaccessible due to its protection level

Library/PackageCache/com.cysharp.r3@ec1e91b2c0/Editor/ObservableTrackerWindow.cs(67,13): error CS0122: 'SplitterGUILayout' is inaccessible due to its protection level

GUID [14cc21ce00a64784eab22336b747c4f8] for asset 'Packages/com.cysharp.r3/Editor/SplitterGUILayout.cs' conflicts with:
  'Packages/com.cysharp.messagepipe/Editor/SplitterGUILayout.cs' (current owner)
We can't assign a new GUID because the asset is in an immutable folder. The asset will be ignored.

Missing AsyncReactiveCommand<T>

Hi,

Thanks for the great library, been using it (in Unity) for a couple of weeks.

I'm really missing an equivalent for AsyncReactiveCommand which exists in UniRx, so I'm curious to hear whether there are plans to add it to R3, and if so if there's a timeline for it?

Thanks in advance.

Preview1 Release Task

  • Avalonia Provider
  • Godot Provider
  • Unity Provider
  • Unity SubscriptionTracker Visualizer
  • ReadMe

SerializableReactiveProperty serialized multiple times error

This started happening when I updated to the latest version today, my previous version was pulled on Jan 24, 2024, so the change that introduced the issue must have happened after that date

I have a SerializableReactiveProperty defined as

[SerializeField] private SerializableReactiveProperty<int> currentEnergy

And every time it compiles it shows the following error in the console

image

My class inherits from MonoBehaviour and has no child classes

vs `IObservable<T>`

The current API uses a custom definition that differs from IObservable<T> and is therefore incompatible as is (conversion is possible with AsIObservable).
Whether we should go with a custom definition or conform to IObservable<T>.

Unity Trigger Source Generator

#7
It seems there is a significant demand for Triggers. In the current state of C#, it might be better to have users create only the necessary triggers on-demand, rather than preparing a large number of triggers in advance. Source Generators seem like a suitable candidate for this task.

Operator UnitTest not yet added

// Rx Merging:
// CombineLatest, Zip, ZipLatest, WithLatestFrom, Switch, Pairwise

// Standard Query:
// Distinct, DistinctBy, DistinctUntilChanged, Scan, DefaultIfEmpty

// return tasks:
// All, Any, Contains, SequenceEqual, IsEmpty, MaxBy, MinBy, ToDictionary, ToLookup,

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.