Amend Navigation
This commit is contained in:
@@ -1,12 +1,6 @@
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace Toolkit.Controls.Avalonia;
|
||||
namespace Toolkit.Controls.Avalonia;
|
||||
|
||||
public class FAPathIcon : FluentAvalonia.UI.Controls.FAPathIcon
|
||||
{
|
||||
}
|
||||
|
||||
public class SymbolIcon : FluentAvalonia.UI.Controls.SymbolIcon
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Toolkit.Controls.Avalonia;
|
||||
|
||||
public class FontIcon : FluentAvalonia.UI.Controls.FontIcon
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Toolkit.Controls.Avalonia;
|
||||
|
||||
public class SymbolIcon : FluentAvalonia.UI.Controls.SymbolIcon
|
||||
{
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Data;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using System.Xml.Linq;
|
||||
using Toolkit.Framework.Foundation;
|
||||
|
||||
namespace Toolkit.Framework.Avalonia;
|
||||
@@ -13,55 +14,50 @@ public class NavigateExtension : TriggerExtension
|
||||
private static readonly AttachedProperty<object> ParameterProperty =
|
||||
AvaloniaProperty.RegisterAttached<NavigateExtension, Control, object>("Parameter");
|
||||
|
||||
private static readonly AvaloniaProperty RouteProperty =
|
||||
AvaloniaProperty.RegisterAttached<NavigateExtension, Control, object>("Route");
|
||||
|
||||
private static readonly AvaloniaProperty ToProperty =
|
||||
AvaloniaProperty.RegisterAttached<NavigateExtension, Control, object>("To");
|
||||
private static readonly AvaloniaProperty PathProperty =
|
||||
AvaloniaProperty.RegisterAttached<NavigateExtension, Control, string>("Path");
|
||||
|
||||
private readonly Binding? mediatorBinding;
|
||||
private readonly List<object?> parameters = new();
|
||||
private readonly Binding? toBinding;
|
||||
private object? route;
|
||||
private Binding? routeBinding;
|
||||
private readonly Binding? pathBinding;
|
||||
|
||||
public NavigateExtension(object mediator,
|
||||
object to)
|
||||
object path)
|
||||
{
|
||||
mediatorBinding = mediator.ToBinding();
|
||||
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
|
||||
this.pathBinding = path is Binding pathBinding ? pathBinding : path.ToBinding();
|
||||
}
|
||||
|
||||
public NavigateExtension(object mediator,
|
||||
object to,
|
||||
object path,
|
||||
object args1)
|
||||
{
|
||||
mediatorBinding = mediator.ToBinding();
|
||||
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
|
||||
this.pathBinding = path is Binding pathBinding ? pathBinding : path.ToBinding();
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
}
|
||||
|
||||
public NavigateExtension(object mediator,
|
||||
object to,
|
||||
object path,
|
||||
object args1,
|
||||
object args2)
|
||||
{
|
||||
mediatorBinding = mediator.ToBinding();
|
||||
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
|
||||
this.pathBinding = path is Binding pathBinding ? pathBinding : path.ToBinding();
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
}
|
||||
|
||||
public NavigateExtension(object mediator,
|
||||
object to,
|
||||
object path,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3)
|
||||
{
|
||||
mediatorBinding = mediator.ToBinding();
|
||||
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
|
||||
this.pathBinding = path is Binding pathBinding ? pathBinding : path.ToBinding();
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
@@ -69,14 +65,14 @@ public class NavigateExtension : TriggerExtension
|
||||
}
|
||||
|
||||
public NavigateExtension(object mediator,
|
||||
object to,
|
||||
object path,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
object args4)
|
||||
{
|
||||
mediatorBinding = mediator.ToBinding();
|
||||
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
|
||||
this.pathBinding = path is Binding pathBinding ? pathBinding : path.ToBinding();
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
@@ -85,7 +81,7 @@ public class NavigateExtension : TriggerExtension
|
||||
}
|
||||
|
||||
public NavigateExtension(object mediator,
|
||||
object to,
|
||||
object path,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
@@ -93,7 +89,7 @@ public class NavigateExtension : TriggerExtension
|
||||
object args5)
|
||||
{
|
||||
mediatorBinding = mediator.ToBinding();
|
||||
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
|
||||
this.pathBinding = path is Binding pathBinding ? pathBinding : path.ToBinding();
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
@@ -103,7 +99,7 @@ public class NavigateExtension : TriggerExtension
|
||||
}
|
||||
|
||||
public NavigateExtension(object mediator,
|
||||
object to,
|
||||
object path,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
@@ -112,7 +108,7 @@ public class NavigateExtension : TriggerExtension
|
||||
object args6)
|
||||
{
|
||||
mediatorBinding = mediator.ToBinding();
|
||||
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
|
||||
this.pathBinding = path is Binding pathBinding ? pathBinding : path.ToBinding();
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
@@ -123,7 +119,7 @@ public class NavigateExtension : TriggerExtension
|
||||
}
|
||||
|
||||
public NavigateExtension(object mediator,
|
||||
object to,
|
||||
object path,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
@@ -133,7 +129,7 @@ public class NavigateExtension : TriggerExtension
|
||||
object args7)
|
||||
{
|
||||
mediatorBinding = mediator.ToBinding();
|
||||
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
|
||||
this.pathBinding = path is Binding pathBinding ? pathBinding : path.ToBinding();
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
@@ -145,7 +141,7 @@ public class NavigateExtension : TriggerExtension
|
||||
}
|
||||
|
||||
public NavigateExtension(object mediator,
|
||||
object to,
|
||||
object path,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
@@ -156,7 +152,7 @@ public class NavigateExtension : TriggerExtension
|
||||
object args8)
|
||||
{
|
||||
mediatorBinding = mediator.ToBinding();
|
||||
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
|
||||
this.pathBinding = path is Binding pathBinding ? pathBinding : path.ToBinding();
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
@@ -169,7 +165,7 @@ public class NavigateExtension : TriggerExtension
|
||||
}
|
||||
|
||||
public NavigateExtension(object mediator,
|
||||
object to,
|
||||
object path,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
@@ -181,7 +177,7 @@ public class NavigateExtension : TriggerExtension
|
||||
object args9)
|
||||
{
|
||||
mediatorBinding = mediator.ToBinding();
|
||||
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
|
||||
this.pathBinding = path is Binding pathBinding ? pathBinding : path.ToBinding();
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
@@ -195,7 +191,7 @@ public class NavigateExtension : TriggerExtension
|
||||
}
|
||||
|
||||
public NavigateExtension(object mediator,
|
||||
object to,
|
||||
object path,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
@@ -208,7 +204,7 @@ public class NavigateExtension : TriggerExtension
|
||||
object args10)
|
||||
{
|
||||
mediatorBinding = mediator.ToBinding();
|
||||
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
|
||||
this.pathBinding = path is Binding pathBinding ? pathBinding : path.ToBinding();
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
@@ -223,7 +219,7 @@ public class NavigateExtension : TriggerExtension
|
||||
}
|
||||
|
||||
public NavigateExtension(object mediator,
|
||||
object to,
|
||||
object path,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
@@ -237,7 +233,7 @@ public class NavigateExtension : TriggerExtension
|
||||
object args11)
|
||||
{
|
||||
mediatorBinding = mediator.ToBinding();
|
||||
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
|
||||
this.pathBinding = path is Binding pathBinding ? pathBinding : path.ToBinding();
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
@@ -253,7 +249,7 @@ public class NavigateExtension : TriggerExtension
|
||||
}
|
||||
|
||||
public NavigateExtension(object mediator,
|
||||
object to,
|
||||
object path,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
@@ -268,7 +264,7 @@ public class NavigateExtension : TriggerExtension
|
||||
object args12)
|
||||
{
|
||||
mediatorBinding = mediator.ToBinding();
|
||||
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
|
||||
this.pathBinding = path is Binding pathBinding ? pathBinding : path.ToBinding();
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
@@ -285,7 +281,7 @@ public class NavigateExtension : TriggerExtension
|
||||
}
|
||||
|
||||
public NavigateExtension(object mediator,
|
||||
object to,
|
||||
object path,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
@@ -301,7 +297,7 @@ public class NavigateExtension : TriggerExtension
|
||||
object args13)
|
||||
{
|
||||
mediatorBinding = mediator.ToBinding();
|
||||
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
|
||||
this.pathBinding = path is Binding pathBinding ? pathBinding : path.ToBinding();
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
@@ -319,7 +315,7 @@ public class NavigateExtension : TriggerExtension
|
||||
}
|
||||
|
||||
public NavigateExtension(object mediator,
|
||||
object to,
|
||||
object path,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
@@ -336,7 +332,7 @@ public class NavigateExtension : TriggerExtension
|
||||
object args14)
|
||||
{
|
||||
mediatorBinding = mediator.ToBinding();
|
||||
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
|
||||
this.pathBinding = path is Binding pathBinding ? pathBinding : path.ToBinding();
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
@@ -355,7 +351,7 @@ public class NavigateExtension : TriggerExtension
|
||||
}
|
||||
|
||||
public NavigateExtension(object mediator,
|
||||
object to,
|
||||
object path,
|
||||
object args1,
|
||||
object args2,
|
||||
object args3,
|
||||
@@ -373,7 +369,7 @@ public class NavigateExtension : TriggerExtension
|
||||
object args15)
|
||||
{
|
||||
mediatorBinding = mediator.ToBinding();
|
||||
this.toBinding = to is Binding toBinding ? toBinding : to.ToBinding();
|
||||
this.pathBinding = path is Binding pathBinding ? pathBinding : path.ToBinding();
|
||||
|
||||
parameters.Add(args1 is MarkupExtension ? args1 : args1.ToBinding());
|
||||
parameters.Add(args2 is MarkupExtension ? args2 : args2.ToBinding());
|
||||
@@ -392,22 +388,6 @@ public class NavigateExtension : TriggerExtension
|
||||
parameters.Add(args15 is MarkupExtension ? args15 : args15.ToBinding());
|
||||
}
|
||||
|
||||
public object? Route
|
||||
{
|
||||
get
|
||||
{
|
||||
return route;
|
||||
}
|
||||
set
|
||||
{
|
||||
route = value;
|
||||
if (route is not null)
|
||||
{
|
||||
routeBinding = route.ToBinding();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnInvoked(object sender, EventArgs args)
|
||||
{
|
||||
if (TargetObject is not null && mediatorBinding is not null)
|
||||
@@ -415,10 +395,10 @@ public class NavigateExtension : TriggerExtension
|
||||
TargetObject.Bind(MediatorProperty, mediatorBinding);
|
||||
if (TargetObject.GetValue(MediatorProperty) is IMediator mediator)
|
||||
{
|
||||
if (toBinding is not null)
|
||||
if (pathBinding is not null)
|
||||
{
|
||||
TargetObject.Bind(ToProperty, toBinding);
|
||||
if (TargetObject.GetValue(ToProperty) is { } to)
|
||||
TargetObject.Bind(PathProperty, pathBinding);
|
||||
if (TargetObject.GetValue(PathProperty) is string path)
|
||||
{
|
||||
List<object>? parameters = new();
|
||||
foreach (object? parameter in this.parameters)
|
||||
@@ -449,27 +429,12 @@ public class NavigateExtension : TriggerExtension
|
||||
}
|
||||
}
|
||||
|
||||
object? route = null;
|
||||
if (routeBinding is not null)
|
||||
if (pathBinding?.StringFormat is string format)
|
||||
{
|
||||
TargetObject.Bind(RouteProperty, routeBinding);
|
||||
route = TargetObject.GetValue(RouteProperty);
|
||||
path = string.Format(format, path);
|
||||
}
|
||||
|
||||
if (to is string name)
|
||||
{
|
||||
if (toBinding?.StringFormat is string format)
|
||||
{
|
||||
name = string.Format(format, name);
|
||||
}
|
||||
|
||||
mediator.Send(new Navigate(name, parameters.ToArray()) { Route = route });
|
||||
}
|
||||
|
||||
if (to is Type type)
|
||||
{
|
||||
mediator.Send(new Navigate(type, parameters.ToArray()) { Route = route });
|
||||
}
|
||||
mediator.Send(new Navigate(path, parameters.ToArray()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
using Avalonia.Controls;
|
||||
using System.Diagnostics;
|
||||
using Toolkit.Controls.Avalonia;
|
||||
using Toolkit.Framework.Foundation;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Toolkit.Framework.Avalonia;
|
||||
|
||||
@@ -30,6 +31,8 @@ public class NavigateHandler : IRequestHandler<Navigate>
|
||||
}
|
||||
|
||||
public ValueTask<Unit> Handle(Navigate request, CancellationToken cancellationToken)
|
||||
{
|
||||
foreach (NavigationSegment segment in NavigationSegment.FromPath(request.Path))
|
||||
{
|
||||
object? content = null;
|
||||
object? template = null;
|
||||
@@ -52,22 +55,16 @@ public class NavigateHandler : IRequestHandler<Navigate>
|
||||
}
|
||||
}
|
||||
|
||||
if (request.Name is { Length: > 0 } name)
|
||||
if (segment.Name is { Length: > 0 } name)
|
||||
{
|
||||
content = namedContentFactory.Create(name, parameters.ToArray());
|
||||
template = namedContentTemplateFactory.Create(name);
|
||||
}
|
||||
|
||||
if (request.Type is Type type)
|
||||
{
|
||||
content = typedContentFactory.Create(type, parameters.ToArray());
|
||||
template = contentTemplateFactory.Create(content);
|
||||
}
|
||||
|
||||
if (template is not null)
|
||||
{
|
||||
object? target = null;
|
||||
if (descriptors.FirstOrDefault(x => request.Route is string { } name && name == x.Name) is NavigationRouteDescriptor descriptor)
|
||||
if (descriptors.FirstOrDefault(x => segment.Target is string { } name && name == x.Name) is NavigationRouteDescriptor descriptor)
|
||||
{
|
||||
target = descriptor.Route;
|
||||
}
|
||||
@@ -91,7 +88,7 @@ public class NavigateHandler : IRequestHandler<Navigate>
|
||||
}
|
||||
else
|
||||
{
|
||||
if (descriptors.FirstOrDefault(x => request.Route is string { } name && name == x.Name) is NavigationRouteDescriptor descriptor)
|
||||
if (descriptors.FirstOrDefault(x => segment.Target is string { } name && name == x.Name) is NavigationRouteDescriptor descriptor)
|
||||
{
|
||||
if (descriptor.Route is ContentControl contentControl)
|
||||
{
|
||||
@@ -99,6 +96,7 @@ public class NavigateHandler : IRequestHandler<Navigate>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return default;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<AssemblyName>Toolkit.Framework.Foundation</AssemblyName>
|
||||
<RootNamespace>Toolkit.Framework.Foundation</RootNamespace>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace Toolkit.Framework.Foundation;
|
||||
|
||||
public struct KeyValueAccumulator
|
||||
{
|
||||
private Dictionary<string, StringValues> accumulator;
|
||||
private Dictionary<string, List<string>> expandingAccumulator;
|
||||
|
||||
public void Append(string key, string value)
|
||||
{
|
||||
accumulator ??= new Dictionary<string, StringValues>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
if (accumulator.TryGetValue(key, out StringValues values))
|
||||
{
|
||||
if (values.Count == 0)
|
||||
{
|
||||
expandingAccumulator[key].Add(value);
|
||||
}
|
||||
else if (values.Count == 1)
|
||||
{
|
||||
accumulator[key] = new string[] { values[0]!, value };
|
||||
}
|
||||
else
|
||||
{
|
||||
accumulator[key] = default;
|
||||
|
||||
expandingAccumulator ??= new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
List<string> list = new(8);
|
||||
string?[] array = values.ToArray();
|
||||
|
||||
list.Add(array[0]!);
|
||||
list.Add(array[1]!);
|
||||
list.Add(value);
|
||||
|
||||
expandingAccumulator[key] = list;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
accumulator[key] = new StringValues(value);
|
||||
}
|
||||
|
||||
ValueCount++;
|
||||
}
|
||||
|
||||
public bool HasValues => ValueCount > 0;
|
||||
|
||||
public int KeyCount => accumulator?.Count ?? 0;
|
||||
|
||||
public int ValueCount { get; private set; }
|
||||
|
||||
public Dictionary<string, StringValues> GetResults()
|
||||
{
|
||||
if (expandingAccumulator != null)
|
||||
{
|
||||
foreach (var entry in expandingAccumulator)
|
||||
{
|
||||
accumulator[entry.Key] = new StringValues(entry.Value.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
return accumulator ?? new Dictionary<string, StringValues>(0, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
|
||||
namespace Toolkit.Framework.Foundation;
|
||||
|
||||
public static class QueryHelpers
|
||||
{
|
||||
public static Dictionary<string, StringValues>? ParseNullableQuery(string? queryString)
|
||||
{
|
||||
KeyValueAccumulator accumulator = new();
|
||||
QueryStringEnumerable enumerable = new(queryString);
|
||||
|
||||
foreach (QueryStringEnumerable.EncodedNameValuePair pair in enumerable)
|
||||
{
|
||||
accumulator.Append(pair.DecodeName().ToString(), pair.DecodeValue().ToString());
|
||||
}
|
||||
|
||||
if (!accumulator.HasValues)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return accumulator.GetResults();
|
||||
}
|
||||
|
||||
public static Dictionary<string, StringValues> ParseQuery(string? queryString)
|
||||
{
|
||||
Dictionary<string, StringValues>? result = ParseNullableQuery(queryString);
|
||||
if (result == null)
|
||||
{
|
||||
return new Dictionary<string, StringValues>();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
using System.Buffers;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Intrinsics;
|
||||
|
||||
readonly struct QueryStringEnumerable
|
||||
{
|
||||
private readonly ReadOnlyMemory<char> queryString;
|
||||
|
||||
public QueryStringEnumerable(string? queryString) : this(queryString.AsMemory())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public QueryStringEnumerable(ReadOnlyMemory<char> queryString)
|
||||
{
|
||||
this.queryString = queryString;
|
||||
}
|
||||
|
||||
public Enumerator GetEnumerator() => new(queryString);
|
||||
|
||||
public readonly struct EncodedNameValuePair
|
||||
{
|
||||
internal EncodedNameValuePair(ReadOnlyMemory<char> encodedName, ReadOnlyMemory<char> encodedValue)
|
||||
{
|
||||
EncodedName = encodedName;
|
||||
EncodedValue = encodedValue;
|
||||
}
|
||||
|
||||
public readonly ReadOnlyMemory<char> EncodedName { get; }
|
||||
|
||||
public readonly ReadOnlyMemory<char> EncodedValue { get; }
|
||||
|
||||
public ReadOnlyMemory<char> DecodeName() => Decode(EncodedName);
|
||||
|
||||
public ReadOnlyMemory<char> DecodeValue() => Decode(EncodedValue);
|
||||
|
||||
private static ReadOnlyMemory<char> Decode(ReadOnlyMemory<char> chars)
|
||||
{
|
||||
return chars.Length < 16 && chars.Span.IndexOfAny('%', '+') < 0 ? chars : Uri.UnescapeDataString(SpanHelper.ReplacePlusWithSpace(chars.Span)).AsMemory();
|
||||
}
|
||||
}
|
||||
|
||||
public struct Enumerator
|
||||
{
|
||||
private ReadOnlyMemory<char> query;
|
||||
|
||||
internal Enumerator(ReadOnlyMemory<char> query)
|
||||
{
|
||||
Current = default;
|
||||
this.query = query.IsEmpty || query.Span[0] != '?' ? query : query[1..];
|
||||
}
|
||||
|
||||
public EncodedNameValuePair Current { get; private set; }
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
while (!query.IsEmpty)
|
||||
{
|
||||
ReadOnlyMemory<char> segment;
|
||||
var delimiterIndex = query.Span.IndexOf('&');
|
||||
if (delimiterIndex >= 0)
|
||||
{
|
||||
segment = query[..delimiterIndex];
|
||||
query = query[(delimiterIndex + 1)..];
|
||||
}
|
||||
else
|
||||
{
|
||||
segment = query;
|
||||
query = default;
|
||||
}
|
||||
|
||||
int equalIndex = segment.Span.IndexOf('=');
|
||||
if (equalIndex >= 0)
|
||||
{
|
||||
Current = new EncodedNameValuePair(segment[..equalIndex], segment[(equalIndex + 1)..]);
|
||||
return true;
|
||||
}
|
||||
else if (!segment.IsEmpty)
|
||||
{
|
||||
Current = new EncodedNameValuePair(segment, default);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Current = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SpanHelper
|
||||
{
|
||||
private static readonly SpanAction<char, IntPtr> replacePlusWithSpace = ReplacePlusWithSpaceCore;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe string ReplacePlusWithSpace(ReadOnlySpan<char> span)
|
||||
{
|
||||
fixed (char* ptr = &MemoryMarshal.GetReference(span))
|
||||
{
|
||||
return string.Create(span.Length, (IntPtr)ptr, replacePlusWithSpace);
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe void ReplacePlusWithSpaceCore(Span<char> buffer, IntPtr state)
|
||||
{
|
||||
fixed (char* ptr = &MemoryMarshal.GetReference(buffer))
|
||||
{
|
||||
ushort* input = (ushort*)state.ToPointer();
|
||||
ushort* output = (ushort*)ptr;
|
||||
|
||||
nint i = 0;
|
||||
nint n = (nint)(uint)buffer.Length;
|
||||
|
||||
if (Vector256.IsHardwareAccelerated && n >= Vector256<ushort>.Count)
|
||||
{
|
||||
Vector256<ushort> vecPlus = Vector256.Create((ushort)'+');
|
||||
Vector256<ushort> vecSpace = Vector256.Create((ushort)' ');
|
||||
|
||||
do
|
||||
{
|
||||
Vector256<ushort> vec = Vector256.Load(input + i);
|
||||
Vector256<ushort> mask = Vector256.Equals(vec, vecPlus);
|
||||
Vector256<ushort> res = Vector256.ConditionalSelect(mask, vecSpace, vec);
|
||||
res.Store(output + i);
|
||||
i += Vector256<ushort>.Count;
|
||||
} while (i <= n - Vector256<ushort>.Count);
|
||||
}
|
||||
|
||||
if (Vector128.IsHardwareAccelerated && n - i >= Vector128<ushort>.Count)
|
||||
{
|
||||
do
|
||||
{
|
||||
Vector128<ushort> vec = Vector128.Load(input + i);
|
||||
Vector128<ushort> vecPlus = Vector128.Create((ushort)'+');
|
||||
Vector128<ushort> mask = Vector128.Equals(vec, vecPlus);
|
||||
Vector128<ushort> vecSpace = Vector128.Create((ushort)' ');
|
||||
Vector128<ushort> res = Vector128.ConditionalSelect(mask, vecSpace, vec);
|
||||
res.Store(output + i);
|
||||
i += Vector128<ushort>.Count;
|
||||
} while (i <= n - Vector128<ushort>.Count);
|
||||
}
|
||||
|
||||
for (; i < n; ++i)
|
||||
{
|
||||
if (input[i] != '+')
|
||||
{
|
||||
output[i] = input[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
output[i] = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,23 +3,13 @@ namespace Toolkit.Framework.Foundation;
|
||||
|
||||
public record Navigate : IRequest
|
||||
{
|
||||
public Navigate(string name, params object?[] parameters)
|
||||
public Navigate(string path, params object?[] parameters)
|
||||
{
|
||||
Name = name;
|
||||
Path = path;
|
||||
Parameters = parameters;
|
||||
}
|
||||
|
||||
public Navigate(Type type, params object?[] parameters)
|
||||
{
|
||||
Type = type;
|
||||
Parameters = parameters;
|
||||
}
|
||||
|
||||
public Type? Type { get; }
|
||||
|
||||
public object? Route { get; init; }
|
||||
|
||||
public string? Name { get; }
|
||||
public string? Path { get; }
|
||||
|
||||
public object?[] Parameters { get; }
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Toolkit.Framework.Foundation;
|
||||
|
||||
public class NavigationSegment
|
||||
{
|
||||
private NavigationSegment(string name, IDictionary<string, StringValues> parameters, string target)
|
||||
{
|
||||
Name = name;
|
||||
Parameters = parameters;
|
||||
Target = target;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
|
||||
public IDictionary<string, StringValues> Parameters { get; }
|
||||
|
||||
public string Target { get; }
|
||||
|
||||
public static IReadOnlyCollection<NavigationSegment> FromPath(string? path)
|
||||
{
|
||||
List<NavigationSegment> result = new();
|
||||
|
||||
if (path is null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
string[] pathParts = path.Split('?');
|
||||
|
||||
string[] segments = pathParts is { Length: >= 1 } ? pathParts[0].Split('/', StringSplitOptions.RemoveEmptyEntries)
|
||||
: Array.Empty<string>();
|
||||
string query = pathParts is { Length: 2 } ? pathParts[1] : "";
|
||||
|
||||
Dictionary<string, StringValues> parameters = QueryHelpers.ParseQuery(query);
|
||||
|
||||
foreach (string segment in segments)
|
||||
{
|
||||
string[] segmentParts = segment.Split('#');
|
||||
|
||||
string name = segmentParts is { Length: >= 1 } ? segmentParts[0] : "";
|
||||
string target = segmentParts is { Length: 2 } ? segmentParts[1] : "";
|
||||
|
||||
Trace.WriteLine(name);
|
||||
Trace.WriteLine(target);
|
||||
|
||||
result.Add(new NavigationSegment(name, parameters, target));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user