aboutsummaryrefslogtreecommitdiff
path: root/lib/Utils/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Utils/src')
-rw-r--r--lib/Utils/src/ArgumentList.cs101
-rw-r--r--lib/Utils/src/Async/AsyncUpdatableResource.cs41
-rw-r--r--lib/Utils/src/Async/IAsyncExclusiveResource.cs6
-rw-r--r--lib/Utils/src/Async/IAsyncResourceStateHandler.cs53
-rw-r--r--lib/Utils/src/Extensions/MemoryExtensions.cs5
-rw-r--r--lib/Utils/src/Memory/Caching/LRUCache.cs14
-rw-r--r--lib/Utils/src/Memory/Caching/LRUDataStore.cs22
-rw-r--r--lib/Utils/src/Memory/PrivateBuffersMemoryPool.cs19
-rw-r--r--lib/Utils/src/Resources/BackedResourceBase.cs38
-rw-r--r--lib/Utils/src/Resources/IResourceStateHandler.cs47
-rw-r--r--lib/Utils/src/Resources/UpdatableResource.cs46
-rw-r--r--lib/Utils/src/VnEncoding.cs8
12 files changed, 292 insertions, 108 deletions
diff --git a/lib/Utils/src/ArgumentList.cs b/lib/Utils/src/ArgumentList.cs
new file mode 100644
index 0000000..ae45e36
--- /dev/null
+++ b/lib/Utils/src/ArgumentList.cs
@@ -0,0 +1,101 @@
+/*
+* Copyright (c) 2022 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Utils
+* File: ArgumentList.cs
+*
+* ArgumentList.cs is part of VNLib.Utils which is part of the larger
+* VNLib collection of libraries and utilities.
+*
+* VNLib.Utils is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published
+* by the Free Software Foundation, either version 2 of the License,
+* or (at your option) any later version.
+*
+* VNLib.Utils is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with VNLib.Utils. If not, see http://www.gnu.org/licenses/.
+*/
+
+using System;
+using System.Linq;
+using System.Collections.Generic;
+
+namespace VNLib.Utils
+{
+ /// <summary>
+ /// Provides methods for parsing an argument list
+ /// </summary>
+ public class ArgumentList : IIndexable<int, string>
+ {
+ private readonly List<string> _args;
+
+ /// <summary>
+ /// Initalzies a the argument parser by copying the given argument array
+ /// </summary>
+ /// <param name="args">The array of arguments to clone</param>
+ /// <exception cref="ArgumentNullException"></exception>
+ public ArgumentList(string[] args)
+ {
+ _ = args ?? throw new ArgumentNullException(nameof(args));
+ _args = args.ToList();
+ }
+
+ /// <summary>
+ /// Initalizes the argument parser by copying the given argument list
+ /// </summary>
+ /// <param name="args">The argument list to clone</param>
+ /// <exception cref="ArgumentNullException"></exception>
+ public ArgumentList(IReadOnlyList<string> args)
+ {
+ _ = args ?? throw new ArgumentNullException(nameof(args));
+ _args = args.ToList();
+ }
+
+ /// <summary>
+ /// Gets the number of arguments in the list
+ /// </summary>
+ public int Count => _args.Count;
+
+ ///<inheritdoc/>
+ public string this[int key]
+ {
+ get => _args[key];
+ set => _args[key] = value;
+ }
+
+ /// <summary>
+ /// Determines of the given argument is present in the argument list
+ /// </summary>
+ /// <param name="arg"></param>
+ /// <returns>A value that indicates if the argument is present in the list</returns>
+ public bool HasArgument(string arg) => _args.Contains(arg);
+
+ /// <summary>
+ /// Determines if the argument is present in the argument list and
+ /// has a non-null value following it.
+ /// </summary>
+ /// <param name="arg">The argument name to test</param>
+ /// <returns>A value that indicates if a non-null argument is present in the list</returns>
+ public bool HasArgumentValue(string arg) => GetArgument(arg) != null;
+
+ /// <summary>
+ /// Gets the value following the specified argument, or
+ /// null no value follows the specified argument
+ /// </summary>
+ /// <param name="arg">The argument to get following value of</param>
+ /// <returns>The argument value if found</returns>
+ public string? GetArgument(string arg)
+ {
+ int index = _args.IndexOf(arg);
+ return index == -1 || index + 1 >= _args.Count ? null : this[index + 1];
+ }
+
+
+ }
+} \ No newline at end of file
diff --git a/lib/Utils/src/Async/AsyncUpdatableResource.cs b/lib/Utils/src/Async/AsyncUpdatableResource.cs
index b4ce519..6b8ec62 100644
--- a/lib/Utils/src/Async/AsyncUpdatableResource.cs
+++ b/lib/Utils/src/Async/AsyncUpdatableResource.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022 Vaughn Nugent
+* Copyright (c) 2023 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Utils
@@ -23,28 +23,13 @@
*/
using System;
-using System.IO;
-using System.Text.Json;
+using System.Threading;
using System.Threading.Tasks;
-using VNLib.Utils.IO;
using VNLib.Utils.Resources;
namespace VNLib.Utils.Async
{
- /// <summary>
- /// A callback delegate used for updating a <see cref="AsyncUpdatableResource"/>
- /// </summary>
- /// <param name="source">The <see cref="AsyncUpdatableResource"/> to be updated</param>
- /// <param name="data">The serialized data to be stored/updated</param>
- /// <exception cref="ResourceUpdateFailedException"></exception>
- public delegate Task AsyncUpdateCallback(object source, Stream data);
- /// <summary>
- /// A callback delegate invoked when a <see cref="AsyncUpdatableResource"/> delete is requested
- /// </summary>
- /// <param name="source">The <see cref="AsyncUpdatableResource"/> to be deleted</param>
- /// <exception cref="ResourceDeleteFailedException"></exception>
- public delegate Task AsyncDeleteCallback(object source);
/// <summary>
/// Implemented by a resource that is backed by an external data store, that when modified or deleted will
@@ -52,8 +37,10 @@ namespace VNLib.Utils.Async
/// </summary>
public abstract class AsyncUpdatableResource : BackedResourceBase, IAsyncExclusiveResource
{
- protected abstract AsyncUpdateCallback UpdateCb { get; }
- protected abstract AsyncDeleteCallback DeleteCb { get; }
+ /// <summary>
+ /// The resource update handler that will be invoked when the resource is modified
+ /// </summary>
+ protected abstract IAsyncResourceStateHandler AsyncHandler { get; }
/// <summary>
/// Releases the resource and flushes pending changes to its backing store.
@@ -62,7 +49,7 @@ namespace VNLib.Utils.Async
/// <exception cref="InvalidOperationException"></exception>
/// <exception cref="ResourceDeleteFailedException"></exception>
/// <exception cref="ResourceUpdateFailedException"></exception>
- public virtual async ValueTask ReleaseAsync()
+ public virtual async ValueTask ReleaseAsync(CancellationToken cancellation = default)
{
//If resource has already been realeased, return
if (IsReleased)
@@ -72,12 +59,12 @@ namespace VNLib.Utils.Async
//If deleted flag is set, invoke the delete callback
if (Deleted)
{
- await DeleteCb(this).ConfigureAwait(true);
+ await AsyncHandler.DeleteAsync(this, cancellation).ConfigureAwait(true);
}
//If the state has been modifed, flush changes to the store
else if (Modified)
{
- await FlushPendingChangesAsync().ConfigureAwait(true);
+ await FlushPendingChangesAsync(cancellation).ConfigureAwait(true);
}
//Set the released value
IsReleased = true;
@@ -92,18 +79,12 @@ namespace VNLib.Utils.Async
/// Only call this method if your store supports multiple state updates
/// </para>
/// </summary>
- protected virtual async Task FlushPendingChangesAsync()
+ protected virtual async Task FlushPendingChangesAsync(CancellationToken cancellation = default)
{
//Get the resource
object resource = GetResource();
- //Open a memory stream to store data in
- using VnMemoryStream data = new();
- //Serialize and write to stream
- VnEncoding.JSONSerializeToBinary(resource, data, resource.GetType(), base.JSO);
- //Reset stream to begining
- _ = data.Seek(0, SeekOrigin.Begin);
//Invoke update callback
- await UpdateCb(this, data).ConfigureAwait(true);
+ await AsyncHandler.UpdateAsync(this, resource, cancellation).ConfigureAwait(true);
//Clear modified flag
Modified = false;
}
diff --git a/lib/Utils/src/Async/IAsyncExclusiveResource.cs b/lib/Utils/src/Async/IAsyncExclusiveResource.cs
index 93157ce..79657c2 100644
--- a/lib/Utils/src/Async/IAsyncExclusiveResource.cs
+++ b/lib/Utils/src/Async/IAsyncExclusiveResource.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022 Vaughn Nugent
+* Copyright (c) 2023 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Utils
@@ -22,7 +22,9 @@
* along with VNLib.Utils. If not, see http://www.gnu.org/licenses/.
*/
+using System.Threading;
using System.Threading.Tasks;
+
using VNLib.Utils.Resources;
namespace VNLib.Utils.Async
@@ -35,6 +37,6 @@ namespace VNLib.Utils.Async
/// <summary>
/// Releases the resource from use. Called when a <see cref="ExclusiveResourceHandle{T}"/> is disposed
/// </summary>
- ValueTask ReleaseAsync();
+ ValueTask ReleaseAsync(CancellationToken cancellation = default);
}
} \ No newline at end of file
diff --git a/lib/Utils/src/Async/IAsyncResourceStateHandler.cs b/lib/Utils/src/Async/IAsyncResourceStateHandler.cs
new file mode 100644
index 0000000..843af96
--- /dev/null
+++ b/lib/Utils/src/Async/IAsyncResourceStateHandler.cs
@@ -0,0 +1,53 @@
+/*
+* Copyright (c) 2023 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Utils
+* File: IAsyncResourceStateHandler.cs
+*
+* IAsyncResourceStateHandler.cs is part of VNLib.Utils which is part of
+* the larger VNLib collection of libraries and utilities.
+*
+* VNLib.Utils is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published
+* by the Free Software Foundation, either version 2 of the License,
+* or (at your option) any later version.
+*
+* VNLib.Utils is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with VNLib.Utils. If not, see http://www.gnu.org/licenses/.
+*/
+
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace VNLib.Utils.Async
+{
+ /// <summary>
+ /// Represents a resource update handler that processes updates asynchronously
+ /// when requested by a resource holder
+ /// </summary>
+ public interface IAsyncResourceStateHandler
+ {
+ /// <summary>
+ /// Updates the resource in it's backing store
+ /// </summary>
+ /// <param name="resource">The instance of the handler that is requesting the update</param>
+ /// <param name="state">The wrapped resource to update</param>
+ /// <param name="cancellation">A token to cancel the operation</param>
+ /// <returns>A task that completes when the resource data has successfully been updated</returns>
+ Task UpdateAsync(AsyncUpdatableResource resource, object state, CancellationToken cancellation);
+
+ /// <summary>
+ /// Deletes the resource from it's backing store
+ /// </summary>
+ /// <param name="resource">The instance of the source data to delete</param>
+ /// <param name="cancellation">A token to cancel the operation</param>
+ /// <returns>A task that completes when the resource has been deleted</returns>
+ Task DeleteAsync(AsyncUpdatableResource resource, CancellationToken cancellation);
+ }
+}
diff --git a/lib/Utils/src/Extensions/MemoryExtensions.cs b/lib/Utils/src/Extensions/MemoryExtensions.cs
index 0e898b4..32bb3d4 100644
--- a/lib/Utils/src/Extensions/MemoryExtensions.cs
+++ b/lib/Utils/src/Extensions/MemoryExtensions.cs
@@ -334,9 +334,9 @@ namespace VNLib.Utils.Extensions
/// <typeparam name="T">The unmanged data type to provide allocations from</typeparam>
/// <returns>The new <see cref="MemoryPool{T}"/> heap wrapper.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static MemoryPool<T> ToPool<T>(this IUnmangedHeap heap) where T : unmanaged
+ public static MemoryPool<T> ToPool<T>(this IUnmangedHeap heap, int maxBufferSize = int.MaxValue) where T : unmanaged
{
- return new PrivateBuffersMemoryPool<T>(heap);
+ return new PrivateBuffersMemoryPool<T>(heap, maxBufferSize);
}
/// <summary>
@@ -388,6 +388,7 @@ namespace VNLib.Utils.Extensions
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe MemoryHandle<T> Alloc<T>(this IUnmangedHeap heap, nuint elements, bool zero = false) where T : unmanaged
{
+ _ = heap ?? throw new ArgumentNullException(nameof(heap));
//Minimum of one element
elements = Math.Max(elements, 1);
//Get element size
diff --git a/lib/Utils/src/Memory/Caching/LRUCache.cs b/lib/Utils/src/Memory/Caching/LRUCache.cs
index 30608af..0c8e169 100644
--- a/lib/Utils/src/Memory/Caching/LRUCache.cs
+++ b/lib/Utils/src/Memory/Caching/LRUCache.cs
@@ -35,17 +35,20 @@ namespace VNLib.Utils.Memory.Caching
public abstract class LRUCache<TKey, TValue> : LRUDataStore<TKey, TValue> where TKey : notnull
{
///<inheritdoc/>
- protected LRUCache()
- {}
+ protected LRUCache(): base()
+ { }
+
///<inheritdoc/>
protected LRUCache(int initialCapacity) : base(initialCapacity)
- {}
+ { }
+
///<inheritdoc/>
protected LRUCache(IEqualityComparer<TKey> keyComparer) : base(keyComparer)
- {}
+ { }
+
///<inheritdoc/>
protected LRUCache(int initialCapacity, IEqualityComparer<TKey> keyComparer) : base(initialCapacity, keyComparer)
- {}
+ { }
/// <summary>
/// The maximum number of items to store in LRU cache
@@ -121,6 +124,7 @@ namespace VNLib.Utils.Memory.Caching
/// </summary>
/// <param name="evicted">The record that is being evicted</param>
protected abstract void Evicted(ref KeyValuePair<TKey, TValue> evicted);
+
/// <summary>
/// Invoked when an entry was requested and was not found in cache.
/// </summary>
diff --git a/lib/Utils/src/Memory/Caching/LRUDataStore.cs b/lib/Utils/src/Memory/Caching/LRUDataStore.cs
index 89d7c12..c1eb22b 100644
--- a/lib/Utils/src/Memory/Caching/LRUDataStore.cs
+++ b/lib/Utils/src/Memory/Caching/LRUDataStore.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022 Vaughn Nugent
+* Copyright (c) 2023 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Utils
@@ -42,6 +42,7 @@ namespace VNLib.Utils.Memory.Caching
/// A lookup table that provides O(1) access times for key-value lookups
/// </summary>
protected Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>> LookupTable { get; }
+
/// <summary>
/// A linked list that tracks the least recently used item.
/// New items (or recently accessed items) are moved to the end of the list.
@@ -52,11 +53,8 @@ namespace VNLib.Utils.Memory.Caching
/// <summary>
/// Initializes an empty <see cref="LRUDataStore{TKey, TValue}"/>
/// </summary>
- protected LRUDataStore()
- {
- LookupTable = new();
- List = new();
- }
+ protected LRUDataStore() : this(EqualityComparer<TKey>.Default)
+ { }
/// <summary>
/// Initializes an empty <see cref="LRUDataStore{TKey, TValue}"/> and sets
@@ -98,6 +96,7 @@ namespace VNLib.Utils.Memory.Caching
/// <param name="key">The key identifying the value</param>
/// <returns>The value stored at the given key</returns>
/// <remarks>Items are promoted in the store when accessed</remarks>
+ /// <exception cref="KeyNotFoundException"></exception>
public virtual TValue this[TKey key]
{
get
@@ -115,7 +114,7 @@ namespace VNLib.Utils.Memory.Caching
List.Remove(oldNode);
//Reuse the node
- oldNode.ValueRef = new KeyValuePair<TKey, TValue>(key, value);
+ oldNode.Value = new KeyValuePair<TKey, TValue>(key, value);
//Move the item to the back of the list
List.AddLast(oldNode);
@@ -135,8 +134,11 @@ namespace VNLib.Utils.Memory.Caching
/// </summary>
///<exception cref="NotImplementedException"></exception>
public virtual ICollection<TValue> Values => throw new NotSupportedException("Values are not stored in an independent collection, as they are not directly mutable");
+
IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => LookupTable.Keys;
+
IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => List.Select(static node => node.Value);
+
IEnumerator<TValue> IEnumerable<TValue>.GetEnumerator() => List.Select(static node => node.Value).GetEnumerator();
/// <summary>
@@ -164,10 +166,13 @@ namespace VNLib.Utils.Memory.Caching
public bool Remove(in KeyValuePair<TKey, TValue> item) => Remove(item.Key);
///<inheritdoc/>
IEnumerator IEnumerable.GetEnumerator() => List.GetEnumerator();
+
///<inheritdoc/>
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) => List.CopyTo(array, arrayIndex);
+
///<inheritdoc/>
public virtual bool ContainsKey(TKey key) => LookupTable.ContainsKey(key);
+
///<inheritdoc/>
public virtual IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => List.GetEnumerator();
@@ -194,6 +199,7 @@ namespace VNLib.Utils.Memory.Caching
LookupTable.Clear();
List.Clear();
}
+
/// <summary>
/// Determines if the <see cref="KeyValuePair{TKey, TValue}"/> exists in the store
/// </summary>
@@ -207,6 +213,7 @@ namespace VNLib.Utils.Memory.Caching
}
return false;
}
+
///<inheritdoc/>
public virtual bool Remove(TKey key)
{
@@ -219,6 +226,7 @@ namespace VNLib.Utils.Memory.Caching
}
return false;
}
+
/// <summary>
/// Tries to get a value from the store with its key. Found items are promoted
/// </summary>
diff --git a/lib/Utils/src/Memory/PrivateBuffersMemoryPool.cs b/lib/Utils/src/Memory/PrivateBuffersMemoryPool.cs
index e73a26f..f2bbd51 100644
--- a/lib/Utils/src/Memory/PrivateBuffersMemoryPool.cs
+++ b/lib/Utils/src/Memory/PrivateBuffersMemoryPool.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022 Vaughn Nugent
+* Copyright (c) 2023 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Utils
@@ -28,19 +28,22 @@ using System.Buffers;
namespace VNLib.Utils.Memory
{
/// <summary>
- /// Provides a <see cref="MemoryPool{T}"/> wrapper for using unmanged <see cref="Win32PrivateHeap"/>s
+ /// Provides a <see cref="MemoryPool{T}"/> wrapper for using an <see cref="IUnmangedHeap"/>s
/// </summary>
/// <typeparam name="T">Unamanged memory type to provide data memory instances from</typeparam>
public sealed class PrivateBuffersMemoryPool<T> : MemoryPool<T> where T : unmanaged
{
private readonly IUnmangedHeap Heap;
- internal PrivateBuffersMemoryPool(IUnmangedHeap heap):base()
+ internal PrivateBuffersMemoryPool(IUnmangedHeap heap, int maxSize)
{
- this.Heap = heap;
+ Heap = heap;
+ MaxBufferSize = maxSize;
}
+
///<inheritdoc/>
- public override int MaxBufferSize => int.MaxValue;
+ public override int MaxBufferSize { get; }
+
///<inheritdoc/>
///<exception cref="OutOfMemoryException"></exception>
///<exception cref="ObjectDisposedException"></exception>
@@ -53,10 +56,8 @@ namespace VNLib.Utils.Memory
/// <typeparam name="TDifType">The unmanaged data type to allocate for</typeparam>
/// <param name="minBufferSize">Minumum size of the buffer</param>
/// <returns>The memory owner of a different data type</returns>
- public IMemoryOwner<TDifType> Rent<TDifType>(int minBufferSize = 0) where TDifType : unmanaged
- {
- return new SysBufferMemoryManager<TDifType>(Heap, (uint)minBufferSize, false);
- }
+ public IMemoryOwner<TDifType> Rent<TDifType>(int minBufferSize = 0) where TDifType : unmanaged => new SysBufferMemoryManager<TDifType>(Heap, (uint)minBufferSize, false);
+
///<inheritdoc/>
protected override void Dispose(bool disposing)
{
diff --git a/lib/Utils/src/Resources/BackedResourceBase.cs b/lib/Utils/src/Resources/BackedResourceBase.cs
index 0a2e1e3..22a965c 100644
--- a/lib/Utils/src/Resources/BackedResourceBase.cs
+++ b/lib/Utils/src/Resources/BackedResourceBase.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022 Vaughn Nugent
+* Copyright (c) 2023 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Utils
@@ -23,7 +23,6 @@
*/
using System;
-using System.Text.Json;
using System.Runtime.CompilerServices;
namespace VNLib.Utils.Resources
@@ -34,23 +33,36 @@ namespace VNLib.Utils.Resources
/// </summary>
public abstract class BackedResourceBase : IResource
{
- ///<inheritdoc/>
- public bool IsReleased { get; protected set; }
+ const int IsReleasedFlag = 1 << 0;
+ const int IsDeletedFlag = 1 << 2;
+ const int IsModifiedFlag = 1 << 3;
- /// <summary>
- /// Optional <see cref="JsonSerializerOptions"/> to be used when serializing
- /// the resource
- /// </summary>
- internal protected virtual JsonSerializerOptions? JSO { get; }
+ private uint _flags;
+
+ ///<inheritdoc/>
+ public bool IsReleased
+ {
+ get => (_flags & IsReleasedFlag) == IsReleasedFlag;
+ protected set => _flags |= IsReleasedFlag;
+ }
/// <summary>
/// A value indicating whether the instance should be deleted when released
/// </summary>
- protected bool Deleted { get; set; }
+ protected bool Deleted
+ {
+ get => (_flags & IsDeletedFlag) == IsDeletedFlag;
+ set => _flags |= IsDeletedFlag;
+ }
+
/// <summary>
/// A value indicating whether the instance should be updated when released
/// </summary>
- protected bool Modified { get; set; }
+ protected bool Modified
+ {
+ get => (_flags & IsModifiedFlag) == IsModifiedFlag;
+ set => _flags |= IsModifiedFlag;
+ }
/// <summary>
/// Checks if the resouce has been disposed and raises an exception if it is
@@ -61,7 +73,7 @@ namespace VNLib.Utils.Resources
{
if (IsReleased)
{
- throw new ObjectDisposedException("The resource has been disposed");
+ throw new ObjectDisposedException(null, "The resource has been disposed");
}
}
@@ -74,6 +86,6 @@ namespace VNLib.Utils.Resources
/// <summary>
/// Marks the resource for deletion from backing store during closing events
/// </summary>
- public virtual void Delete() => Deleted = true;
+ public virtual void Delete() => _flags |= IsDeletedFlag;
}
} \ No newline at end of file
diff --git a/lib/Utils/src/Resources/IResourceStateHandler.cs b/lib/Utils/src/Resources/IResourceStateHandler.cs
new file mode 100644
index 0000000..c3d0d56
--- /dev/null
+++ b/lib/Utils/src/Resources/IResourceStateHandler.cs
@@ -0,0 +1,47 @@
+/*
+* Copyright (c) 2023 Vaughn Nugent
+*
+* Library: VNLib
+* Package: VNLib.Utils
+* File: IResourceStateHandler.cs
+*
+* IResourceStateHandler.cs is part of VNLib.Utils which is part of the larger
+* VNLib collection of libraries and utilities.
+*
+* VNLib.Utils is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published
+* by the Free Software Foundation, either version 2 of the License,
+* or (at your option) any later version.
+*
+* VNLib.Utils is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with VNLib.Utils. If not, see http://www.gnu.org/licenses/.
+*/
+
+namespace VNLib.Utils.Resources
+{
+ /// <summary>
+ /// Implemented by a resource that is backed by an external data store, that when modified or deleted will
+ /// be reflected to the backing store.
+ /// </summary>
+ public interface IResourceStateHandler
+ {
+ /// <summary>
+ /// Called when a resource update has been requested
+ /// </summary>
+ /// <param name="resource">The <see cref="UpdatableResource"/> to be updated</param>
+ /// <param name="data">The wrapped state data to update</param>
+ void Update(UpdatableResource resource, object data);
+
+ /// <summary>
+ /// Called when a resource delete has been requested
+ /// </summary>
+ /// <param name="resource">The <see cref="UpdatableResource"/> to be deleted</param>
+ /// <exception cref="ResourceDeleteFailedException"></exception>
+ void Delete(UpdatableResource resource);
+ }
+} \ No newline at end of file
diff --git a/lib/Utils/src/Resources/UpdatableResource.cs b/lib/Utils/src/Resources/UpdatableResource.cs
index 16f26f2..68072f9 100644
--- a/lib/Utils/src/Resources/UpdatableResource.cs
+++ b/lib/Utils/src/Resources/UpdatableResource.cs
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2022 Vaughn Nugent
+* Copyright (c) 2023 Vaughn Nugent
*
* Library: VNLib
* Package: VNLib.Utils
@@ -23,25 +23,9 @@
*/
using System;
-using System.IO;
-
-using VNLib.Utils.IO;
namespace VNLib.Utils.Resources
{
- /// <summary>
- /// A callback delegate used for updating a <see cref="UpdatableResource"/>
- /// </summary>
- /// <param name="source">The <see cref="UpdatableResource"/> to be updated</param>
- /// <param name="data">The serialized data to be stored/updated</param>
- /// <exception cref="ResourceUpdateFailedException"></exception>
- public delegate void UpdateCallback(object source, Stream data);
- /// <summary>
- /// A callback delegate invoked when a <see cref="UpdatableResource"/> delete is requested
- /// </summary>
- /// <param name="source">The <see cref="UpdatableResource"/> to be deleted</param>
- /// <exception cref="ResourceDeleteFailedException"></exception>
- public delegate void DeleteCallback(object source);
/// <summary>
/// Implemented by a resource that is backed by an external data store, that when modified or deleted will
@@ -50,19 +34,11 @@ namespace VNLib.Utils.Resources
public abstract class UpdatableResource : BackedResourceBase, IExclusiveResource
{
/// <summary>
- /// The update callback method to invoke during a release operation
- /// when the resource is updated.
+ /// Gets the <see cref="IResourceStateHandler"/> that will be invoked when the resource is released
/// </summary>
- protected abstract UpdateCallback UpdateCb { get; }
- /// <summary>
- /// The callback method to invoke during a realease operation
- /// when the resource should be deleted
- /// </summary>
- protected abstract DeleteCallback DeleteCb { get; }
+ protected abstract IResourceStateHandler Handler { get; }
- /// <summary>
/// <inheritdoc/>
- /// </summary>
/// <exception cref="InvalidOperationException"></exception>
/// <exception cref="ResourceDeleteFailedException"></exception>
/// <exception cref="ResourceUpdateFailedException"></exception>
@@ -76,7 +52,7 @@ namespace VNLib.Utils.Resources
//If deleted flag is set, invoke the delete callback
if (Deleted)
{
- DeleteCb(this);
+ Handler.Delete(this);
}
//If the state has been modifed, flush changes to the store
else if (Modified)
@@ -88,24 +64,20 @@ namespace VNLib.Utils.Resources
}
/// <summary>
+ /// <para>
/// Writes the current state of the the resource to the backing store
/// immediatly by invoking the specified callback.
- /// <br></br>
- /// <br></br>
+ /// </para>
+ /// <para>
/// Only call this method if your store supports multiple state updates
+ /// </para>
/// </summary>
protected virtual void FlushPendingChanges()
{
//Get the resource
object resource = GetResource();
- //Open a memory stream to store data in
- using VnMemoryStream data = new();
- //Serialize and write to stream
- VnEncoding.JSONSerializeToBinary(resource, data, resource.GetType(), JSO);
- //Reset stream to begining
- _ = data.Seek(0, SeekOrigin.Begin);
//Invoke update callback
- UpdateCb(this, data);
+ Handler.Update(this, resource);
//Clear modified flag
Modified = false;
}
diff --git a/lib/Utils/src/VnEncoding.cs b/lib/Utils/src/VnEncoding.cs
index 35d52a7..9a50a50 100644
--- a/lib/Utils/src/VnEncoding.cs
+++ b/lib/Utils/src/VnEncoding.cs
@@ -471,7 +471,8 @@ namespace VNLib.Utils
}
}
return value;
- }
+ }
+
/// <summary>
/// Converts the base32 character buffer to its structure representation
/// </summary>
@@ -485,7 +486,7 @@ namespace VNLib.Utils
//calc size of bin buffer
int size = base32.Length;
//Rent a bin buffer
- using UnsafeMemoryHandle<byte> binBuffer = Memory.MemoryUtil.UnsafeAlloc(size);
+ using UnsafeMemoryHandle<byte> binBuffer = MemoryUtil.UnsafeAlloc(size);
//Try to decode the data
ERRNO decoded = TryFromBase32Chars(base32, binBuffer.Span);
//Marshal back to a struct
@@ -505,7 +506,7 @@ namespace VNLib.Utils
return null;
}
//Buffer size of the base32 string will always be enough buffer space
- using UnsafeMemoryHandle<byte> tempBuffer = Memory.MemoryUtil.UnsafeAlloc(base32.Length);
+ using UnsafeMemoryHandle<byte> tempBuffer = MemoryUtil.UnsafeAlloc(base32.Length);
//Try to decode the data
ERRNO decoded = TryFromBase32Chars(base32, tempBuffer.Span);
@@ -704,6 +705,7 @@ namespace VNLib.Utils
{
return Convert.TryFromBase64Chars(base64, buffer, out int bytesWritten) ? bytesWritten : ERRNO.E_FAIL;
}
+
/// <summary>
/// Tries to convert the 8-bit unsigned integers inside the specified read-only span
/// into their equivalent string representation that is encoded with base-64 digits.