diff src/name/blackcap/clipman/Misc.kt @ 47:19d9da731c43

Recoded; cleaned up root namespace, removed race conditions.
author David Barts <n5jrn@me.com>
date Sun, 12 Apr 2020 14:31:06 -0700
parents 33fbe3a78d84
children 3f8409470fdf
line wrap: on
line diff
--- a/src/name/blackcap/clipman/Misc.kt	Mon Feb 10 16:40:09 2020 -0700
+++ b/src/name/blackcap/clipman/Misc.kt	Sun Apr 12 14:31:06 2020 -0700
@@ -8,6 +8,9 @@
 import java.nio.charset.Charset
 import javax.swing.*
 import javax.swing.text.JTextComponent
+import kotlin.annotation.*
+import kotlin.properties.ReadWriteProperty
+import kotlin.reflect.*
 
 /**
  * Name of the character set (encoding) we preferentially use for many
@@ -17,35 +20,39 @@
 val CHARSET = Charset.forName(CHARSET_NAME)
 
 /**
- * Allows a val to have lateinit functionality. It is an error to attempt
- * to retrieve this object's value unless it has been set, and it is an
- * error to attempt to set the value of an already-set object.
+ * Delegate that makes a var that can only be set once. This is commonly
+ * needed in Swing, because some vars inevitably need to be declared at
+ * outer levels but initialized in the Swing event dispatch thread.
+ *
  * @param &lt;T&gt; type of the associated value
  */
-class LateInit<T> {
-    private var _v: T? = null
+class SetOnceImpl<T>: ReadWriteProperty<Any?,T> {
+    private var setOnceValue: T? = null
 
-    /**
-     * The value associated with this object. The name of this property is
-     * deliberately short.
-     */
-    var v: T
-    get() {
-        if (_v == null) {
-            throw IllegalStateException("cannot retrieve un-initialized value")
+    override operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
+        if (setOnceValue == null) {
+            throw RuntimeException("${property.name} has not been initialized")
         } else {
-            return _v!!
+            return setOnceValue!!
         }
     }
-    @Synchronized set(value) {
-        if (_v != null) {
-            throw IllegalStateException("cannot set already-initialized value")
+
+    @Synchronized
+    override operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T): Unit {
+        if (setOnceValue != null) {
+            throw RuntimeException("${property.name} has already been initialized")
         }
-        _v = value
+        setOnceValue = value
     }
 }
 
 /**
+ * Normal way to create a setOnce var:
+ * var something: SomeType by setOnce()
+ */
+fun <T> setOnce(): SetOnceImpl<T> = SetOnceImpl<T>()
+
+/**
  * Run something in the Swing thread, asynchronously.
  * @param block lambda containing code to run
  */
@@ -99,4 +106,3 @@
     }
     return null
 }
-