com.fofx.observething 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/README.md.meta +7 -0
- package/Runtime/CollectionIdProvider.cs +72 -0
- package/Runtime/CollectionIdProvider.cs.meta +2 -0
- package/Runtime/IObservable.cs +66 -0
- package/Runtime/IObservable.cs.meta +2 -0
- package/Runtime/Implementations/Observable.cs +30 -0
- package/Runtime/Implementations/Observable.cs.meta +2 -0
- package/Runtime/Implementations/ObservableBase.cs +173 -0
- package/Runtime/Implementations/ObservableBase.cs.meta +2 -0
- package/Runtime/Implementations/ObservableCollection.cs +141 -0
- package/Runtime/Implementations/ObservableCollection.cs.meta +2 -0
- package/Runtime/Implementations/ObservableDictionary.cs +166 -0
- package/Runtime/Implementations/ObservableDictionary.cs.meta +2 -0
- package/Runtime/Implementations/ObservableList.cs +163 -0
- package/Runtime/Implementations/ObservableList.cs.meta +2 -0
- package/Runtime/Implementations/ObservableSet.cs +137 -0
- package/Runtime/Implementations/ObservableSet.cs.meta +2 -0
- package/Runtime/Implementations/ObservableValue.cs +59 -0
- package/Runtime/Implementations/ObservableValue.cs.meta +2 -0
- package/Runtime/Implementations.meta +8 -0
- package/Runtime/Observables/BatchObservable.cs +72 -0
- package/Runtime/Observables/BatchObservable.cs.meta +2 -0
- package/Runtime/Observables/CastObservable.cs +128 -0
- package/Runtime/Observables/CastObservable.cs.meta +2 -0
- package/Runtime/Observables/CombineObservable.cs +96 -0
- package/Runtime/Observables/CombineObservable.cs.meta +2 -0
- package/Runtime/Observables/CombineValueObservable.cs +319 -0
- package/Runtime/Observables/CombineValueObservable.cs.meta +2 -0
- package/Runtime/Observables/ConcatObservable.cs +75 -0
- package/Runtime/Observables/ConcatObservable.cs.meta +2 -0
- package/Runtime/Observables/ContainsObservable.cs +71 -0
- package/Runtime/Observables/ContainsObservable.cs.meta +2 -0
- package/Runtime/Observables/CountObservable.cs +29 -0
- package/Runtime/Observables/CountObservable.cs.meta +2 -0
- package/Runtime/Observables/DistinctObservable.cs +55 -0
- package/Runtime/Observables/DistinctObservable.cs.meta +2 -0
- package/Runtime/Observables/FirstObservable.cs +53 -0
- package/Runtime/Observables/FirstObservable.cs.meta +2 -0
- package/Runtime/Observables/IndexOfObservable.cs +83 -0
- package/Runtime/Observables/IndexOfObservable.cs.meta +2 -0
- package/Runtime/Observables/OperationStreamObservable.cs +194 -0
- package/Runtime/Observables/OperationStreamObservable.cs.meta +2 -0
- package/Runtime/Observables/OrderByObservable.cs +116 -0
- package/Runtime/Observables/OrderByObservable.cs.meta +2 -0
- package/Runtime/Observables/SelectCollectionObservable.cs +29 -0
- package/Runtime/Observables/SelectCollectionObservable.cs.meta +2 -0
- package/Runtime/Observables/SelectListObservable.cs +29 -0
- package/Runtime/Observables/SelectListObservable.cs.meta +2 -0
- package/Runtime/Observables/SelectManyObservable.cs +78 -0
- package/Runtime/Observables/SelectManyObservable.cs.meta +2 -0
- package/Runtime/Observables/SelectValueObservable.cs +28 -0
- package/Runtime/Observables/SelectValueObservable.cs.meta +2 -0
- package/Runtime/Observables/SkipWhileObservable.cs +32 -0
- package/Runtime/Observables/SkipWhileObservable.cs.meta +2 -0
- package/Runtime/Observables/ThenObservable.cs +209 -0
- package/Runtime/Observables/ThenObservable.cs.meta +2 -0
- package/Runtime/Observables/ToDictionaryObservable.cs +35 -0
- package/Runtime/Observables/ToDictionaryObservable.cs.meta +2 -0
- package/Runtime/Observables/TrackObservable.cs +74 -0
- package/Runtime/Observables/TrackObservable.cs.meta +2 -0
- package/Runtime/Observables/UnwrapCollectionObservable.cs +64 -0
- package/Runtime/Observables/UnwrapCollectionObservable.cs.meta +2 -0
- package/Runtime/Observables/UnwrapListObservable.cs +69 -0
- package/Runtime/Observables/UnwrapListObservable.cs.meta +2 -0
- package/Runtime/Observables/UnwrapValueObservable.cs +56 -0
- package/Runtime/Observables/UnwrapValueObservable.cs.meta +2 -0
- package/Runtime/Observables/WhereObservable.cs +85 -0
- package/Runtime/Observables/WhereObservable.cs.meta +2 -0
- package/Runtime/Observables/WithPreviousObservable.cs +36 -0
- package/Runtime/Observables/WithPreviousObservable.cs.meta +2 -0
- package/Runtime/Observables.cs +467 -0
- package/Runtime/Observables.cs.meta +2 -0
- package/Runtime/Observables.meta +8 -0
- package/Runtime/ObservationContext.cs +126 -0
- package/Runtime/ObservationContext.cs.meta +2 -0
- package/Runtime/Observers.cs +403 -0
- package/Runtime/Observers.cs.meta +2 -0
- package/Runtime/Operators/BatchOperator.cs +71 -0
- package/Runtime/Operators/BatchOperator.cs.meta +2 -0
- package/Runtime/Operators/CollectionOperator.cs +30 -0
- package/Runtime/Operators/CollectionOperator.cs.meta +2 -0
- package/Runtime/Operators/DictionaryOperator.cs +45 -0
- package/Runtime/Operators/DictionaryOperator.cs.meta +2 -0
- package/Runtime/Operators/IInitializationOperationsProvider.cs +10 -0
- package/Runtime/Operators/IInitializationOperationsProvider.cs.meta +2 -0
- package/Runtime/Operators/ListOperator.cs +44 -0
- package/Runtime/Operators/ListOperator.cs.meta +2 -0
- package/Runtime/Operators/ObservableOperator.cs +75 -0
- package/Runtime/Operators/ObservableOperator.cs.meta +2 -0
- package/Runtime/Operators/Operator.cs +65 -0
- package/Runtime/Operators/Operator.cs.meta +2 -0
- package/Runtime/Operators/SetOperator.cs +44 -0
- package/Runtime/Operators/SetOperator.cs.meta +2 -0
- package/Runtime/Operators/ValueOperator.cs +30 -0
- package/Runtime/Operators/ValueOperator.cs.meta +2 -0
- package/Runtime/Operators.meta +8 -0
- package/Runtime/PriorityQueue.cs +1096 -0
- package/Runtime/PriorityQueue.cs.meta +2 -0
- package/Runtime/com.fofx.observething.asmdef +14 -0
- package/Runtime/com.fofx.observething.asmdef.meta +7 -0
- package/Runtime.meta +8 -0
- package/Tests/CollectionObservableTests.cs +739 -0
- package/Tests/CollectionObservableTests.cs.meta +2 -0
- package/Tests/DictionaryObservableTests.cs +85 -0
- package/Tests/DictionaryObservableTests.cs.meta +2 -0
- package/Tests/ListObservableTests.cs +148 -0
- package/Tests/ListObservableTests.cs.meta +2 -0
- package/Tests/ObservationContextTests.cs +359 -0
- package/Tests/ObservationContextTests.cs.meta +2 -0
- package/Tests/ValueObservableTests.cs +322 -0
- package/Tests/ValueObservableTests.cs.meta +2 -0
- package/Tests/com.fofx.observething.tests.asmdef +24 -0
- package/Tests/com.fofx.observething.tests.asmdef.meta +7 -0
- package/Tests.meta +8 -0
- package/package.json +24 -0
- package/package.json.meta +7 -0
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections;
|
|
3
|
+
using System.Collections.Generic;
|
|
4
|
+
|
|
5
|
+
namespace ObserveThing
|
|
6
|
+
{
|
|
7
|
+
public interface IListOp : IOperation
|
|
8
|
+
{
|
|
9
|
+
uint elementId { get; }
|
|
10
|
+
int index { get; }
|
|
11
|
+
object element { get; }
|
|
12
|
+
bool isRemove { get; }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public struct ListOp<T> : IListOp
|
|
16
|
+
{
|
|
17
|
+
public IObservable<IOperation> source { get; set; }
|
|
18
|
+
public int index { get; set; }
|
|
19
|
+
public uint elementId { get; set; }
|
|
20
|
+
public T element { get; set; }
|
|
21
|
+
public bool isRemove { get; set; }
|
|
22
|
+
|
|
23
|
+
object IListOp.element => element;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public class ObservableList<T> : ObservableBase<IListObserver<T>, ListOp<T>>, IListObservable<T>, IEnumerable<T>
|
|
27
|
+
{
|
|
28
|
+
public T this[int index]
|
|
29
|
+
{
|
|
30
|
+
get => _list[index];
|
|
31
|
+
set
|
|
32
|
+
{
|
|
33
|
+
RemoveAt(index);
|
|
34
|
+
Insert(index, value);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
IEnumerator<T> IEnumerable<T>.GetEnumerator()
|
|
39
|
+
=> _list.GetEnumerator();
|
|
40
|
+
|
|
41
|
+
IEnumerator IEnumerable.GetEnumerator()
|
|
42
|
+
=> _list.GetEnumerator();
|
|
43
|
+
|
|
44
|
+
public int count => _list.Count;
|
|
45
|
+
|
|
46
|
+
private List<T> _list = new List<T>();
|
|
47
|
+
private List<uint> _ids = new List<uint>();
|
|
48
|
+
private CollectionIdProvider _idProvider;
|
|
49
|
+
|
|
50
|
+
public ObservableList() : this(default, default(IEnumerable<T>)) { }
|
|
51
|
+
public ObservableList(params T[] value) : this(default, (IEnumerable<T>)value) { }
|
|
52
|
+
public ObservableList(IEnumerable<T> value) : this(default, value) { }
|
|
53
|
+
|
|
54
|
+
public ObservableList(ObservationContext context) : this(context, default(IEnumerable<T>)) { }
|
|
55
|
+
public ObservableList(ObservationContext context, params T[] value) : this(context, (IEnumerable<T>)value) { }
|
|
56
|
+
public ObservableList(ObservationContext context, IEnumerable<T> value) : base(context)
|
|
57
|
+
{
|
|
58
|
+
_idProvider = new CollectionIdProvider(_ids.Contains);
|
|
59
|
+
|
|
60
|
+
if (value == null)
|
|
61
|
+
return;
|
|
62
|
+
|
|
63
|
+
foreach (var element in value)
|
|
64
|
+
{
|
|
65
|
+
_list.Add(element);
|
|
66
|
+
_ids.Add(_idProvider.GetUnusedId());
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public void Add(T added)
|
|
71
|
+
=> Insert(_list.Count, added);
|
|
72
|
+
|
|
73
|
+
public void AddRange(IEnumerable<T> toAdd)
|
|
74
|
+
{
|
|
75
|
+
foreach (var added in toAdd)
|
|
76
|
+
Add(added);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public bool Remove(T removed)
|
|
80
|
+
{
|
|
81
|
+
var index = _list.IndexOf(removed);
|
|
82
|
+
|
|
83
|
+
if (index == -1)
|
|
84
|
+
return false;
|
|
85
|
+
|
|
86
|
+
RemoveAt(index);
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public void RemoveAt(int index)
|
|
91
|
+
{
|
|
92
|
+
var removed = _list[index];
|
|
93
|
+
var id = _ids[index];
|
|
94
|
+
_list.RemoveAt(index);
|
|
95
|
+
_ids.RemoveAt(index);
|
|
96
|
+
EnqueuePendingOperation(new ListOp<T>() { source = this, element = removed, elementId = id, index = index, isRemove = true });
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public void Insert(int index, T item)
|
|
100
|
+
{
|
|
101
|
+
var id = _idProvider.GetUnusedId();
|
|
102
|
+
_list.Insert(index, item);
|
|
103
|
+
_ids.Insert(index, id);
|
|
104
|
+
EnqueuePendingOperation(new ListOp<T>() { source = this, element = item, elementId = id, index = index, isRemove = false });
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
public void Clear()
|
|
108
|
+
{
|
|
109
|
+
while (_list.Count > 0)
|
|
110
|
+
RemoveAt(_list.Count - 1);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
public int IndexOf(T item)
|
|
114
|
+
=> _list.IndexOf(item);
|
|
115
|
+
|
|
116
|
+
public bool Contains(T item)
|
|
117
|
+
=> _list.Contains(item);
|
|
118
|
+
|
|
119
|
+
protected override IEnumerable<ListOp<T>> GetInitializationOperations()
|
|
120
|
+
{
|
|
121
|
+
for (int i = 0; i < _list.Count; i++)
|
|
122
|
+
{
|
|
123
|
+
yield return new ListOp<T>() { source = this, element = _list[i], elementId = _ids[i], index = i, isRemove = false };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
protected override void SendOperation(IListObserver<T> observer, ListOp<T> operation)
|
|
128
|
+
{
|
|
129
|
+
if (operation.isRemove)
|
|
130
|
+
{
|
|
131
|
+
observer.OnRemove(operation.elementId, operation.index, operation.element);
|
|
132
|
+
}
|
|
133
|
+
else
|
|
134
|
+
{
|
|
135
|
+
observer.OnAdd(operation.elementId, operation.index, operation.element);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
IDisposable IListObservable.Subscribe(IListObserver observer, bool immediate, uint? priority)
|
|
140
|
+
=> Subscribe(new ListObserver<T>(
|
|
141
|
+
onAdd: (id, index, element) => observer.OnAdd(id, index, element),
|
|
142
|
+
onRemove: (id, index, element) => observer.OnRemove(id, index, element),
|
|
143
|
+
onDispose: observer.OnDispose,
|
|
144
|
+
onError: observer.OnError
|
|
145
|
+
), immediate, priority);
|
|
146
|
+
|
|
147
|
+
IDisposable ICollectionObservable<T>.Subscribe(ICollectionObserver<T> observer, bool immediate, uint? priority)
|
|
148
|
+
=> Subscribe(new ListObserver<T>(
|
|
149
|
+
onAdd: (id, index, element) => observer.OnAdd(id, element),
|
|
150
|
+
onRemove: (id, index, element) => observer.OnRemove(id, element),
|
|
151
|
+
onDispose: observer.OnDispose,
|
|
152
|
+
onError: observer.OnError
|
|
153
|
+
), immediate, priority);
|
|
154
|
+
|
|
155
|
+
IDisposable ICollectionObservable.Subscribe(ICollectionObserver observer, bool immediate, uint? priority)
|
|
156
|
+
=> Subscribe(new ListObserver<T>(
|
|
157
|
+
onAdd: (id, index, element) => observer.OnAdd(id, element),
|
|
158
|
+
onRemove: (id, index, element) => observer.OnRemove(id, element),
|
|
159
|
+
onDispose: observer.OnDispose,
|
|
160
|
+
onError: observer.OnError
|
|
161
|
+
), immediate, priority);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections;
|
|
3
|
+
using System.Collections.Generic;
|
|
4
|
+
using System.Linq;
|
|
5
|
+
|
|
6
|
+
namespace ObserveThing
|
|
7
|
+
{
|
|
8
|
+
public interface ISetOp : IOperation
|
|
9
|
+
{
|
|
10
|
+
uint elementId { get; }
|
|
11
|
+
object element { get; }
|
|
12
|
+
bool isRemove { get; }
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
public struct SetOp<T> : ISetOp
|
|
16
|
+
{
|
|
17
|
+
public IObservable<IOperation> source { get; set; }
|
|
18
|
+
public uint elementId { get; set; }
|
|
19
|
+
public T element { get; set; }
|
|
20
|
+
public bool isRemove { get; set; }
|
|
21
|
+
|
|
22
|
+
object ISetOp.element => element;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public class ObservableSet<T> : ObservableBase<ISetObserver<T>, SetOp<T>>, ISetObservable<T>, IEnumerable<T>
|
|
26
|
+
{
|
|
27
|
+
public int count => _set.Count;
|
|
28
|
+
|
|
29
|
+
public IEnumerator<T> GetEnumerator()
|
|
30
|
+
=> _set.Keys.GetEnumerator();
|
|
31
|
+
|
|
32
|
+
IEnumerator IEnumerable.GetEnumerator()
|
|
33
|
+
=> _set.Keys.GetEnumerator();
|
|
34
|
+
|
|
35
|
+
private Dictionary<T, uint> _set = new Dictionary<T, uint>();
|
|
36
|
+
private CollectionIdProvider _idProvider;
|
|
37
|
+
|
|
38
|
+
public ObservableSet() : this(default, default) { }
|
|
39
|
+
public ObservableSet(IEnumerable<T> values) : this(default, values) { }
|
|
40
|
+
public ObservableSet(ObservationContext context) : this(context, null) { }
|
|
41
|
+
public ObservableSet(ObservationContext context, IEnumerable<T> values) : base(context)
|
|
42
|
+
{
|
|
43
|
+
_idProvider = new CollectionIdProvider(x => _set.ContainsValue(x));
|
|
44
|
+
|
|
45
|
+
if (values == null)
|
|
46
|
+
return;
|
|
47
|
+
|
|
48
|
+
foreach (T value in values)
|
|
49
|
+
_set.Add(value, _idProvider.GetUnusedId());
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public bool Add(T element)
|
|
53
|
+
{
|
|
54
|
+
if (_set.ContainsKey(element))
|
|
55
|
+
return false;
|
|
56
|
+
|
|
57
|
+
var id = _idProvider.GetUnusedId();
|
|
58
|
+
_set.Add(element, id);
|
|
59
|
+
EnqueuePendingOperation(new SetOp<T>() { source = this, elementId = id, element = element, isRemove = false });
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public void AddRange(IEnumerable<T> elements)
|
|
64
|
+
{
|
|
65
|
+
foreach (var element in elements)
|
|
66
|
+
Add(element);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
public bool Remove(T element)
|
|
70
|
+
{
|
|
71
|
+
if (!_set.TryGetValue(element, out var id))
|
|
72
|
+
return false;
|
|
73
|
+
|
|
74
|
+
_set.Remove(element);
|
|
75
|
+
EnqueuePendingOperation(new SetOp<T>() { source = this, elementId = id, element = element, isRemove = true });
|
|
76
|
+
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public void Clear()
|
|
81
|
+
{
|
|
82
|
+
foreach (var kvp in _set.ToArray())
|
|
83
|
+
{
|
|
84
|
+
_set.Remove(kvp.Key);
|
|
85
|
+
EnqueuePendingOperation(new SetOp<T>() { source = this, elementId = kvp.Value, element = kvp.Key, isRemove = true });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
public bool Contains(T element)
|
|
90
|
+
=> _set.ContainsKey(element);
|
|
91
|
+
|
|
92
|
+
public uint GetElementId(T element)
|
|
93
|
+
=> _set[element];
|
|
94
|
+
|
|
95
|
+
protected override IEnumerable<SetOp<T>> GetInitializationOperations()
|
|
96
|
+
{
|
|
97
|
+
foreach (var element in _set)
|
|
98
|
+
yield return new SetOp<T>() { source = this, element = element.Key, elementId = element.Value, isRemove = false };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
protected override void SendOperation(ISetObserver<T> observer, SetOp<T> operation)
|
|
102
|
+
{
|
|
103
|
+
if (operation.isRemove)
|
|
104
|
+
{
|
|
105
|
+
observer.OnRemove(operation.elementId, operation.element);
|
|
106
|
+
}
|
|
107
|
+
else
|
|
108
|
+
{
|
|
109
|
+
observer.OnAdd(operation.elementId, operation.element);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
IDisposable ISetObservable.Subscribe(ISetObserver observer, bool immediate, uint? priority)
|
|
114
|
+
=> Subscribe(new SetObserver<T>(
|
|
115
|
+
onAdd: (id, element) => observer.OnAdd(id, element),
|
|
116
|
+
onRemove: (id, element) => observer.OnRemove(id, element),
|
|
117
|
+
onDispose: observer.OnDispose,
|
|
118
|
+
onError: observer.OnError
|
|
119
|
+
), immediate, priority);
|
|
120
|
+
|
|
121
|
+
IDisposable ICollectionObservable<T>.Subscribe(ICollectionObserver<T> observer, bool immediate, uint? priority)
|
|
122
|
+
=> Subscribe(new SetObserver<T>(
|
|
123
|
+
onAdd: (id, element) => observer.OnAdd(id, element),
|
|
124
|
+
onRemove: (id, element) => observer.OnRemove(id, element),
|
|
125
|
+
onDispose: observer.OnDispose,
|
|
126
|
+
onError: observer.OnError
|
|
127
|
+
), immediate, priority);
|
|
128
|
+
|
|
129
|
+
IDisposable ICollectionObservable.Subscribe(ICollectionObserver observer, bool immediate, uint? priority)
|
|
130
|
+
=> Subscribe(new SetObserver<T>(
|
|
131
|
+
onAdd: (id, element) => observer.OnAdd(id, element),
|
|
132
|
+
onRemove: (id, element) => observer.OnRemove(id, element),
|
|
133
|
+
onDispose: observer.OnDispose,
|
|
134
|
+
onError: observer.OnError
|
|
135
|
+
), immediate, priority);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections.Generic;
|
|
3
|
+
|
|
4
|
+
namespace ObserveThing
|
|
5
|
+
{
|
|
6
|
+
public interface IValueOp : IOperation
|
|
7
|
+
{
|
|
8
|
+
object value { get; }
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
public struct ValueOp<T> : IValueOp
|
|
12
|
+
{
|
|
13
|
+
public IObservable<IOperation> source { get; set; }
|
|
14
|
+
public T value { get; set; }
|
|
15
|
+
|
|
16
|
+
object IValueOp.value => value;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public class ObservableValue<T> : ObservableBase<IValueObserver<T>, ValueOp<T>>, IValueObservable<T>
|
|
20
|
+
{
|
|
21
|
+
public T value
|
|
22
|
+
{
|
|
23
|
+
get => _value;
|
|
24
|
+
set
|
|
25
|
+
{
|
|
26
|
+
if (Equals(_value, value))
|
|
27
|
+
return;
|
|
28
|
+
|
|
29
|
+
_value = value;
|
|
30
|
+
EnqueuePendingOperation(new ValueOp<T>() { source = this, value = value });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private T _value;
|
|
35
|
+
|
|
36
|
+
public ObservableValue() : this(default, default) { }
|
|
37
|
+
public ObservableValue(T value) : this(default, value) { }
|
|
38
|
+
public ObservableValue(ObservationContext context) : this(context, default) { }
|
|
39
|
+
public ObservableValue(ObservationContext context, T value) : base(context)
|
|
40
|
+
{
|
|
41
|
+
_value = value;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
protected override IEnumerable<ValueOp<T>> GetInitializationOperations()
|
|
45
|
+
{
|
|
46
|
+
yield return new ValueOp<T>() { source = this, value = _value };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
protected override void SendOperation(IValueObserver<T> observer, ValueOp<T> operation)
|
|
50
|
+
=> observer.OnNext(operation.value);
|
|
51
|
+
|
|
52
|
+
public IDisposable Subscribe(IValueObserver observer, bool immediate = false, uint? priority = null)
|
|
53
|
+
=> Subscribe(new ValueObserver<T>(
|
|
54
|
+
onNext: x => observer.OnNext(x),
|
|
55
|
+
onDispose: observer.OnDispose,
|
|
56
|
+
onError: observer.OnError
|
|
57
|
+
), immediate, priority);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections.Generic;
|
|
3
|
+
|
|
4
|
+
namespace ObserveThing
|
|
5
|
+
{
|
|
6
|
+
public class BatchObservable<T> : IInitializationOperationsProvider<BatchOp<T>>, IPendingObserver where T : IOperation
|
|
7
|
+
{
|
|
8
|
+
public bool immediate { get; } = false;
|
|
9
|
+
public uint priority { get; private set; }
|
|
10
|
+
public bool disposed { get; private set; }
|
|
11
|
+
|
|
12
|
+
private IObservable<T> _source;
|
|
13
|
+
private Observable<BatchOp<T>> _operand;
|
|
14
|
+
private IDisposable _subscriptions;
|
|
15
|
+
private bool _pending;
|
|
16
|
+
|
|
17
|
+
private List<T> _batchedOperations = new List<T>();
|
|
18
|
+
|
|
19
|
+
public BatchObservable(IObservable<T> source, Observable<BatchOp<T>> operand)
|
|
20
|
+
{
|
|
21
|
+
priority = source.context.AllocateObserverPriority();
|
|
22
|
+
|
|
23
|
+
_source = source;
|
|
24
|
+
_operand = operand;
|
|
25
|
+
|
|
26
|
+
_subscriptions = source.Subscribe(new Observer<T>(
|
|
27
|
+
onNext: HandleSourceOperation,
|
|
28
|
+
onError: operand.OnError,
|
|
29
|
+
onDispose: Dispose
|
|
30
|
+
), immediate: true);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private void HandleSourceOperation(T operation)
|
|
34
|
+
{
|
|
35
|
+
_batchedOperations.Add(operation);
|
|
36
|
+
|
|
37
|
+
if (_pending)
|
|
38
|
+
return;
|
|
39
|
+
|
|
40
|
+
_pending = true;
|
|
41
|
+
_source.context.RegisterPendingObserver(this);
|
|
42
|
+
_source.context.NotifyPendingObserversIfNecessary();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
public IEnumerable<BatchOp<T>> GetInitializationOperations()
|
|
46
|
+
{
|
|
47
|
+
List<T> initOps = new List<T>();
|
|
48
|
+
var subscription = _source.Subscribe(new Observer<T>(x => initOps.Add(x)));
|
|
49
|
+
subscription.Dispose();
|
|
50
|
+
yield return new BatchOp<T>() { source = _source, operations = initOps };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public void SendNext()
|
|
54
|
+
{
|
|
55
|
+
_pending = false;
|
|
56
|
+
|
|
57
|
+
var batch = _batchedOperations.ToArray();
|
|
58
|
+
_batchedOperations.Clear();
|
|
59
|
+
|
|
60
|
+
_operand.EnqueueOperation(new BatchOp<T>() { source = _source, operations = batch });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public void Dispose()
|
|
64
|
+
{
|
|
65
|
+
disposed = true;
|
|
66
|
+
_source.context.DeallocateObserverPriority(priority);
|
|
67
|
+
_subscriptions?.Dispose();
|
|
68
|
+
_subscriptions = null;
|
|
69
|
+
_operand.Dispose();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
|
|
3
|
+
namespace ObserveThing
|
|
4
|
+
{
|
|
5
|
+
public class CastValueObservable<T> : IDisposable
|
|
6
|
+
{
|
|
7
|
+
private ObservableValue<T> _operand;
|
|
8
|
+
private IDisposable _subscription;
|
|
9
|
+
|
|
10
|
+
public CastValueObservable(IValueObservable source, ObservableValue<T> operand)
|
|
11
|
+
{
|
|
12
|
+
_operand = operand;
|
|
13
|
+
_subscription = source.Subscribe(
|
|
14
|
+
onNext: x => operand.value = (T)x,
|
|
15
|
+
onError: operand.OnError,
|
|
16
|
+
onDispose: Dispose,
|
|
17
|
+
immediate: true
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public void Dispose()
|
|
22
|
+
{
|
|
23
|
+
_subscription?.Dispose();
|
|
24
|
+
_subscription = null;
|
|
25
|
+
_operand.Dispose();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public class CastCollectionObservable<T> : IDisposable
|
|
30
|
+
{
|
|
31
|
+
private ObservableCollection<T> _operand;
|
|
32
|
+
private IDisposable _subscription;
|
|
33
|
+
|
|
34
|
+
public CastCollectionObservable(ICollectionObservable source, ObservableCollection<T> operand)
|
|
35
|
+
{
|
|
36
|
+
_operand = operand;
|
|
37
|
+
_subscription = source.SubscribeWithId(
|
|
38
|
+
onAdd: (id, x) => operand.Add(id, (T)x),
|
|
39
|
+
onRemove: (id, _) => operand.Remove(id),
|
|
40
|
+
onError: operand.OnError,
|
|
41
|
+
onDispose: Dispose,
|
|
42
|
+
immediate: true
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public void Dispose()
|
|
47
|
+
{
|
|
48
|
+
_subscription?.Dispose();
|
|
49
|
+
_subscription = null;
|
|
50
|
+
_operand.Dispose();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
public class CastListObservable<T> : IDisposable
|
|
55
|
+
{
|
|
56
|
+
private ObservableList<T> _operand;
|
|
57
|
+
private IDisposable _subscription;
|
|
58
|
+
|
|
59
|
+
public CastListObservable(IListObservable source, ObservableList<T> operand)
|
|
60
|
+
{
|
|
61
|
+
_operand = operand;
|
|
62
|
+
_subscription = source.Subscribe(
|
|
63
|
+
onAdd: (index, x) => operand.Insert(index, (T)x),
|
|
64
|
+
onRemove: (index, _) => operand.RemoveAt(index),
|
|
65
|
+
onError: operand.OnError,
|
|
66
|
+
onDispose: Dispose,
|
|
67
|
+
immediate: true
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
public void Dispose()
|
|
72
|
+
{
|
|
73
|
+
_subscription?.Dispose();
|
|
74
|
+
_subscription = null;
|
|
75
|
+
_operand.Dispose();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public class CastSetObservable<T> : IDisposable
|
|
80
|
+
{
|
|
81
|
+
private ObservableSet<T> _operand;
|
|
82
|
+
private IDisposable _subscription;
|
|
83
|
+
|
|
84
|
+
public CastSetObservable(ISetObservable source, ObservableSet<T> operand)
|
|
85
|
+
{
|
|
86
|
+
_operand = operand;
|
|
87
|
+
_subscription = source.Subscribe(
|
|
88
|
+
onAdd: x => operand.Add((T)x),
|
|
89
|
+
onRemove: x => operand.Remove((T)x),
|
|
90
|
+
onError: operand.OnError,
|
|
91
|
+
onDispose: Dispose,
|
|
92
|
+
immediate: true
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public void Dispose()
|
|
97
|
+
{
|
|
98
|
+
_subscription?.Dispose();
|
|
99
|
+
_subscription = null;
|
|
100
|
+
_operand.Dispose();
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public class CastDictionaryObservable<TKey, TValue> : IDisposable
|
|
105
|
+
{
|
|
106
|
+
private ObservableDictionary<TKey, TValue> _operand;
|
|
107
|
+
private IDisposable _subscription;
|
|
108
|
+
|
|
109
|
+
public CastDictionaryObservable(IDictionaryObservable source, ObservableDictionary<TKey, TValue> operand)
|
|
110
|
+
{
|
|
111
|
+
_operand = operand;
|
|
112
|
+
_subscription = source.Subscribe(
|
|
113
|
+
onAdd: x => operand.Add((TKey)x.Key, (TValue)x.Value),
|
|
114
|
+
onRemove: x => operand.Remove((TKey)x.Key),
|
|
115
|
+
onError: operand.OnError,
|
|
116
|
+
onDispose: Dispose,
|
|
117
|
+
immediate: true
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
public void Dispose()
|
|
122
|
+
{
|
|
123
|
+
_subscription?.Dispose();
|
|
124
|
+
_subscription = null;
|
|
125
|
+
_operand.Dispose();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections.Generic;
|
|
3
|
+
|
|
4
|
+
namespace ObserveThing
|
|
5
|
+
{
|
|
6
|
+
public class CombineObservable<T> : IInitializationOperationsProvider<T> where T : IOperation
|
|
7
|
+
{
|
|
8
|
+
private ISetObservable<IObservable<T>> _source;
|
|
9
|
+
private Observable<T> _operand;
|
|
10
|
+
private bool _disposeOnSourceEmpty;
|
|
11
|
+
private uint _elementPriority;
|
|
12
|
+
private Dictionary<IObservable<T>, IDisposable> _observables = new Dictionary<IObservable<T>, IDisposable>();
|
|
13
|
+
private IDisposable _subscriptions;
|
|
14
|
+
private bool _disposed;
|
|
15
|
+
|
|
16
|
+
public CombineObservable(ISetObservable<IObservable<T>> source, Observable<T> operand, bool disposeOnSourceEmpty = false)
|
|
17
|
+
{
|
|
18
|
+
_source = source;
|
|
19
|
+
_operand = operand;
|
|
20
|
+
_disposeOnSourceEmpty = disposeOnSourceEmpty;
|
|
21
|
+
_elementPriority = _source.context.AllocateObserverPriority();
|
|
22
|
+
_subscriptions = _source.Subscribe(new SetObserver<IObservable<T>>(
|
|
23
|
+
onAdd: HandleElementAdded,
|
|
24
|
+
onRemove: HandleElementRemoved,
|
|
25
|
+
onError: _operand.OnError,
|
|
26
|
+
onDispose: Dispose
|
|
27
|
+
), immediate: true);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
public IEnumerable<T> GetInitializationOperations()
|
|
31
|
+
{
|
|
32
|
+
List<T> initOps = new List<T>();
|
|
33
|
+
|
|
34
|
+
foreach (var element in _observables.Keys)
|
|
35
|
+
{
|
|
36
|
+
var subscription = element.Subscribe(new Observer<T>(x => initOps.Add(x)));
|
|
37
|
+
subscription.Dispose();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
foreach (var op in initOps)
|
|
41
|
+
yield return op;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
private void HandleElementAdded(uint _, IObservable<T> observable)
|
|
45
|
+
{
|
|
46
|
+
_observables.Add(
|
|
47
|
+
observable,
|
|
48
|
+
observable.Subscribe(new Observer<T>(
|
|
49
|
+
onNext: HandleElementChanged,
|
|
50
|
+
onError: _operand.OnError,
|
|
51
|
+
onDispose: () =>
|
|
52
|
+
{
|
|
53
|
+
if (_disposed)
|
|
54
|
+
return;
|
|
55
|
+
|
|
56
|
+
HandleElementRemoved(0, observable);
|
|
57
|
+
}
|
|
58
|
+
), immediate: true, priority: _elementPriority)
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private void HandleElementRemoved(uint _, IObservable<T> observable)
|
|
63
|
+
{
|
|
64
|
+
if (!_observables.TryGetValue(observable, out var subscription))
|
|
65
|
+
return;
|
|
66
|
+
|
|
67
|
+
_observables.Remove(observable);
|
|
68
|
+
subscription.Dispose();
|
|
69
|
+
|
|
70
|
+
if (_disposeOnSourceEmpty && _observables.Count == 0)
|
|
71
|
+
Dispose();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
protected void HandleElementChanged(T operation)
|
|
75
|
+
{
|
|
76
|
+
_operand.EnqueueOperation(operation);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
public void Dispose()
|
|
80
|
+
{
|
|
81
|
+
if (_disposed)
|
|
82
|
+
return;
|
|
83
|
+
|
|
84
|
+
_disposed = true;
|
|
85
|
+
|
|
86
|
+
_source.context.DeallocateObserverPriority(_elementPriority);
|
|
87
|
+
|
|
88
|
+
foreach (var subscription in _observables.Values)
|
|
89
|
+
subscription.Dispose();
|
|
90
|
+
|
|
91
|
+
_subscriptions?.Dispose();
|
|
92
|
+
_subscriptions = null;
|
|
93
|
+
_operand.Dispose();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|