From dc4ec153b87f864be16f3fec0b32a39dcf58ce97 Mon Sep 17 00:00:00 2001 From: bfren Date: Fri, 27 Feb 2026 12:04:48 +0000 Subject: [PATCH 1/4] Adding direct implementations instead of overloads - #63 --- .../Enumerable/EnumerableExtensions.Bind.cs | 52 +++++++++++--- .../Enumerable/EnumerableExtensions.Filter.cs | 64 ++++++++++++++--- .../EnumerableExtensions.FilterBind.cs | 72 +++++++++++++++---- .../EnumerableExtensions.FilterMap.cs | 72 +++++++++++++++---- .../EnumerableExtensions.Iterate.cs | 48 ++++++++++--- .../Enumerable/EnumerableExtensions.Map.cs | 52 +++++++++++--- 6 files changed, 304 insertions(+), 56 deletions(-) diff --git a/src/All/Extensions/Enumerable/EnumerableExtensions.Bind.cs b/src/All/Extensions/Enumerable/EnumerableExtensions.Bind.cs index 7b867a2b..6fdafd69 100644 --- a/src/All/Extensions/Enumerable/EnumerableExtensions.Bind.cs +++ b/src/All/Extensions/Enumerable/EnumerableExtensions.Bind.cs @@ -28,12 +28,30 @@ public static IEnumerable> Bind(this IEnumerable - public static Task>> BindAsync(this IEnumerable> @this, Func>> f) => - BindAsync(Task.FromResult(@this), f); + public static async Task>> BindAsync(this IEnumerable> @this, Func>> f) + { + var items = new List>(); + + foreach (var item in @this.Filter()) + { + items.Add(await item.BindAsync(f)); + } + + return items; + } /// - public static Task>> BindAsync(this Task>> @this, Func> f) => - BindAsync(@this, async x => f(x)); + public static async Task>> BindAsync(this Task>> @this, Func> f) + { + var items = new List>(); + + foreach (var item in await @this.FilterAsync()) + { + items.Add(item.Bind(f)); + } + + return items; + } /// public static async Task>> BindAsync(this Task>> @this, Func>> f) @@ -69,12 +87,30 @@ public static IEnumerable> Bind(this IEnumerable - public static Task>> BindAsync(this IEnumerable> @this, Func>> f) => - BindAsync(Task.FromResult(@this), f); + public static async Task>> BindAsync(this IEnumerable> @this, Func>> f) + { + var items = new List>(); + + foreach (var item in @this) + { + items.Add(await item.BindAsync(f)); + } + + return items; + } /// - public static Task>> BindAsync(this Task>> @this, Func> f) => - BindAsync(@this, async x => f(x)); + public static async Task>> BindAsync(this Task>> @this, Func> f) + { + var items = new List>(); + + foreach (var item in await @this) + { + items.Add(item.Bind(f)); + } + + return items; + } /// public static async Task>> BindAsync(this Task>> @this, Func>> f) diff --git a/src/All/Extensions/Enumerable/EnumerableExtensions.Filter.cs b/src/All/Extensions/Enumerable/EnumerableExtensions.Filter.cs index 79e4fc0c..0d260371 100644 --- a/src/All/Extensions/Enumerable/EnumerableExtensions.Filter.cs +++ b/src/All/Extensions/Enumerable/EnumerableExtensions.Filter.cs @@ -63,12 +63,36 @@ public static IEnumerable> Filter(this IEnumerable> @this, } /// - public static Task>> FilterAsync(this IEnumerable> @this, Func> fTest) => - FilterAsync(Task.FromResult(@this), fTest); + public static async Task>> FilterAsync(this IEnumerable> @this, Func> fTest) + { + var list = new List>(); + + foreach (var item in @this) + { + foreach (var value in await item.FilterAsync(fTest)) + { + list.Add(value); + } + } + + return list; + } /// - public static Task>> FilterAsync(this Task>> @this, Func fTest) => - FilterAsync(@this, async x => fTest(x)); + public static async Task>> FilterAsync(this Task>> @this, Func fTest) + { + var list = new List>(); + + foreach (var item in await @this) + { + foreach (var value in item.Filter(fTest)) + { + list.Add(value); + } + } + + return list; + } /// public static async Task>> FilterAsync(this Task>> @this, Func> fTest) @@ -109,12 +133,36 @@ public static IEnumerable> Filter(this IEnumerable> @this } /// - public static Task>> FilterAsync(this IEnumerable> @this, Func> fTest) => - FilterAsync(Task.FromResult(@this), fTest); + public static async Task>> FilterAsync(this IEnumerable> @this, Func> fTest) + { + var list = new List>(); + + foreach (var item in @this) + { + foreach (var value in await item.FilterAsync(fTest).Unsafe()) + { + list.Add(value); + } + } + + return list; + } /// - public static Task>> FilterAsync(this Task>> @this, Func fTest) => - FilterAsync(@this, async x => fTest(x)); + public static async Task>> FilterAsync(this Task>> @this, Func fTest) + { + var list = new List>(); + + foreach (var item in await @this) + { + foreach (var value in item.Filter(fTest).Unsafe()) + { + list.Add(value); + } + } + + return list; + } /// public static async Task>> FilterAsync(this Task>> @this, Func> fTest) diff --git a/src/All/Extensions/Enumerable/EnumerableExtensions.FilterBind.cs b/src/All/Extensions/Enumerable/EnumerableExtensions.FilterBind.cs index 1119e7b2..47f40a50 100644 --- a/src/All/Extensions/Enumerable/EnumerableExtensions.FilterBind.cs +++ b/src/All/Extensions/Enumerable/EnumerableExtensions.FilterBind.cs @@ -35,18 +35,42 @@ Func> f } /// - public static Task>> FilterBindAsync(this IEnumerable> @this, + public static async Task>> FilterBindAsync(this IEnumerable> @this, Func fTest, Func>> f - ) => - FilterBindAsync(Task.FromResult(@this), fTest, f); + ) + { + var items = new List>(); + + foreach (var item in @this) + { + foreach (var value in await item.BindIfAsync(fTest, f)) + { + items.Add(value); + } + } + + return items; + } /// - public static Task>> FilterBindAsync(this Task>> @this, + public static async Task>> FilterBindAsync(this Task>> @this, Func fTest, Func> f - ) => - FilterBindAsync(@this, fTest, async x => f(x)); + ) + { + var items = new List>(); + + foreach (var item in await @this) + { + foreach (var value in item.BindIf(fTest, f)) + { + items.Add(value); + } + } + + return items; + } /// public static async Task>> FilterBindAsync(this Task>> @this, @@ -95,18 +119,42 @@ Func> f } /// - public static Task>> FilterBindAsync(this IEnumerable> @this, + public static async Task>> FilterBindAsync(this IEnumerable> @this, Func fTest, Func>> f - ) => - FilterBindAsync(Task.FromResult(@this), fTest, f); + ) + { + var items = new List>(); + + foreach (var item in @this) + { + foreach (var value in await item.BindIfAsync(fTest, f).Unsafe()) + { + items.Add(value); + } + } + + return items; + } /// - public static Task>> FilterBindAsync(this Task>> @this, + public static async Task>> FilterBindAsync(this Task>> @this, Func fTest, Func> f - ) => - FilterBindAsync(@this, fTest, async x => f(x)); + ) + { + var items = new List>(); + + foreach (var item in await @this) + { + foreach (var value in item.BindIf(fTest, f).Unsafe()) + { + items.Add(value); + } + } + + return items; + } /// public static async Task>> FilterBindAsync(this Task>> @this, diff --git a/src/All/Extensions/Enumerable/EnumerableExtensions.FilterMap.cs b/src/All/Extensions/Enumerable/EnumerableExtensions.FilterMap.cs index 68249a56..3a7df4e5 100644 --- a/src/All/Extensions/Enumerable/EnumerableExtensions.FilterMap.cs +++ b/src/All/Extensions/Enumerable/EnumerableExtensions.FilterMap.cs @@ -35,18 +35,42 @@ Func f } /// - public static Task>> FilterMapAsync(this IEnumerable> @this, + public static async Task>> FilterMapAsync(this IEnumerable> @this, Func fTest, Func> f - ) => - FilterMapAsync(Task.FromResult(@this), fTest, f); + ) + { + var list = new List>(); + + foreach (var item in @this) + { + foreach (var value in await item.MapIfAsync(fTest, f)) + { + list.Add(value); + } + } + + return list; + } /// - public static Task>> FilterMapAsync(this Task>> @this, + public static async Task>> FilterMapAsync(this Task>> @this, Func fTest, Func f - ) => - FilterMapAsync(@this, fTest, async x => f(x)); + ) + { + var list = new List>(); + + foreach (var item in await @this) + { + foreach (var value in item.MapIf(fTest, f)) + { + list.Add(value); + } + } + + return list; + } /// public static async Task>> FilterMapAsync(this Task>> @this, @@ -95,18 +119,42 @@ Func f } /// - public static Task>> FilterMapAsync(this IEnumerable> @this, + public static async Task>> FilterMapAsync(this IEnumerable> @this, Func fTest, Func> f - ) => - FilterMapAsync(Task.FromResult(@this), fTest, f); + ) + { + var list = new List>(); + + foreach (var item in @this) + { + foreach (var value in await item.MapIfAsync(fTest, f).Unsafe()) + { + list.Add(value); + } + } + + return list; + } /// - public static Task>> FilterMapAsync(this Task>> @this, + public static async Task>> FilterMapAsync(this Task>> @this, Func fTest, Func f - ) => - FilterMapAsync(@this, fTest, async x => f(x)); + ) + { + var list = new List>(); + + foreach (var item in await @this) + { + foreach (var value in item.MapIf(fTest, f).Unsafe()) + { + list.Add(value); + } + } + + return list; + } /// public static async Task>> FilterMapAsync(this Task>> @this, diff --git a/src/All/Extensions/Enumerable/EnumerableExtensions.Iterate.cs b/src/All/Extensions/Enumerable/EnumerableExtensions.Iterate.cs index 62f17ce0..d5384acc 100644 --- a/src/All/Extensions/Enumerable/EnumerableExtensions.Iterate.cs +++ b/src/All/Extensions/Enumerable/EnumerableExtensions.Iterate.cs @@ -30,12 +30,28 @@ public static void Iterate(this IEnumerable> @this, Action f) } /// - public static Task IterateAsync(this IEnumerable> @this, Func f) => - IterateAsync(Task.FromResult(@this), f); + public static async Task IterateAsync(this IEnumerable> @this, Func f) + { + foreach (var item in @this) + { + foreach (var value in item) + { + await f(value); + } + } + } /// - public static Task IterateAsync(this Task>> @this, Action f) => - IterateAsync(@this, async x => f(x)); + public static async Task IterateAsync(this Task>> @this, Action f) + { + foreach (var item in await @this) + { + foreach (var value in item) + { + f(value); + } + } + } /// public static async Task IterateAsync(this Task>> @this, Func f) @@ -72,12 +88,28 @@ public static void Iterate(this IEnumerable> @this, Action f) } /// - public static Task IterateAsync(this IEnumerable> @this, Func f) => - IterateAsync(Task.FromResult(@this), f); + public static async Task IterateAsync(this IEnumerable> @this, Func f) + { + foreach (var item in @this) + { + foreach (var value in item.Unsafe()) + { + await f(value); + } + } + } /// - public static Task IterateAsync(this Task>> @this, Action f) => - IterateAsync(@this, async x => f(x)); + public static async Task IterateAsync(this Task>> @this, Action f) + { + foreach (var item in await @this) + { + foreach (var value in item.Unsafe()) + { + f(value); + } + } + } /// public static async Task IterateAsync(this Task>> @this, Func f) diff --git a/src/All/Extensions/Enumerable/EnumerableExtensions.Map.cs b/src/All/Extensions/Enumerable/EnumerableExtensions.Map.cs index 4bb8f97f..fc6bc1d9 100644 --- a/src/All/Extensions/Enumerable/EnumerableExtensions.Map.cs +++ b/src/All/Extensions/Enumerable/EnumerableExtensions.Map.cs @@ -28,12 +28,30 @@ public static IEnumerable> Map(this IEnumerable - public static Task>> MapAsync(this IEnumerable> @this, Func> f) => - MapAsync(Task.FromResult(@this), f); + public static async Task>> MapAsync(this IEnumerable> @this, Func> f) + { + var list = new List>(); + + foreach (var item in @this) + { + list.Add(await item.MapAsync(f)); + } + + return list; + } /// - public static Task>> MapAsync(this Task>> @this, Func f) => - MapAsync(@this, async x => f(x)); + public static async Task>> MapAsync(this Task>> @this, Func f) + { + var list = new List>(); + + foreach (var item in await @this) + { + list.Add(item.Map(f)); + } + + return list; + } /// public static async Task>> MapAsync(this Task>> @this, Func> f) @@ -69,12 +87,30 @@ public static IEnumerable> Map(this IEnumerable - public static Task>> MapAsync(this IEnumerable> @this, Func> f) => - MapAsync(Task.FromResult(@this), f); + public static async Task>> MapAsync(this IEnumerable> @this, Func> f) + { + var list = new List>(); + + foreach (var item in @this) + { + list.Add(await item.MapAsync(f)); + } + + return list; + } /// - public static Task>> MapAsync(this Task>> @this, Func f) => - MapAsync(@this, async x => f(x)); + public static async Task>> MapAsync(this Task>> @this, Func f) + { + var list = new List>(); + + foreach (var item in await @this) + { + list.Add(item.Map(f)); + } + + return list; + } /// public static async Task>> MapAsync(this Task>> @this, Func> f) From 15e0bcb69235c21a89923a9c37395878ac667890 Mon Sep 17 00:00:00 2001 From: bfren Date: Fri, 27 Feb 2026 12:07:09 +0000 Subject: [PATCH 2/4] Write directly to Utf8JsonWriter - #63 --- src/All/Json/MonadJsonConverter.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/All/Json/MonadJsonConverter.cs b/src/All/Json/MonadJsonConverter.cs index cb4cf18f..60238e5b 100644 --- a/src/All/Json/MonadJsonConverter.cs +++ b/src/All/Json/MonadJsonConverter.cs @@ -60,7 +60,6 @@ public override void Write(Utf8JsonWriter writer, TMonad value, JsonSerializerOp return; } - var json = JsonSerializer.SerializeToUtf8Bytes(value.Value, options); - writer.WriteRawValue(json); + JsonSerializer.Serialize(writer, value.Value, options); } } From 3e2fc09dae7074a2761392cbc6fec97ab8825ade Mon Sep 17 00:00:00 2001 From: bfren Date: Fri, 27 Feb 2026 12:08:20 +0000 Subject: [PATCH 3/4] Adding GetOrCreate overload when no options - #63 --- src/Caching/WrapCache.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/Caching/WrapCache.cs b/src/Caching/WrapCache.cs index 6148bc9e..99879a2b 100644 --- a/src/Caching/WrapCache.cs +++ b/src/Caching/WrapCache.cs @@ -108,7 +108,12 @@ public Maybe GetOrCreate(TKey key, Func valueFactory, Me GetOrCreate(key, () => M.Wrap(valueFactory()), opt); /// - public Maybe GetOrCreate(TKey key, Func> valueFactory) + public Maybe GetOrCreate(TKey key, Func> valueFactory) => + GetOrCreate(key, valueFactory, new()); + + + /// + public Maybe GetOrCreate(TKey key, Func> valueFactory, MemoryCacheEntryOptions opt) { // Check whether or not the value already exists var value = GetValue(key); @@ -133,7 +138,7 @@ public Maybe GetOrCreate(TKey key, Func> valueFact .Ctx(nameof(WrapCache), nameof(GetOrCreate)) ) .Map( - x => Cache.GetOrCreate(key, e => { _ = e.SetValue(x!); return x; })! + x => Cache.GetOrCreate(key, e => { _ = e.SetOptions(opt).SetValue(x!); return x; })! ); } catch (Exception ex) @@ -150,10 +155,6 @@ public Maybe GetOrCreate(TKey key, Func> valueFact } } - /// - public Maybe GetOrCreate(TKey key, Func> valueFactory, MemoryCacheEntryOptions opt) => - GetOrCreateAsync(key, async () => valueFactory(), opt).Result; - /// public Task> GetOrCreateAsync(TKey key, Func> valueFactory) => GetOrCreateAsync(key, async () => M.Wrap(await valueFactory()), new()); From 70448569cc3785b3ba0d002cf412406116324c35 Mon Sep 17 00:00:00 2001 From: bfren Date: Fri, 27 Feb 2026 12:14:50 +0000 Subject: [PATCH 4/4] Cache GetProperty in F.Format - #63 --- src/Common/Functions/F.Format.cs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Common/Functions/F.Format.cs b/src/Common/Functions/F.Format.cs index 28c63eb0..f0cfb60d 100644 --- a/src/Common/Functions/F.Format.cs +++ b/src/Common/Functions/F.Format.cs @@ -2,6 +2,7 @@ // Copyright (c) bfren - licensed under https://mit.bfren.dev/2019 using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Reflection; using System.Text.RegularExpressions; @@ -10,6 +11,9 @@ namespace Wrap; public static partial class F { + internal static ConcurrentDictionary> TypeInfoCache = + new(); + /// public static string Format(string formatString, T source) => Format(formatString, source, null); @@ -41,7 +45,6 @@ public static string Format(string formatString, T source, string? replaceIfN var values = new List(regex.Count(formatString)); var replaceIndex = 0; // keeps track of replace loop so we can match named template values with an array source var numberedTemplates = true; - var flags = BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance; var rewrittenFormat = regex.Replace(formatString, (m) => { // This is the value inside the braces, e.g. "0" in "{0}" or "A" in "{A}" @@ -66,7 +69,7 @@ public static string Format(string formatString, T source, string? replaceIfN val, // Source object - get matching property value for named template - { } obj when !numberedTemplates && typeof(T).GetProperty(template, flags)?.GetValue(obj) is object val => + { } obj when !numberedTemplates && PropertyCache.GetProperty(template)?.GetValue(obj) is object val => val, // Nothing matches so put placeholder back @@ -132,4 +135,13 @@ public static string Format(string formatString, T source, string? replaceIfN /// [GeneratedRegex("(?\\{)+(?