first cut of rspace/rstrat code with eq semi cut over
[scpubgit/DX.git] / lib / DX / Predicate / MemberAt.pm
CommitLineData
9d759b64 1package DX::Predicate::MemberAt;
2
7f385fb2 3use DX::Utils qw(:builders :dep_types);
dcf2adc7 4use DX::ActionBuilder::ProxySetToAdd;
c35c4f36 5use DX::ActionBuilder::Null;
9d759b64 6use DX::Class;
7
8with 'DX::Role::Predicate';
9
9d759b64 10sub _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');
ba6fa299 14 my $basic_deps = sub {
15 (depends_on => [
8c6c9551 16 [ EXISTENCE_OF ,=> $coll, ($_[1]||$_[0])->string_value ],
17 [ CONTENTS_OF ,=> $_[0] ],
18 [ CONTENTS_OF ,=> $coll, ($_[1]||$_[0])->string_value ],
19 [ CONTENTS_OF ,=> $value ],
ba6fa299 20 ])
21 };
22 if ($value->is_set) {
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);
27 return step(
28 actions => [],
29 $basic_deps->($key),
30 );
31 }
32 die "Bizarre: member_at called with non-fresh unset value"
33 unless $value->action_builder->isa('DX::ActionBuilder::UnsetValue');
34 if ($key->is_set) {
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);
38 return step(
39 actions => [ $set ],
40 $basic_deps->($key),
41 );
42 }
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,
48 );
49 my $set = $value->action_for_set_value(
50 $value->but(
51 action_builder => $ab
52 )
53 );
54 return step(
55 actions => [ $set ],
56 $basic_deps->($key),
57 );
58 }
59 return ();
60 }
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";
64 return map {
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));
67 step(
68 actions => [ $set_key, $set_value ],
69 $basic_deps->($key, $kstr),
70 );
71 } $coll->index_list;
9d759b64 72}
73
74sub selection_depends_on {
75 my ($self, $coll, $key, $value) = @_;
0498469a 76 die "NEEDS REDOING";
efad53c4 77 [ [ $coll => ($key->can_set_value ? INDICES_OF : (EXISTENCE_OF ,=> $key)) ],
9d759b64 78 $key,
79 $value,
80 ]
81}
82
7f385fb2 83# member_at Dict Key Value
84#
85# Dict must be set to a dict (later maybe also an array and Key -> Index)
86#
87# Key bound ->
88#
89# Key exists ->
90#
91# Value bound ->
92#
93# Dict.Key = Value ->
94#
95# Trivial resolution
96#
97# Dict.Key != Value ->
98#
99# Failure
100#
101# Value unbound ->
102#
103# Set value to Dict.Key
104#
105# Key does not exist ->
106#
107# Dict allows add ->
108#
109# Value bound ->
110#
111# Failure on (exists Dict.Key, Value)
112#
113# Value unbound ->
114#
115# Set value to ProxySetToAdd value
116#
117# Dict disallows add ->
118#
119# Failure on (exists Dict.Key)
120#
121# Key unbound ->
122#
123# Value must also be unbound, because seriously?
124#
125# Set [Key, Value] to each pair in turn
126
127sub _resolution_space_for {
128 my ($self, $dict, $key, $value) = @_;
129
130 die "Fucked" unless $dict->does('DX::Role::StructuredValue');
131
132 if ($key->is_set) {
133
134 if (my $cur_val = $dict->get_member_at($key)) {
135
136 my $deps = [
137 [ CONTENTS_OF ,=> $dict, $key->string_value ],
138 [ CONTENTS_OF ,=> $value ],
139 ];
140
141 if ($value->is_set) {
142
143 my @members = (
144 $cur_val->equals($value)
145 # Trivial resolution, D.K = V
146 ? res(
147 actions => [],
148 veracity_depends_on => $deps,
149 )
150 # Failure
151 : ()
152 );
153
154 return rspace(
155 geometry_depends_on => $deps,
156 members => \@members
157 );
158
159 }
160
161 return rspace(
162 geometry_depends_on => [
163 [ CONTENTS_OF ,=> $dict, $key->string_value ],
164 [ TYPE_OF ,=> $value ],
165 ],
166 members => [
167 res(
168 actions => [ $value->action_for_set_value($cur_val) ],
169 veracity_depends_on => $deps,
170 ),
171 ]
172 );
173
174 }
175
176 if ($dict->can_add_member) {
177
178 my $deps = [
179 [ EXISTENCE_OF ,=> $dict, $key->string_value ],
180 [ TYPE_OF ,=> $value ],
181 ];
182
183 if ($value->is_set) {
184
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)
188 return rspace(
189 geometry_depends_on => $deps,
190 members => [],
191 );
192 }
193
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,
198 );
199
200 return rspace(
201 geometry_depends_on => $deps,
202 members => [
203 res(
204 actions => [
205 $value->action_for_set_value(
206 $value->but(action_builder => $ab),
207 ),
208 ],
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,
213 ),
214 ],
215 );
216
217 }
218
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
221 return rspace(
222 geometry_depends_on => [
223 [ EXISTENCE_OF ,=> $dict, $key->string_value ],
224 ],
225 members => [],
226 );
227
228 }
229
230 die "Fucked" if $value->is_set; # +D -K +V ? seriously ?
231
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.
235
236 my @cand = map [
237 [ $_ ],
238 [ $dict->get_member_at($_) ],
239 ], map string($_), $dict->index_list;
240
241 return rspace(
242 geometry_depends_on => [
243 [ INDICES_OF ,=> $dict ],
244 [ TYPE_OF ,=> $key ],
245 [ TYPE_OF ,=> $value ],
246 ],
247 members => [
248 rstrat(
249 action_prototypes => [
250 [ $key => 'set_value' ],
251 [ $value => 'set_value' ],
252 ],
253 veracity_depends_on_builder => sub {
254 my ($this_key, $this_val) = @_;
255 return [
256 [ CONTENTS_OF ,=> $dict, $this_key->string_value ],
257 [ CONTENTS_OF ,=> $key ],
258 [ CONTENTS_OF ,=> $value ],
259 ];
260 },
261 implementation_candidates => \@cand,
262 ),
263 ],
264 );
265}
266
9d759b64 2671;