74 lines
2.9 KiB
Ruby
74 lines
2.9 KiB
Ruby
module Concurrent
|
|
module Concern
|
|
|
|
# Object references in Ruby are mutable. This can lead to serious problems when
|
|
# the `#value` of a concurrent object is a mutable reference. Which is always the
|
|
# case unless the value is a `Fixnum`, `Symbol`, or similar "primitive" data type.
|
|
# Most classes in this library that expose a `#value` getter method do so using the
|
|
# `Dereferenceable` mixin module.
|
|
#
|
|
# @!macro copy_options
|
|
module Dereferenceable
|
|
# NOTE: This module is going away in 2.0. In the mean time we need it to
|
|
# play nicely with the synchronization layer. This means that the
|
|
# including class SHOULD be synchronized and it MUST implement a
|
|
# `#synchronize` method. Not doing so will lead to runtime errors.
|
|
|
|
# Return the value this object represents after applying the options specified
|
|
# by the `#set_deref_options` method.
|
|
#
|
|
# @return [Object] the current value of the object
|
|
def value
|
|
synchronize { apply_deref_options(@value) }
|
|
end
|
|
alias_method :deref, :value
|
|
|
|
protected
|
|
|
|
# Set the internal value of this object
|
|
#
|
|
# @param [Object] value the new value
|
|
def value=(value)
|
|
synchronize{ @value = value }
|
|
end
|
|
|
|
# @!macro dereferenceable_set_deref_options
|
|
# Set the options which define the operations #value performs before
|
|
# returning data to the caller (dereferencing).
|
|
#
|
|
# @note Most classes that include this module will call `#set_deref_options`
|
|
# from within the constructor, thus allowing these options to be set at
|
|
# object creation.
|
|
#
|
|
# @param [Hash] opts the options defining dereference behavior.
|
|
# @option opts [String] :dup_on_deref (false) call `#dup` before returning the data
|
|
# @option opts [String] :freeze_on_deref (false) call `#freeze` before returning the data
|
|
# @option opts [String] :copy_on_deref (nil) call the given `Proc` passing
|
|
# the internal value and returning the value returned from the proc
|
|
def set_deref_options(opts = {})
|
|
synchronize{ ns_set_deref_options(opts) }
|
|
end
|
|
|
|
# @!macro dereferenceable_set_deref_options
|
|
# @!visibility private
|
|
def ns_set_deref_options(opts)
|
|
@dup_on_deref = opts[:dup_on_deref] || opts[:dup]
|
|
@freeze_on_deref = opts[:freeze_on_deref] || opts[:freeze]
|
|
@copy_on_deref = opts[:copy_on_deref] || opts[:copy]
|
|
@do_nothing_on_deref = !(@dup_on_deref || @freeze_on_deref || @copy_on_deref)
|
|
nil
|
|
end
|
|
|
|
# @!visibility private
|
|
def apply_deref_options(value)
|
|
return nil if value.nil?
|
|
return value if @do_nothing_on_deref
|
|
value = @copy_on_deref.call(value) if @copy_on_deref
|
|
value = value.dup if @dup_on_deref
|
|
value = value.freeze if @freeze_on_deref
|
|
value
|
|
end
|
|
end
|
|
end
|
|
end
|