reactivity
This commit is contained in:
parent
8e8c63e3f2
commit
ea54bed80d
@ -55,6 +55,7 @@
|
|||||||
<Compile Include="Reactive\ReactiveSender.cs" />
|
<Compile Include="Reactive\ReactiveSender.cs" />
|
||||||
<Compile Include="Reactive\ReactiveStream.cs" />
|
<Compile Include="Reactive\ReactiveStream.cs" />
|
||||||
<Compile Include="Reactive\ReactiveProvider.cs" />
|
<Compile Include="Reactive\ReactiveProvider.cs" />
|
||||||
|
<Compile Include="Reactive\TimeSignedObject.cs" />
|
||||||
<Compile Include="SecureRandom.cs" />
|
<Compile Include="SecureRandom.cs" />
|
||||||
<Compile Include="FrameworkFix.cs" />
|
<Compile Include="FrameworkFix.cs" />
|
||||||
<Compile Include="TImer.cs" />
|
<Compile Include="TImer.cs" />
|
||||||
@ -62,7 +63,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include=".gitignore" />
|
<Content Include=".gitignore" />
|
||||||
<Content Include="DTLib.sln" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="README.md" />
|
<None Include="README.md" />
|
||||||
|
|||||||
@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
namespace DTLib
|
namespace DTLib
|
||||||
{
|
{
|
||||||
public delegate Task EventHandlerAsync<TEventArgs>(TEventArgs e);
|
// по идее это нужно, чтоб делать так: SomeEvent?.Invoke().Wait()
|
||||||
public delegate Task EventHandlerAsync();
|
public delegate Task EventHandlerAsyncDelegate();
|
||||||
|
public delegate Task EventHandlerAsyncDelegate<T>(T e);
|
||||||
|
public delegate Task EventHandlerAsyncDelegate<T0, T1>(T0 e0, T1 e1);
|
||||||
|
public delegate Task EventHandlerAsyncDelegate<T0, T1, T2>(T0 e0, T1 e1, T2 e2);
|
||||||
|
public delegate Task EventHandlerAsyncDelegate<T0, T1, T2, T3>(T0 e0, T1 e1, T2 e2, T3 e3);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -152,6 +152,13 @@ namespace DTLib
|
|||||||
b.Append(input);
|
b.Append(input);
|
||||||
return b.ToString();
|
return b.ToString();
|
||||||
}
|
}
|
||||||
|
public static string Multiply(this char input, int howMany)
|
||||||
|
{
|
||||||
|
StringBuilder b = new();
|
||||||
|
for (int i = 0; i < howMany; i++)
|
||||||
|
b.Append(input);
|
||||||
|
return b.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
public static void Throw(this Exception ex) => throw ex;
|
public static void Throw(this Exception ex) => throw ex;
|
||||||
|
|
||||||
@ -221,5 +228,13 @@ namespace DTLib
|
|||||||
{
|
{
|
||||||
if (input is null) if_true();
|
if (input is null) if_true();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string AddZeroes<T>(this T number, int length)
|
||||||
|
{
|
||||||
|
var str = number.ToString();
|
||||||
|
//var diff = str.Length -length ;
|
||||||
|
//if (diff > 0)
|
||||||
|
return Multiply('0', str.Length - length) + str;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -8,42 +8,93 @@ namespace DTLib.Reactive
|
|||||||
{
|
{
|
||||||
public ReactiveListener() { }
|
public ReactiveListener() { }
|
||||||
public ReactiveListener(ReactiveStream<T> stream) : base(stream) { }
|
public ReactiveListener(ReactiveStream<T> stream) : base(stream) { }
|
||||||
|
public ReactiveListener(ICollection<ReactiveStream<T>> streams) : base(streams) { }
|
||||||
|
|
||||||
public EventHandlerAsync<T> ElementAddedHandler;
|
|
||||||
public void SetHandler(EventHandlerAsync<T> handler)
|
public event Action<ReactiveStream<T>, T> ElementAddedEvent;
|
||||||
{
|
void ElementAdded(ReactiveStream<T> stream, TimeSignedObject<T> e) => ElementAdded(stream, e.Value);
|
||||||
lock (Stream) ElementAddedHandler = handler;
|
void ElementAdded(ReactiveStream<T> stream, T e) =>
|
||||||
}
|
Task.Run(() => ElementAddedEvent?.Invoke(stream, e));
|
||||||
public async Task ElementAdded(T e) => await Task.Run(() => ElementAddedHandler?.Invoke(e));
|
|
||||||
|
|
||||||
public override void Join(ReactiveStream<T> stream)
|
public override void Join(ReactiveStream<T> stream)
|
||||||
{
|
{
|
||||||
base.Join(stream);
|
base.Join(stream);
|
||||||
lock (Stream) stream.ElementAddedEvent += ElementAdded;
|
lock (Streams) stream.ElementAddedEvent += ElementAdded;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Leave(ReactiveStream<T> stream)
|
public override void Leave(ReactiveStream<T> stream)
|
||||||
{
|
{
|
||||||
base.Leave(stream);
|
base.Leave(stream);
|
||||||
lock (Stream) stream.ElementAddedEvent -= ElementAdded;
|
lock (Streams) stream.ElementAddedEvent -= ElementAdded;
|
||||||
}
|
}
|
||||||
|
|
||||||
public T GetFirstElement() => Stream[0];
|
public T GetFirst()
|
||||||
public T GetLastElement() => Stream[Stream.Length - 1];
|
{
|
||||||
|
if (Streams.Count == 0) throw new Exception("ReactiveListener is not connected to any streams");
|
||||||
|
TimeSignedObject<T> rezult = null;
|
||||||
|
foreach (ReactiveStream<T> stream in Streams)
|
||||||
|
if (stream.Count != 0)
|
||||||
|
{
|
||||||
|
TimeSignedObject<T> e = stream[0];
|
||||||
|
if (rezult is null) rezult = e;
|
||||||
|
else if (rezult.Time > e.Time) rezult = e;
|
||||||
|
}
|
||||||
|
return rezult.Value;
|
||||||
|
}
|
||||||
|
public T GetLast()
|
||||||
|
{
|
||||||
|
if (Streams.Count == 0) throw new Exception("ReactiveListener is not connected to any streams");
|
||||||
|
TimeSignedObject<T> rezult = null;
|
||||||
|
foreach (ReactiveStream<T> stream in Streams)
|
||||||
|
if (stream.Count != 0)
|
||||||
|
{
|
||||||
|
TimeSignedObject<T> e = stream[stream.Count - 1];
|
||||||
|
if (rezult is null) rezult = e;
|
||||||
|
else if (rezult.Time < e.Time) rezult = e;
|
||||||
|
}
|
||||||
|
return rezult.Value;
|
||||||
|
}
|
||||||
|
|
||||||
public T FindOne(Func<T, bool> condition) =>
|
public T FindOne(Func<T, bool> condition)
|
||||||
/*foreach (T el in Stream)
|
{
|
||||||
if (condition(el))
|
if (Streams.Count == 0) throw new Exception("ReactiveListener is not connected to any streams");
|
||||||
return el;*/
|
foreach (ReactiveStream<T> stream in Streams)
|
||||||
default;
|
foreach (TimeSignedObject<T> el in stream)
|
||||||
|
if (condition(el.Value))
|
||||||
|
return el.Value;
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimeSignedObject<T> FindOne(Func<TimeSignedObject<T>, bool> condition)
|
||||||
|
{
|
||||||
|
if (Streams.Count == 0) throw new Exception("ReactiveListener is not connected to any streams");
|
||||||
|
foreach (ReactiveStream<T> stream in Streams)
|
||||||
|
foreach (TimeSignedObject<T> el in stream)
|
||||||
|
if (condition(el))
|
||||||
|
return el;
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
public List<T> FindAll(Func<T, bool> condition)
|
public List<T> FindAll(Func<T, bool> condition)
|
||||||
{
|
{
|
||||||
List<T> elements = new();
|
if (Streams.Count == 0) throw new Exception("ReactiveListener is not connected to any streams");
|
||||||
/*foreach (T el in Stream)
|
List<T> rezults = new();
|
||||||
if (condition(el))
|
foreach (ReactiveStream<T> stream in Streams)
|
||||||
elements.Add(el);*/
|
foreach (TimeSignedObject<T> el in stream)
|
||||||
return elements;
|
if (condition(el.Value))
|
||||||
|
rezults.Add(el.Value);
|
||||||
|
return rezults;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TimeSignedObject<T>> FindAll(Func<TimeSignedObject<T>, bool> condition)
|
||||||
|
{
|
||||||
|
if (Streams.Count == 0) throw new Exception("ReactiveListener is not connected to any streams");
|
||||||
|
List<TimeSignedObject<T>> rezults = new();
|
||||||
|
foreach (ReactiveStream<T> stream in Streams)
|
||||||
|
foreach (TimeSignedObject<T> el in stream)
|
||||||
|
if (condition(el))
|
||||||
|
rezults.Add(el);
|
||||||
|
return rezults;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,28 +1,35 @@
|
|||||||
namespace DTLib.Reactive
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace DTLib.Reactive
|
||||||
{
|
{
|
||||||
public abstract class ReactiveProvider<T>
|
public abstract class ReactiveProvider<T>
|
||||||
{
|
{
|
||||||
protected ReactiveStream<T> Stream
|
protected List<ReactiveStream<T>> Streams
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{ lock (_stream) return _stream; }
|
{ lock (_streams) return _streams; }
|
||||||
set
|
set
|
||||||
{ lock (_stream) _stream = value; }
|
{ lock (_streams) _streams = value; }
|
||||||
}
|
}
|
||||||
protected ReactiveStream<T> _stream;
|
private List<ReactiveStream<T>> _streams = new();
|
||||||
|
|
||||||
public ReactiveProvider() { }
|
public ReactiveProvider() { }
|
||||||
|
public ReactiveProvider(ReactiveStream<T> stream) => Streams.Add(stream);
|
||||||
public ReactiveProvider(ReactiveStream<T> stream) => Join(stream);
|
public ReactiveProvider(ICollection<ReactiveStream<T>> streams) => Streams = streams.ToList();
|
||||||
|
|
||||||
public virtual void Join(ReactiveStream<T> stream)
|
public virtual void Join(ReactiveStream<T> stream)
|
||||||
{
|
{
|
||||||
lock (Stream) Stream = stream;
|
if (IsConnetcedTo(stream)) throw new Exception("ReactiveListener is already connected to the stream");
|
||||||
|
Streams.Add(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Leave(ReactiveStream<T> stream)
|
public virtual void Leave(ReactiveStream<T> stream)
|
||||||
{
|
{
|
||||||
lock (Stream) Stream = null;
|
if (!Streams.Remove(stream)) throw new Exception("ReactiveListener is not connected to the stream");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsConnetcedTo(ReactiveStream<T> stream) => Streams.Contains(stream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,18 @@
|
|||||||
namespace DTLib.Reactive
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace DTLib.Reactive
|
||||||
{
|
{
|
||||||
public class ReactiveSender<T> : ReactiveProvider<T>
|
public class ReactiveSender<T> : ReactiveProvider<T>
|
||||||
{
|
{
|
||||||
|
|
||||||
public ReactiveSender() { }
|
public ReactiveSender() { }
|
||||||
public ReactiveSender(ReactiveStream<T> stream) : base(stream) { }
|
public ReactiveSender(ReactiveStream<T> stream) : base(stream) { }
|
||||||
|
public ReactiveSender(ICollection<ReactiveStream<T>> streams) : base(streams) { }
|
||||||
|
|
||||||
public void Send(T e)
|
public void Send(T e)
|
||||||
{
|
{
|
||||||
lock (Stream) Stream.Add(e);
|
foreach (ReactiveStream<T> s in Streams)
|
||||||
|
s.Add(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,38 +1,74 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace DTLib.Reactive
|
namespace DTLib.Reactive
|
||||||
{
|
{
|
||||||
public class ReactiveStream<T>
|
public class ReactiveStream<T> : IEnumerable<TimeSignedObject<T>>, IList<TimeSignedObject<T>>
|
||||||
{
|
{
|
||||||
public ReactiveStream() { }
|
public ReactiveStream() { }
|
||||||
|
|
||||||
List<T> _storage = new();
|
List<TimeSignedObject<T>> _storage = new();
|
||||||
List<T> Storage
|
List<TimeSignedObject<T>> Storage
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{ lock (Storage) return _storage; }
|
{ lock (_storage) return _storage; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Length
|
public int Count => Storage.Count;
|
||||||
|
|
||||||
|
public TimeSignedObject<T> this[int index]
|
||||||
{
|
{
|
||||||
get
|
get => Storage[index];
|
||||||
{ lock (Storage) return Storage.Count; }
|
set => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public T this[int index]
|
public event Action<ReactiveStream<T>, TimeSignedObject<T>> ElementAddedEvent;
|
||||||
|
public void Add(TimeSignedObject<T> elem)
|
||||||
{
|
{
|
||||||
get
|
Storage.Add(elem);
|
||||||
{ lock (Storage) return Storage[index]; }
|
ElementAddedEvent?.Invoke(this, elem);
|
||||||
}
|
}
|
||||||
|
public void Add(T elem) => Add(new TimeSignedObject<T>(elem));
|
||||||
|
|
||||||
internal event EventHandlerAsync<T> ElementAddedEvent;
|
public void Clear() => Storage.Clear();
|
||||||
|
public int IndexOf(TimeSignedObject<T> item) => Storage.IndexOf(item);
|
||||||
|
public bool Contains(TimeSignedObject<T> item) => Storage.Contains(item);
|
||||||
|
|
||||||
internal void Add(T elem)
|
public IEnumerator<TimeSignedObject<T>> GetEnumerator() => new Enumerator(Storage);
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => new Enumerator(Storage);
|
||||||
|
|
||||||
|
struct Enumerator : IEnumerator<TimeSignedObject<T>>
|
||||||
{
|
{
|
||||||
lock (Storage) Storage.Add(elem);
|
public Enumerator(List<TimeSignedObject<T>> storage)
|
||||||
ElementAddedEvent?.Invoke(elem);
|
{
|
||||||
|
_storage = storage;
|
||||||
|
_index = storage.Count - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<TimeSignedObject<T>> _storage;
|
||||||
|
int _index;
|
||||||
|
public TimeSignedObject<T> Current => _storage[_index];
|
||||||
|
object IEnumerator.Current => Current;
|
||||||
|
|
||||||
|
public void Dispose() => _storage = null;
|
||||||
|
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
if (_index < 0)
|
||||||
|
return false;
|
||||||
|
_index--;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset() => _index = _storage.Count - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Clear() { lock (Storage) Storage.Clear(); }
|
bool ICollection<TimeSignedObject<T>>.IsReadOnly { get; } = false;
|
||||||
|
|
||||||
|
public void Insert(int index, TimeSignedObject<T> item) => throw new NotImplementedException();
|
||||||
|
public void RemoveAt(int index) => throw new NotImplementedException();
|
||||||
|
public void CopyTo(TimeSignedObject<T>[] array, int arrayIndex) => throw new NotImplementedException();
|
||||||
|
public bool Remove(TimeSignedObject<T> item) => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
16
Reactive/TimeSignedObject.cs
Normal file
16
Reactive/TimeSignedObject.cs
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DTLib.Reactive
|
||||||
|
{
|
||||||
|
public class TimeSignedObject<T>
|
||||||
|
{
|
||||||
|
public T Value { get; init; }
|
||||||
|
public long Time { get; init; }
|
||||||
|
|
||||||
|
public TimeSignedObject(T value)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
Time = DateTime.Now.Ticks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user