Added some kind of environment handling.
authorFredrik Tolf <fredrik@dolda2000.com>
Fri, 25 Feb 2022 16:39:51 +0000 (17:39 +0100)
committerFredrik Tolf <fredrik@dolda2000.com>
Fri, 25 Feb 2022 16:39:51 +0000 (17:39 +0100)
src/jrw/Dispatch.java
src/jrw/Environment.java [new file with mode: 0644]

index d08867c..10b0909 100644 (file)
@@ -4,11 +4,13 @@ import java.util.*;
 
 public class Dispatch {
     public static Map<Object, Object> handle(Handler handler, Request req) {
-       while(true) {
-           try {
-               return(handler.handle(req));
-           } catch(Restart r) {
-               handler = r;
+       try(Environment.Frame f = new Environment().frame()) {
+           while(true) {
+               try {
+                   return(handler.handle(req));
+               } catch(Restart r) {
+                   handler = r;
+               }
            }
        }
     }
diff --git a/src/jrw/Environment.java b/src/jrw/Environment.java
new file mode 100644 (file)
index 0000000..a93b149
--- /dev/null
@@ -0,0 +1,85 @@
+package jrw;
+
+import java.util.*;
+import java.util.function.*;
+
+public class Environment {
+    public static final Environment root = new Environment();
+    private static final ThreadLocal<Environment> current = new ThreadLocal<>();
+    public final Environment parent;
+    private Map<Variable<?>, Object> data = Collections.emptyMap();
+
+    public static class Variable<T> {
+       private final Supplier<? extends T> ival;
+       private T rval;
+       private boolean inited;
+
+       public Variable(Supplier<? extends T> ival) {
+           this.ival = ival;
+       }
+
+       @SuppressWarnings("unchecked")
+       public T get() {
+           for(Environment env = current(); env != null; env = env.parent) {
+               Map<Variable<?>, Object> data = env.data;
+               if(data.containsKey(this))
+                   return((T)data.get(this));
+           }
+           if(!inited) {
+               synchronized(this) {
+                   if(!inited) {
+                       rval = (this.ival == null) ? null : this.ival.get();
+                       inited = true;
+                   }
+               }
+           }
+           return(rval);
+       }
+    }
+
+    public Environment(Environment parent) {
+       this.parent = parent;
+    }
+
+    public Environment() {
+       this(current());
+    }
+
+    public <T> void set(Variable<T> var, T val) {
+       synchronized(this) {
+           Map<Variable<?>, Object> data = new IdentityHashMap<>(this.data);
+           data.put(var, val);
+           this.data = data;
+       }
+    }
+
+    public <T> void clear(Variable<T> var, T val) {
+       synchronized(this) {
+           Map<Variable<?>, Object> data = new IdentityHashMap<>(this.data);
+           data.remove(var);
+           this.data = data;
+       }
+    }
+
+    public static Environment current() {
+       Environment ret = current.get();
+       return((ret == null) ? root : ret);
+    }
+
+    public class Frame implements AutoCloseable {
+       private final Environment prev;
+
+       private Frame() {
+           this.prev = current.get();
+           current.set(Environment.this);
+       }
+
+       public void close() {
+           current.set(prev);
+       }
+    }
+
+    public Frame frame() {
+       return(new Frame());
+    }
+}