diff --git a/Controls/Avalonia/IconElement/FAPathIcon.cs b/Controls/Avalonia/IconElement/FAPathIcon.cs index ae36a98..de87c81 100644 --- a/Controls/Avalonia/IconElement/FAPathIcon.cs +++ b/Controls/Avalonia/IconElement/FAPathIcon.cs @@ -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 -{ } diff --git a/Controls/Avalonia/IconElement/FontIcon.cs b/Controls/Avalonia/IconElement/FontIcon.cs new file mode 100644 index 0000000..b4b19a6 --- /dev/null +++ b/Controls/Avalonia/IconElement/FontIcon.cs @@ -0,0 +1,6 @@ +namespace Toolkit.Controls.Avalonia; + +public class FontIcon : FluentAvalonia.UI.Controls.FontIcon +{ + +} \ No newline at end of file diff --git a/Controls/Avalonia/IconElement/SymbolIcon.cs b/Controls/Avalonia/IconElement/SymbolIcon.cs new file mode 100644 index 0000000..1a4fe93 --- /dev/null +++ b/Controls/Avalonia/IconElement/SymbolIcon.cs @@ -0,0 +1,6 @@ +namespace Toolkit.Controls.Avalonia; + +public class SymbolIcon : FluentAvalonia.UI.Controls.SymbolIcon +{ + +} diff --git a/Framework/Avalonia/Markups/NavigateExtension.cs b/Framework/Avalonia/Markups/NavigateExtension.cs index 5911911..d53ec67 100644 --- a/Framework/Avalonia/Markups/NavigateExtension.cs +++ b/Framework/Avalonia/Markups/NavigateExtension.cs @@ -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 ParameterProperty = AvaloniaProperty.RegisterAttached("Parameter"); - private static readonly AvaloniaProperty RouteProperty = - AvaloniaProperty.RegisterAttached("Route"); - - private static readonly AvaloniaProperty ToProperty = - AvaloniaProperty.RegisterAttached("To"); + private static readonly AvaloniaProperty PathProperty = + AvaloniaProperty.RegisterAttached("Path"); private readonly Binding? mediatorBinding; private readonly List 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? 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())); } } } diff --git a/Framework/Avalonia/Navigation/NavigateHandler.cs b/Framework/Avalonia/Navigation/NavigateHandler.cs index f27a3ad..e7aa658 100644 --- a/Framework/Avalonia/Navigation/NavigateHandler.cs +++ b/Framework/Avalonia/Navigation/NavigateHandler.cs @@ -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; @@ -31,71 +32,68 @@ public class NavigateHandler : IRequestHandler public ValueTask Handle(Navigate request, CancellationToken cancellationToken) { - object? content = null; - object? template = null; - - Dictionary keyedParameters = new(); - List parameters = new(); - - foreach (object? parameter in request.Parameters) + foreach (NavigationSegment segment in NavigationSegment.FromPath(request.Path)) { - if (parameter is not null) + object? content = null; + object? template = null; + + Dictionary keyedParameters = new(); + List parameters = new(); + + foreach (object? parameter in request.Parameters) { - if (parameter is KeyValuePair keyed) + if (parameter is not null) { - keyedParameters.Add(keyed.Key, keyed.Value); + if (parameter is KeyValuePair keyed) + { + keyedParameters.Add(keyed.Key, keyed.Value); + } + else + { + parameters.Add(parameter); + } + } + } + + if (segment.Name is { Length: > 0 } name) + { + content = namedContentFactory.Create(name, parameters.ToArray()); + template = namedContentTemplateFactory.Create(name); + } + + if (template is not null) + { + object? target = null; + if (descriptors.FirstOrDefault(x => segment.Target is string { } name && name == x.Name) is NavigationRouteDescriptor descriptor) + { + target = descriptor.Route; } else { - parameters.Add(parameter); + target = template; } - } - } - if (request.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) - { - target = descriptor.Route; + if (target is Frame frame) + { + mediator.Send(new FrameNavigation(frame, content, template, keyedParameters)); + } + else if (target is ContentDialog dialog) + { + mediator.Send(new ContentDialogNavigation(dialog, content, template, keyedParameters)); + } + else if (target is ContentControl contentControl) + { + mediator.Send(new ContentControlNavigation(contentControl, content, template, keyedParameters)); + } } else { - target = template; - } - - if (target is Frame frame) - { - mediator.Send(new FrameNavigation(frame, content, template, keyedParameters)); - } - else if (target is ContentDialog dialog) - { - mediator.Send(new ContentDialogNavigation(dialog, content, template, keyedParameters)); - } - else if (target is ContentControl contentControl) - { - mediator.Send(new ContentControlNavigation(contentControl, content, template, keyedParameters)); - } - } - else - { - if (descriptors.FirstOrDefault(x => request.Route is string { } name && name == x.Name) is NavigationRouteDescriptor descriptor) - { - if (descriptor.Route is ContentControl contentControl) + if (descriptors.FirstOrDefault(x => segment.Target is string { } name && name == x.Name) is NavigationRouteDescriptor descriptor) { - contentControl.Content = null; + if (descriptor.Route is ContentControl contentControl) + { + contentControl.Content = null; + } } } } diff --git a/Framework/Foundation/Foundation.csproj b/Framework/Foundation/Foundation.csproj index bd3f1a3..80df8b8 100644 --- a/Framework/Foundation/Foundation.csproj +++ b/Framework/Foundation/Foundation.csproj @@ -6,6 +6,7 @@ enable Toolkit.Framework.Foundation Toolkit.Framework.Foundation + true diff --git a/Framework/Foundation/Helpers/KeyValueAccumulator.cs b/Framework/Foundation/Helpers/KeyValueAccumulator.cs new file mode 100644 index 0000000..1c7d8a7 --- /dev/null +++ b/Framework/Foundation/Helpers/KeyValueAccumulator.cs @@ -0,0 +1,66 @@ +using Microsoft.Extensions.Primitives; + +namespace Toolkit.Framework.Foundation; + +public struct KeyValueAccumulator +{ + private Dictionary accumulator; + private Dictionary> expandingAccumulator; + + public void Append(string key, string value) + { + accumulator ??= new Dictionary(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>(StringComparer.OrdinalIgnoreCase); + + List 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 GetResults() + { + if (expandingAccumulator != null) + { + foreach (var entry in expandingAccumulator) + { + accumulator[entry.Key] = new StringValues(entry.Value.ToArray()); + } + } + + return accumulator ?? new Dictionary(0, StringComparer.OrdinalIgnoreCase); + } +} \ No newline at end of file diff --git a/Framework/Foundation/Helpers/QueryHelpers.cs b/Framework/Foundation/Helpers/QueryHelpers.cs new file mode 100644 index 0000000..7679433 --- /dev/null +++ b/Framework/Foundation/Helpers/QueryHelpers.cs @@ -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? 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 ParseQuery(string? queryString) + { + Dictionary? result = ParseNullableQuery(queryString); + if (result == null) + { + return new Dictionary(); + } + + return result; + } +} \ No newline at end of file diff --git a/Framework/Foundation/Helpers/QueryStringEnumerable.cs b/Framework/Foundation/Helpers/QueryStringEnumerable.cs new file mode 100644 index 0000000..4c2f4d8 --- /dev/null +++ b/Framework/Foundation/Helpers/QueryStringEnumerable.cs @@ -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 queryString; + + public QueryStringEnumerable(string? queryString) : this(queryString.AsMemory()) + { + + } + + public QueryStringEnumerable(ReadOnlyMemory queryString) + { + this.queryString = queryString; + } + + public Enumerator GetEnumerator() => new(queryString); + + public readonly struct EncodedNameValuePair + { + internal EncodedNameValuePair(ReadOnlyMemory encodedName, ReadOnlyMemory encodedValue) + { + EncodedName = encodedName; + EncodedValue = encodedValue; + } + + public readonly ReadOnlyMemory EncodedName { get; } + + public readonly ReadOnlyMemory EncodedValue { get; } + + public ReadOnlyMemory DecodeName() => Decode(EncodedName); + + public ReadOnlyMemory DecodeValue() => Decode(EncodedValue); + + private static ReadOnlyMemory Decode(ReadOnlyMemory chars) + { + return chars.Length < 16 && chars.Span.IndexOfAny('%', '+') < 0 ? chars : Uri.UnescapeDataString(SpanHelper.ReplacePlusWithSpace(chars.Span)).AsMemory(); + } + } + + public struct Enumerator + { + private ReadOnlyMemory query; + + internal Enumerator(ReadOnlyMemory 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 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 replacePlusWithSpace = ReplacePlusWithSpaceCore; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static unsafe string ReplacePlusWithSpace(ReadOnlySpan span) + { + fixed (char* ptr = &MemoryMarshal.GetReference(span)) + { + return string.Create(span.Length, (IntPtr)ptr, replacePlusWithSpace); + } + } + + private static unsafe void ReplacePlusWithSpaceCore(Span 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.Count) + { + Vector256 vecPlus = Vector256.Create((ushort)'+'); + Vector256 vecSpace = Vector256.Create((ushort)' '); + + do + { + Vector256 vec = Vector256.Load(input + i); + Vector256 mask = Vector256.Equals(vec, vecPlus); + Vector256 res = Vector256.ConditionalSelect(mask, vecSpace, vec); + res.Store(output + i); + i += Vector256.Count; + } while (i <= n - Vector256.Count); + } + + if (Vector128.IsHardwareAccelerated && n - i >= Vector128.Count) + { + do + { + Vector128 vec = Vector128.Load(input + i); + Vector128 vecPlus = Vector128.Create((ushort)'+'); + Vector128 mask = Vector128.Equals(vec, vecPlus); + Vector128 vecSpace = Vector128.Create((ushort)' '); + Vector128 res = Vector128.ConditionalSelect(mask, vecSpace, vec); + res.Store(output + i); + i += Vector128.Count; + } while (i <= n - Vector128.Count); + } + + for (; i < n; ++i) + { + if (input[i] != '+') + { + output[i] = input[i]; + } + else + { + output[i] = ' '; + } + } + } + } + } +} \ No newline at end of file diff --git a/Framework/Foundation/Navigation/Navigate.cs b/Framework/Foundation/Navigation/Navigate.cs index 4288f34..2d4eaef 100644 --- a/Framework/Foundation/Navigation/Navigate.cs +++ b/Framework/Foundation/Navigation/Navigate.cs @@ -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; } } \ No newline at end of file diff --git a/Framework/Foundation/Navigation/NavigationSegment.cs b/Framework/Foundation/Navigation/NavigationSegment.cs new file mode 100644 index 0000000..47a13ca --- /dev/null +++ b/Framework/Foundation/Navigation/NavigationSegment.cs @@ -0,0 +1,53 @@ +using Microsoft.Extensions.Primitives; +using System.Diagnostics; + +namespace Toolkit.Framework.Foundation; + +public class NavigationSegment +{ + private NavigationSegment(string name, IDictionary parameters, string target) + { + Name = name; + Parameters = parameters; + Target = target; + } + + public string Name { get; } + + public IDictionary Parameters { get; } + + public string Target { get; } + + public static IReadOnlyCollection FromPath(string? path) + { + List 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 query = pathParts is { Length: 2 } ? pathParts[1] : ""; + + Dictionary 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; + } +}