90 lines
2.2 KiB
Ruby
90 lines
2.2 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
# Released under the MIT License.
|
|
# Copyright, 2022-2024, by Samuel Williams.
|
|
|
|
require 'fiber'
|
|
|
|
# @namespace
|
|
class Fiber
|
|
# Provides compatibility shims for fiber storage.
|
|
module Storage
|
|
# Initialize the fiber with the given storage.
|
|
def initialize(*arguments, storage: true, **options, &block)
|
|
case storage
|
|
when true
|
|
@storage = Fiber.current.storage
|
|
else
|
|
raise TypeError, "Storage must be a hash!" unless storage.is_a?(Hash)
|
|
|
|
@storage = storage
|
|
end
|
|
|
|
super(*arguments, **options, &block)
|
|
end
|
|
|
|
# Set the storage associated with this fiber, clearing any previous storage.
|
|
def storage=(hash)
|
|
@storage = hash.dup
|
|
end
|
|
|
|
# The storage associated with this fiber.
|
|
def storage
|
|
@storage.dup
|
|
end
|
|
|
|
# @private
|
|
def __storage__
|
|
@storage ||= {}
|
|
end
|
|
end
|
|
|
|
unless Fiber.current.respond_to?(:storage)
|
|
prepend Storage
|
|
|
|
# Get a value from the current fiber's storage.
|
|
def self.[] key
|
|
raise TypeError, "Key must be symbol!" unless key.is_a?(Symbol)
|
|
|
|
self.current.__storage__[key]
|
|
end
|
|
|
|
# Set a value in the current fiber's storage.
|
|
def self.[]= key, value
|
|
raise TypeError, "Key must be symbol!" unless key.is_a?(Symbol)
|
|
|
|
self.current.__storage__[key] = value
|
|
end
|
|
else
|
|
# Whether the fiber storage has buggy keys. Unfortunately the original implementation of fiber storage was broken, this method detects the bug and is used to apply a fix.
|
|
def self.__borked_keys__
|
|
!Fiber.new do
|
|
key = :"#{self.object_id}.key"
|
|
Fiber[key] = true
|
|
Fiber[key]
|
|
end.resume
|
|
end
|
|
|
|
if __borked_keys__
|
|
# This is a fix for the original implementation of fiber storage which incorrectly handled non-dynamic symbol keys.
|
|
module FixBorkedKeys
|
|
# Lookup the value for the key, ensuring the symbol is dynamic.
|
|
def [](key)
|
|
raise TypeError, "Key must be symbol!" unless key.is_a?(Symbol)
|
|
|
|
super(eval(key.inspect))
|
|
end
|
|
|
|
# Assign the value to the key, ensuring the symbol is dynamic.
|
|
def []=(key, value)
|
|
raise TypeError, "Key must be symbol!" unless key.is_a?(Symbol)
|
|
|
|
super(eval(key.inspect), value)
|
|
end
|
|
end
|
|
|
|
singleton_class.prepend FixBorkedKeys
|
|
end
|
|
end
|
|
end
|