mirror of
https://github.com/wabbajack-tools/wabbajack.git
synced 2024-08-30 18:42:17 +00:00
DictionaryExt. Other Ext files migrated to Common
This commit is contained in:
parent
21b603e78a
commit
fa504a1b16
25
Wabbajack.Common/Extensions/DictionaryExt.cs
Normal file
25
Wabbajack.Common/Extensions/DictionaryExt.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
public static class DictionaryExt
|
||||
{
|
||||
public static V TryCreate<K, V>(this IDictionary<K, V> dict, K key)
|
||||
where V : new()
|
||||
{
|
||||
return dict.TryCreate(key, () => new V());
|
||||
}
|
||||
|
||||
public static V TryCreate<K, V>(this IDictionary<K, V> dict, K key, Func<V> create)
|
||||
{
|
||||
if (dict.TryGetValue(key, out var val)) return val;
|
||||
var ret = create();
|
||||
dict[key] = ret;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
172
Wabbajack.Common/Extensions/RxExt.cs
Normal file
172
Wabbajack.Common/Extensions/RxExt.cs
Normal file
@ -0,0 +1,172 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Concurrency;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Wabbajack
|
||||
{
|
||||
public static class RxExt
|
||||
{
|
||||
/// <summary>
|
||||
/// Convenience function that discards events that are null
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="source"></param>
|
||||
/// <returns>Source events that are not null</returns>
|
||||
public static IObservable<T> NotNull<T>(this IObservable<T> source)
|
||||
where T : class
|
||||
{
|
||||
return source.Where(u => u != null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts any observable to type Unit. Useful for when you care that a signal occurred,
|
||||
/// but don't care about what its value is downstream.
|
||||
/// </summary>
|
||||
/// <returns>An observable that returns Unit anytime the source signal fires an event.</returns>
|
||||
public static IObservable<Unit> Unit<T>(this IObservable<T> source)
|
||||
{
|
||||
return source.Select(_ => System.Reactive.Unit.Default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convenience operator to subscribe to the source observable, only when a second "switch" observable is on.
|
||||
/// When the switch is on, the source will be subscribed to, and its updates passed through.
|
||||
/// When the switch is off, the subscription to the source observable will be stopped, and no signal will be published.
|
||||
/// </summary>
|
||||
/// <param name="source">Source observable to subscribe to if on</param>
|
||||
/// <param name="filterSwitch">On/Off signal of whether to subscribe to source observable</param>
|
||||
/// <returns>Observable that publishes data from source, if the switch is on.</returns>
|
||||
public static IObservable<T> FilterSwitch<T>(this IObservable<T> source, IObservable<bool> filterSwitch)
|
||||
{
|
||||
return filterSwitch
|
||||
.DistinctUntilChanged()
|
||||
.Select(on =>
|
||||
{
|
||||
if (on)
|
||||
{
|
||||
return source;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Observable.Empty<T>();
|
||||
}
|
||||
})
|
||||
.Switch();
|
||||
}
|
||||
|
||||
|
||||
/// Inspiration:
|
||||
/// http://reactivex.io/documentation/operators/debounce.html
|
||||
/// https://stackoverflow.com/questions/20034476/how-can-i-use-reactive-extensions-to-throttle-events-using-a-max-window-size
|
||||
public static IObservable<T> Debounce<T>(this IObservable<T> source, TimeSpan interval, IScheduler scheduler = null)
|
||||
{
|
||||
scheduler = scheduler ?? Scheduler.Default;
|
||||
return Observable.Create<T>(o =>
|
||||
{
|
||||
var hasValue = false;
|
||||
bool throttling = false;
|
||||
T value = default;
|
||||
|
||||
var dueTimeDisposable = new SerialDisposable();
|
||||
|
||||
void internalCallback()
|
||||
{
|
||||
if (hasValue)
|
||||
{
|
||||
// We have another value that came in to fire.
|
||||
// Reregister for callback
|
||||
dueTimeDisposable.Disposable = scheduler.Schedule(interval, internalCallback);
|
||||
o.OnNext(value);
|
||||
value = default;
|
||||
hasValue = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nothing to do, throttle is complete.
|
||||
throttling = false;
|
||||
}
|
||||
}
|
||||
|
||||
return source.Subscribe(
|
||||
onNext: (x) =>
|
||||
{
|
||||
if (!throttling)
|
||||
{
|
||||
// Fire initial value
|
||||
o.OnNext(x);
|
||||
// Mark that we're throttling
|
||||
throttling = true;
|
||||
// Register for callback when throttle is complete
|
||||
dueTimeDisposable.Disposable = scheduler.Schedule(interval, internalCallback);
|
||||
}
|
||||
else
|
||||
{
|
||||
// In the middle of throttle
|
||||
// Save value and return
|
||||
hasValue = true;
|
||||
value = x;
|
||||
}
|
||||
},
|
||||
onError: o.OnError,
|
||||
onCompleted: o.OnCompleted);
|
||||
});
|
||||
}
|
||||
|
||||
public static IObservable<Unit> SelectTask<T>(this IObservable<T> source, Func<T, Task> task)
|
||||
{
|
||||
return source
|
||||
.SelectMany(async i =>
|
||||
{
|
||||
await task(i).ConfigureAwait(false);
|
||||
return System.Reactive.Unit.Default;
|
||||
});
|
||||
}
|
||||
|
||||
public static IObservable<Unit> SelectTask<T>(this IObservable<T> source, Func<Task> task)
|
||||
{
|
||||
return source
|
||||
.SelectMany(async _ =>
|
||||
{
|
||||
await task().ConfigureAwait(false);
|
||||
return System.Reactive.Unit.Default;
|
||||
});
|
||||
}
|
||||
|
||||
public static IObservable<R> SelectTask<T, R>(this IObservable<T> source, Func<Task<R>> task)
|
||||
{
|
||||
return source
|
||||
.SelectMany(_ => task());
|
||||
}
|
||||
|
||||
public static IObservable<R> SelectTask<T, R>(this IObservable<T> source, Func<T, Task<R>> task)
|
||||
{
|
||||
return source
|
||||
.SelectMany(x => task(x));
|
||||
}
|
||||
|
||||
public static IObservable<T> DoTask<T>(this IObservable<T> source, Func<T, Task> task)
|
||||
{
|
||||
return source
|
||||
.SelectMany(async (x) =>
|
||||
{
|
||||
await task(x).ConfigureAwait(false);
|
||||
return x;
|
||||
});
|
||||
}
|
||||
|
||||
public static IObservable<R> WhereCastable<T, R>(this IObservable<T> source)
|
||||
where R : class
|
||||
where T : class
|
||||
{
|
||||
return source
|
||||
.Select(x => x as R)
|
||||
.NotNull();
|
||||
}
|
||||
}
|
||||
}
|
@ -92,7 +92,10 @@
|
||||
<Compile Include="Error States\ErrorResponse.cs" />
|
||||
<Compile Include="Error States\GetResponse.cs" />
|
||||
<Compile Include="ExtensionManager.cs" />
|
||||
<Compile Include="Extensions\DictionaryExt.cs" />
|
||||
<Compile Include="Extensions\HashHelper.cs" />
|
||||
<Compile Include="Extensions\RxExt.cs" />
|
||||
<Compile Include="Extensions\TaskExt.cs" />
|
||||
<Compile Include="FileExtractor.cs" />
|
||||
<Compile Include="GameMetaData.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
|
@ -116,7 +116,6 @@
|
||||
<Compile Include="Downloaders\MEGADownloader.cs" />
|
||||
<Compile Include="Downloaders\ModDBDownloader.cs" />
|
||||
<Compile Include="Downloaders\NexusDownloader.cs" />
|
||||
<Compile Include="Extensions\TaskExt.cs" />
|
||||
<Compile Include="Installer.cs" />
|
||||
<Compile Include="ModListRegistry\ModListMetadata.cs" />
|
||||
<Compile Include="NexusApi\Dtos.cs" />
|
||||
|
@ -31,18 +31,6 @@ namespace Wabbajack
|
||||
return This.WhenAny(property1, selector: x => x.GetValue());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convenience function that discards events that are null
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="source"></param>
|
||||
/// <returns>Source events that are not null</returns>
|
||||
public static IObservable<T> NotNull<T>(this IObservable<T> source)
|
||||
where T : class
|
||||
{
|
||||
return source.Where(u => u != null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convenience wrapper to observe following calls on the GUI thread.
|
||||
/// </summary>
|
||||
@ -51,42 +39,6 @@ namespace Wabbajack
|
||||
return source.ObserveOn(RxApp.MainThreadScheduler);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts any observable to type Unit. Useful for when you care that a signal occurred,
|
||||
/// but don't care about what its value is downstream.
|
||||
/// </summary>
|
||||
/// <returns>An observable that returns Unit anytime the source signal fires an event.</returns>
|
||||
public static IObservable<Unit> Unit<T>(this IObservable<T> source)
|
||||
{
|
||||
return source.Select(_ => System.Reactive.Unit.Default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convenience operator to subscribe to the source observable, only when a second "switch" observable is on.
|
||||
/// When the switch is on, the source will be subscribed to, and its updates passed through.
|
||||
/// When the switch is off, the subscription to the source observable will be stopped, and no signal will be published.
|
||||
/// </summary>
|
||||
/// <param name="source">Source observable to subscribe to if on</param>
|
||||
/// <param name="filterSwitch">On/Off signal of whether to subscribe to source observable</param>
|
||||
/// <returns>Observable that publishes data from source, if the switch is on.</returns>
|
||||
public static IObservable<T> FilterSwitch<T>(this IObservable<T> source, IObservable<bool> filterSwitch)
|
||||
{
|
||||
return filterSwitch
|
||||
.DistinctUntilChanged()
|
||||
.Select(on =>
|
||||
{
|
||||
if (on)
|
||||
{
|
||||
return source;
|
||||
}
|
||||
else
|
||||
{
|
||||
return Observable.Empty<T>();
|
||||
}
|
||||
})
|
||||
.Switch();
|
||||
}
|
||||
|
||||
public static IObservable<Unit> StartingExecution(this IReactiveCommand cmd)
|
||||
{
|
||||
return cmd.IsExecuting
|
||||
@ -95,114 +47,6 @@ namespace Wabbajack
|
||||
.Unit();
|
||||
}
|
||||
|
||||
/// Inspiration:
|
||||
/// http://reactivex.io/documentation/operators/debounce.html
|
||||
/// https://stackoverflow.com/questions/20034476/how-can-i-use-reactive-extensions-to-throttle-events-using-a-max-window-size
|
||||
public static IObservable<T> Debounce<T>(this IObservable<T> source, TimeSpan interval, IScheduler scheduler = null)
|
||||
{
|
||||
scheduler = scheduler ?? Scheduler.Default;
|
||||
return Observable.Create<T>(o =>
|
||||
{
|
||||
var hasValue = false;
|
||||
bool throttling = false;
|
||||
T value = default;
|
||||
|
||||
var dueTimeDisposable = new SerialDisposable();
|
||||
|
||||
void internalCallback()
|
||||
{
|
||||
if (hasValue)
|
||||
{
|
||||
// We have another value that came in to fire.
|
||||
// Reregister for callback
|
||||
dueTimeDisposable.Disposable = scheduler.Schedule(interval, internalCallback);
|
||||
o.OnNext(value);
|
||||
value = default;
|
||||
hasValue = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Nothing to do, throttle is complete.
|
||||
throttling = false;
|
||||
}
|
||||
}
|
||||
|
||||
return source.Subscribe(
|
||||
onNext: (x) =>
|
||||
{
|
||||
if (!throttling)
|
||||
{
|
||||
// Fire initial value
|
||||
o.OnNext(x);
|
||||
// Mark that we're throttling
|
||||
throttling = true;
|
||||
// Register for callback when throttle is complete
|
||||
dueTimeDisposable.Disposable = scheduler.Schedule(interval, internalCallback);
|
||||
}
|
||||
else
|
||||
{
|
||||
// In the middle of throttle
|
||||
// Save value and return
|
||||
hasValue = true;
|
||||
value = x;
|
||||
}
|
||||
},
|
||||
onError: o.OnError,
|
||||
onCompleted: o.OnCompleted);
|
||||
});
|
||||
}
|
||||
|
||||
public static IObservable<Unit> SelectTask<T>(this IObservable<T> source, Func<T, Task> task)
|
||||
{
|
||||
return source
|
||||
.SelectMany(async i =>
|
||||
{
|
||||
await task(i).ConfigureAwait(false);
|
||||
return System.Reactive.Unit.Default;
|
||||
});
|
||||
}
|
||||
|
||||
public static IObservable<Unit> SelectTask<T>(this IObservable<T> source, Func<Task> task)
|
||||
{
|
||||
return source
|
||||
.SelectMany(async _ =>
|
||||
{
|
||||
await task().ConfigureAwait(false);
|
||||
return System.Reactive.Unit.Default;
|
||||
});
|
||||
}
|
||||
|
||||
public static IObservable<R> SelectTask<T, R>(this IObservable<T> source, Func<Task<R>> task)
|
||||
{
|
||||
return source
|
||||
.SelectMany(_ => task());
|
||||
}
|
||||
|
||||
public static IObservable<R> SelectTask<T, R>(this IObservable<T> source, Func<T, Task<R>> task)
|
||||
{
|
||||
return source
|
||||
.SelectMany(x => task(x));
|
||||
}
|
||||
|
||||
public static IObservable<T> DoTask<T>(this IObservable<T> source, Func<T, Task> task)
|
||||
{
|
||||
return source
|
||||
.SelectMany(async (x) =>
|
||||
{
|
||||
await task(x).ConfigureAwait(false);
|
||||
return x;
|
||||
});
|
||||
}
|
||||
|
||||
public static IObservable<R> WhereCastable<T, R>(this IObservable<T> source)
|
||||
where R : class
|
||||
where T : class
|
||||
{
|
||||
return source
|
||||
.Select(x => x as R)
|
||||
.NotNull();
|
||||
}
|
||||
|
||||
/// These snippets were provided by RolandPheasant (author of DynamicData)
|
||||
/// They'll be going into the official library at some point, but are here for now.
|
||||
#region Dynamic Data EnsureUniqueChanges
|
||||
|
Loading…
Reference in New Issue
Block a user