From 28227040d3dc9d7a22e6003999b62db9c52b35f3 Mon Sep 17 00:00:00 2001 From: Jaremy Creechley Date: Tue, 5 Sep 2023 13:18:07 -0700 Subject: [PATCH] add docs --- datastore/threadbackend.nim | 39 ++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/datastore/threadbackend.nim b/datastore/threadbackend.nim index 087dc48..29ed620 100644 --- a/datastore/threadbackend.nim +++ b/datastore/threadbackend.nim @@ -17,12 +17,30 @@ export key, query, smartptrs, databuffer push: {.upraises: [].} type - ThreadSafeTypes* = DataBuffer | void | bool | ThreadDatastorePtr | QueryResponseBuffer + ThreadSafeTypes* = DataBuffer | void | bool | ThreadDatastorePtr | QueryResponseBuffer ##\ + ## This is a whitelisting of types that can be used with ThreadResult below + ## These types need to be thread safe with refc. That means no + ## GC types. + ThreadResult*[T: ThreadSafeTypes] = object + ## Encapsulates both the results from a thread but also the cross + ## thread signaling mechanism. This makes it easier to keep them + ## together. signal*: ThreadSignalPtr results*: Result[T, CatchableErrorBuffer] - TResult*[T] = SharedPtr[ThreadResult[T]] + TResult*[T] = SharedPtr[ThreadResult[T]] ##\ + ## SharedPtr that allocates a shared buffer and keeps the + ## memory allocated until all references to it are gone. + ## + ## Since ThreadResult is a plain object, and if its lifetime is + ## tied to that of an async proc or the thread-backend request + ## it could be freed before the other thread is finished. + ## + ## For example, `myFuture.cancel()` can end an async proc early. + ## If the ThreadResult was stored in the async's memory then it'd + ## be free'ed along with the rest of the async env. This would + ## result in likely memory corruption (use-after-free). ThreadDatastore* = object tp*: Taskpool @@ -37,6 +55,11 @@ type proc newThreadResult*[T]( tp: typedesc[T] ): Result[TResult[T], ref CatchableError] = + ## Creates a new TResult including allocating + ## a new ThreadSignalPtr. + ## + ## Since allocating the TSP can fail, this returns + ## a Result. let res = newSharedPtr(ThreadResult[T]) let signal = ThreadSignalPtr.new() if signal.isErr: @@ -46,15 +69,25 @@ proc newThreadResult*[T]( ok res proc success*[T](ret: TResult[T], value: T) = + ## convenience wrapper for `TResult` to make + ## "returning" results easier ret[].results.ok(value) proc success*[T: void](ret: TResult[T]) = + ## convenience wrapper for `TResult` to make + ## "returning" results easier ret[].results.ok() proc failure*[T](ret: TResult[T], exc: ref Exception) = + ## convenience wrapper for `TResult` to make + ## "returning" results easier ret[].results.err(exc.toBuffer()) -proc convert*[T, S](ret: TResult[T], tp: typedesc[S]): Result[S, ref CatchableError] = +proc convert*[T, S](ret: TResult[T], + tp: typedesc[S] + ): Result[S, ref CatchableError] = + ## convenience wrapper for `TResult` to make + ## fetching results from `TResult` easier. if ret[].results.isOk(): when S is seq[byte]: result.ok(ret[].results.get().toSeq(byte))