File: settable_struct.rb

package info (click to toggle)
ruby-concurrent 1.1.6%2Bdfsg-5
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 30,284 kB
  • sloc: ruby: 30,875; java: 6,117; javascript: 1,114; ansic: 288; makefile: 10; sh: 6
file content (139 lines) | stat: -rw-r--r-- 4,011 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
require 'concurrent/synchronization/abstract_struct'
require 'concurrent/errors'
require 'concurrent/synchronization'

module Concurrent

  # An thread-safe, write-once variation of Ruby's standard `Struct`.
  # Each member can have its value set at most once, either at construction
  # or any time thereafter. Attempting to assign a value to a member
  # that has already been set will result in a `Concurrent::ImmutabilityError`.
  #
  # @see http://ruby-doc.org/core-2.2.0/Struct.html Ruby standard library `Struct`
  # @see http://en.wikipedia.org/wiki/Final_(Java) Java `final` keyword
  module SettableStruct
    include Synchronization::AbstractStruct

    # @!macro struct_values
    def values
      synchronize { ns_values }
    end
    alias_method :to_a, :values

    # @!macro struct_values_at
    def values_at(*indexes)
      synchronize { ns_values_at(indexes) }
    end

    # @!macro struct_inspect
    def inspect
      synchronize { ns_inspect }
    end
    alias_method :to_s, :inspect

    # @!macro struct_merge
    def merge(other, &block)
      synchronize { ns_merge(other, &block) }
    end

    # @!macro struct_to_h
    def to_h
      synchronize { ns_to_h }
    end

    # @!macro struct_get
    def [](member)
      synchronize { ns_get(member) }
    end

    # @!macro struct_equality
    def ==(other)
      synchronize { ns_equality(other) }
    end

    # @!macro struct_each
    def each(&block)
      return enum_for(:each) unless block_given?
      synchronize { ns_each(&block) }
    end

    # @!macro struct_each_pair
    def each_pair(&block)
      return enum_for(:each_pair) unless block_given?
      synchronize { ns_each_pair(&block) }
    end

    # @!macro struct_select
    def select(&block)
      return enum_for(:select) unless block_given?
      synchronize { ns_select(&block) }
    end

    # @!macro struct_set
    #
    # @raise [Concurrent::ImmutabilityError] if the given member has already been set
    def []=(member, value)
      if member.is_a? Integer
        length = synchronize { @values.length }
        if member >= length
          raise IndexError.new("offset #{member} too large for struct(size:#{length})")
        end
        synchronize do
          unless @values[member].nil?
            raise Concurrent::ImmutabilityError.new('struct member has already been set')
          end
          @values[member] = value
        end
      else
        send("#{member}=", value)
      end
    rescue NoMethodError
      raise NameError.new("no member '#{member}' in struct")
    end

    private

    # @!visibility private
    def initialize_copy(original)
      synchronize do
        super(original)
        ns_initialize_copy
      end
    end

    # @!macro struct_new
    def self.new(*args, &block)
      clazz_name = nil
      if args.length == 0
        raise ArgumentError.new('wrong number of arguments (0 for 1+)')
      elsif args.length > 0 && args.first.is_a?(String)
        clazz_name = args.shift
      end
      FACTORY.define_struct(clazz_name, args, &block)
    end

    FACTORY = Class.new(Synchronization::LockableObject) do
      def define_struct(name, members, &block)
        synchronize do
          clazz = Synchronization::AbstractStruct.define_struct_class(SettableStruct, Synchronization::LockableObject, name, members, &block)
          members.each_with_index do |member, index|
            clazz.send :remove_method, member if clazz.instance_methods.include? member
            clazz.send(:define_method, member) do
              synchronize { @values[index] }
            end
            clazz.send(:define_method, "#{member}=") do |value|
              synchronize do
                unless @values[index].nil?
                  raise Concurrent::ImmutabilityError.new('struct member has already been set')
                end
                @values[index] = value
              end
            end
          end
          clazz
        end
      end
    end.new
    private_constant :FACTORY
  end
end