diff --git a/src/spectator/lazy_wrapper.cr b/src/spectator/lazy_wrapper.cr new file mode 100644 index 0000000..438e58b --- /dev/null +++ b/src/spectator/lazy_wrapper.cr @@ -0,0 +1,19 @@ +require "./lazy" +require "./wrapper" + +module Spectator + # Lazily stores a value of any type. + # Combines `Lazy` and `Wrapper`. + struct LazyWrapper + @lazy = Lazy(Wrapper).new + + # Retrieves the value, if it was previously fetched. + # On the first invocation of this method, it will yield. + # The block should return the value to store. + # Subsequent calls will return the same value and not yield. + def get(type : T.class, &block : -> T) : T forall T + wrapper = @lazy.get { Wrapper.new(yield) } + wrapper.get(type) + end + end +end diff --git a/src/spectator/wrapper.cr b/src/spectator/wrapper.cr new file mode 100644 index 0000000..efee1b6 --- /dev/null +++ b/src/spectator/wrapper.cr @@ -0,0 +1,41 @@ +module Spectator + # Typeless wrapper for a value. + # Stores any value or reference type. + # However, the type must be known when retrieving the value. + struct Wrapper + @value : TypelessValue + + # Creates a wrapper for the specified value. + def initialize(value) + @value = Value.new(value) + end + + # Retrieves the previously wrapped value. + # The *type* of the wrapped value must match otherwise an error will be raised. + def get(type : T.class) : T forall T + value = @value.as(Value(T)) + value.get + end + + # Base type that generic types inherit from. + # This provides a common base type, + # since Crystal doesn't support storing an `Object` (yet). + # Instances of this type must be downcast to `Value` to be useful. + private abstract class TypelessValue + end + + # Generic value wrapper. + # Simply holds a value and inherits from `TypelessValue`, + # so that all types of this class can be stored as one. + private class Value(T) < TypelessValue + # Creates the wrapper with the specified value. + def initialize(@value : T) + end + + # Retrieves the wrapped value. + def get : T + @value + end + end + end +end