Skip to content

Commit

Permalink
Fix an issue with singleton's getting GC'd
Browse files Browse the repository at this point in the history
  • Loading branch information
jjv360 committed Mar 13, 2023
1 parent 8248970 commit 5efc2e1
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 4 deletions.
2 changes: 1 addition & 1 deletion classes.nimble
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Package
version = "0.3.16"
version = "0.3.17"
author = "jjv360"
description = "Adds class support to Nim."
license = "MIT"
Expand Down
21 changes: 18 additions & 3 deletions src/classes/plugin_singleton.nim
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,36 @@ proc injectSharedAccessor(classDef : ClassDescription) =
return

# Create a function called shared() which returns a single instance of this class
var sharedInstanceVarName = ident("__sharedInstance_" & $classDef.name)
var methodDef = Method()
let className = classDef.name
methodDef.definition = quote do:
method shared*() : `className`
methodDef.body = quote do:
var singletonInstance {.global.} : `className` = nil
if singletonInstance == nil: singletonInstance = `className`.init()
return singletonInstance
if `sharedInstanceVarName` == nil: `sharedInstanceVarName` = `className`.init()
return `sharedInstanceVarName`
methodDef.isStatic = true
classDef.methods.definitions.add(methodDef)

## Inject the shared variable into the class body
proc injectSharedVar(classDef : ClassDescription) =

# Stop if not a singleton
if classDef.macroName != "singleton":
return

# Add the code before the method bodies
var sharedInstanceVarName = ident("__sharedInstance_" & $classDef.name)
var className = classDef.name
classDef.outputForwardDeclarations.add(quote do:
var `sharedInstanceVarName` : `className` = nil
)


## Register the plugin at compile-time
static:
classCompilerPlugins.add(proc(stage : ClassCompilerStage, classDef : ClassDescription) =
if stage == ClassCompilerGatherDefinitions: injectSharedAccessor(classDef)
if stage == ClassCompilerGenerateCode: injectSharedVar(classDef)
)

11 changes: 11 additions & 0 deletions test.nim
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,17 @@ singleton Singleton2 of Singleton1:

method myFunc(): int = 6

## Ensure only one class is created
var singletonCounter = 0
singleton SingleTest:
method init() = singletonCounter += 1
method deinit() = singletonCounter -= 1
method test() = discard
SingleTest.shared.test()
SingleTest.shared.test()
assert(SingleTest.shared == SingleTest.shared, "Only one instance of a singleton should exist.")
assert(singletonCounter == 1, "Singleton constructor should only run once")

test "Subclassing"
assert(Singleton2.shared.v1 == 3)
assert(Singleton2.shared.v2 == 4)
Expand Down

0 comments on commit 5efc2e1

Please sign in to comment.