1 package DX::Predicate::MemberAt;
3 use DX::Utils qw(:builders :dep_types);
4 use DX::ActionBuilder::ProxySetToAdd;
5 use DX::ActionBuilder::Null;
8 with 'DX::Role::Predicate';
10 sub _possible_resolution_list {
11 my ($self, $coll, $key, $value) = @_;
12 die "First argument to member_at must be a structured value"
13 unless $coll->does('DX::Role::StructuredValue');
14 my $basic_deps = sub {
16 [ EXISTENCE_OF ,=> $coll, ($_[1]||$_[0])->string_value ],
17 [ CONTENTS_OF ,=> $_[0] ],
18 [ CONTENTS_OF ,=> $coll, ($_[1]||$_[0])->string_value ],
19 [ CONTENTS_OF ,=> $value ],
23 # Already set values are only supported for recheck
24 trace member_at => "+D +K +V";
25 return () unless $key->is_set and my $cur_val = $coll->get_member_at($key);
26 return () unless $cur_val->equals($value);
32 die "Bizarre: member_at called with non-fresh unset value"
33 unless $value->action_builder->isa('DX::ActionBuilder::UnsetValue');
35 trace member_at => "+D +K -V";
36 if (my $cur_val = $coll->get_member_at($key)) {
37 my $set = $value->action_for_set_value($cur_val);
43 if (my $p = $coll->value_path) {
44 my @path = (@$p, $key->string_value);
45 my $ab = DX::ActionBuilder::ProxySetToAdd->new(
46 target_path => \@path,
47 proxy_to => $coll->action_builder,
49 my $set = $value->action_for_set_value(
61 die "Bizarre: member_at called with non-fresh unset key"
62 unless $key->action_builder->isa('DX::ActionBuilder::UnsetValue');
63 trace member_at => "+D -K -V";
65 my $set_key = $key->action_for_set_value(my $kstr = string($_));
66 my $set_value = $value->action_for_set_value($coll->get_member_at($kstr));
68 actions => [ $set_key, $set_value ],
69 $basic_deps->($key, $kstr),
74 sub selection_depends_on {
75 my ($self, $coll, $key, $value) = @_;
77 [ [ $coll => ($key->can_set_value ? INDICES_OF : (EXISTENCE_OF ,=> $key)) ],
83 # member_at Dict Key Value
85 # Dict must be set to a dict (later maybe also an array and Key -> Index)
97 # Dict.Key != Value ->
103 # Set value to Dict.Key
105 # Key does not exist ->
111 # Failure on (exists Dict.Key, Value)
115 # Set value to ProxySetToAdd value
117 # Dict disallows add ->
119 # Failure on (exists Dict.Key)
123 # Value must also be unbound, because seriously?
125 # Set [Key, Value] to each pair in turn
127 sub _resolution_space_for {
128 my ($self, $dict, $key, $value) = @_;
130 die "Fucked" unless $dict->does('DX::Role::StructuredValue');
134 if (my $cur_val = $dict->get_member_at($key)) {
137 [ CONTENTS_OF ,=> $dict, $key->string_value ],
138 [ CONTENTS_OF ,=> $value ],
141 if ($value->is_set) {
144 $cur_val->equals($value)
145 # Trivial resolution, D.K = V
148 veracity_depends_on => $deps,
155 geometry_depends_on => $deps,
162 geometry_depends_on => [
163 [ CONTENTS_OF ,=> $dict, $key->string_value ],
164 [ TYPE_OF ,=> $value ],
168 actions => [ $value->action_for_set_value($cur_val) ],
169 veracity_depends_on => $deps,
176 if ($dict->can_add_member) {
179 [ EXISTENCE_OF ,=> $dict, $key->string_value ],
180 [ TYPE_OF ,=> $value ],
183 if ($value->is_set) {
185 # If we get here, it means (currently) that we entered recheck
186 # due to the deletion of the key from the dict and should fail
187 # (or there's a bug in the compiler but let's hope not)
189 geometry_depends_on => $deps,
194 my @path = (@{$dict->value_path}, $key->string_value);
195 my $ab = DX::ActionBuilder::ProxySetToAdd->new(
196 target_path => \@path,
197 proxy_to => $dict->action_builder,
201 geometry_depends_on => $deps,
205 $value->action_for_set_value(
206 $value->but(action_builder => $ab),
209 # Veracity only depends on EXISTENCE_OF at this stage - if the
210 # $value is later set, recheck will lead us down a different path
211 # that will update those dependencies to include CONTENTS_OF
212 veracity_depends_on => $deps,
219 # Dict doesn't allow adding keys and key doesn't exist, so
220 # the contents of the value is completely irrelevant to the failure
222 geometry_depends_on => [
223 [ EXISTENCE_OF ,=> $dict, $key->string_value ],
230 die "Fucked" if $value->is_set; # +D -K +V ? seriously ?
232 # Laaater we may need to look at autovivifying an additional key/index
233 # ala ProxySetToAdd but I'm not 100% sure how that will make sense and
234 # premature generalisation is the root of all eval.
238 [ $dict->get_member_at($_) ],
239 ], map string($_), $dict->index_list;
242 geometry_depends_on => [
243 [ INDICES_OF ,=> $dict ],
244 [ TYPE_OF ,=> $key ],
245 [ TYPE_OF ,=> $value ],
249 action_prototypes => [
250 [ $key => 'set_value' ],
251 [ $value => 'set_value' ],
253 veracity_depends_on_builder => sub {
254 my ($this_key, $this_val) = @_;
256 [ CONTENTS_OF ,=> $dict, $this_key->string_value ],
257 [ CONTENTS_OF ,=> $key ],
258 [ CONTENTS_OF ,=> $value ],
261 implementation_candidates => \@cand,