@@ -139,6 +139,85 @@ defprotocol Inspect do
139
139
# Handle structs in Any
140
140
@ fallback_to_any true
141
141
142
+ @ impl true
143
+ defmacro __deriving__ ( module , options ) do
144
+ info = Macro . struct_info! ( module , __CALLER__ )
145
+ fields = Enum . sort ( Enum . map ( info , & & 1 . field ) -- [ :__exception__ , :__struct__ ] )
146
+
147
+ only = Keyword . get ( options , :only , fields )
148
+ except = Keyword . get ( options , :except , [ ] )
149
+ optional = Keyword . get ( options , :optional , [ ] )
150
+
151
+ :ok = validate_option ( :only , only , fields , module )
152
+ :ok = validate_option ( :except , except , fields , module )
153
+ :ok = validate_option ( :optional , optional , fields , module )
154
+
155
+ inspect_module =
156
+ if fields == Enum . sort ( only ) and except == [ ] do
157
+ Inspect.Map
158
+ else
159
+ Inspect.Any
160
+ end
161
+
162
+ filtered_fields =
163
+ fields
164
+ |> Enum . reject ( & ( & 1 in except ) )
165
+ |> Enum . filter ( & ( & 1 in only ) )
166
+
167
+ filtered_guard =
168
+ quote do
169
+ var! ( field ) in unquote ( filtered_fields )
170
+ end
171
+
172
+ field_guard =
173
+ if optional == [ ] do
174
+ filtered_guard
175
+ else
176
+ optional_map =
177
+ for field <- optional , into: % { } do
178
+ default = Enum . find ( info , % { } , & ( & 1 . field == field ) ) |> Map . get ( :default , nil )
179
+ { field , default }
180
+ end
181
+
182
+ quote do
183
+ unquote ( filtered_guard ) and
184
+ not case unquote ( Macro . escape ( optional_map ) ) do
185
+ % { ^ var! ( field ) => var! ( default ) } ->
186
+ var! ( default ) == Map . get ( var! ( struct ) , var! ( field ) )
187
+
188
+ % { } ->
189
+ false
190
+ end
191
+ end
192
+ end
193
+
194
+ quote do
195
+ defimpl Inspect , for: unquote ( module ) do
196
+ def inspect ( var! ( struct ) , var! ( opts ) ) do
197
+ var! ( infos ) =
198
+ for % { field: var! ( field ) } = var! ( info ) <- unquote ( module ) . __info__ ( :struct ) ,
199
+ unquote ( field_guard ) ,
200
+ do: var! ( info )
201
+
202
+ var! ( name ) = Macro . inspect_atom ( :literal , unquote ( module ) )
203
+ unquote ( inspect_module ) . inspect ( var! ( struct ) , var! ( name ) , var! ( infos ) , var! ( opts ) )
204
+ end
205
+ end
206
+ end
207
+ end
208
+
209
+ defp validate_option ( option , option_list , fields , module ) do
210
+ case option_list -- fields do
211
+ [ ] ->
212
+ :ok
213
+
214
+ unknown_fields ->
215
+ raise ArgumentError ,
216
+ "unknown fields #{ Kernel . inspect ( unknown_fields ) } in #{ Kernel . inspect ( option ) } " <>
217
+ "when deriving the Inspect protocol for #{ Kernel . inspect ( module ) } "
218
+ end
219
+ end
220
+
142
221
@ doc """
143
222
Converts `term` into an algebra document.
144
223
@@ -548,79 +627,6 @@ defimpl Inspect, for: Reference do
548
627
end
549
628
550
629
defimpl Inspect , for: Any do
551
- defmacro __deriving__ ( module , struct , options ) do
552
- fields = Enum . sort ( Map . keys ( struct ) -- [ :__exception__ , :__struct__ ] )
553
-
554
- only = Keyword . get ( options , :only , fields )
555
- except = Keyword . get ( options , :except , [ ] )
556
- optional = Keyword . get ( options , :optional , [ ] )
557
-
558
- :ok = validate_option ( :only , only , fields , module )
559
- :ok = validate_option ( :except , except , fields , module )
560
- :ok = validate_option ( :optional , optional , fields , module )
561
-
562
- inspect_module =
563
- if fields == Enum . sort ( only ) and except == [ ] do
564
- Inspect.Map
565
- else
566
- Inspect.Any
567
- end
568
-
569
- filtered_fields =
570
- fields
571
- |> Enum . reject ( & ( & 1 in except ) )
572
- |> Enum . filter ( & ( & 1 in only ) )
573
-
574
- filtered_guard =
575
- quote do
576
- var! ( field ) in unquote ( filtered_fields )
577
- end
578
-
579
- field_guard =
580
- if optional == [ ] do
581
- filtered_guard
582
- else
583
- optional_map = for field <- optional , into: % { } , do: { field , Map . fetch! ( struct , field ) }
584
-
585
- quote do
586
- unquote ( filtered_guard ) and
587
- not case unquote ( Macro . escape ( optional_map ) ) do
588
- % { ^ var! ( field ) => var! ( default ) } ->
589
- var! ( default ) == Map . get ( var! ( struct ) , var! ( field ) )
590
-
591
- % { } ->
592
- false
593
- end
594
- end
595
- end
596
-
597
- quote do
598
- defimpl Inspect , for: unquote ( module ) do
599
- def inspect ( var! ( struct ) , var! ( opts ) ) do
600
- var! ( infos ) =
601
- for % { field: var! ( field ) } = var! ( info ) <- unquote ( module ) . __info__ ( :struct ) ,
602
- unquote ( field_guard ) ,
603
- do: var! ( info )
604
-
605
- var! ( name ) = Macro . inspect_atom ( :literal , unquote ( module ) )
606
- unquote ( inspect_module ) . inspect ( var! ( struct ) , var! ( name ) , var! ( infos ) , var! ( opts ) )
607
- end
608
- end
609
- end
610
- end
611
-
612
- defp validate_option ( option , option_list , fields , module ) do
613
- case option_list -- fields do
614
- [ ] ->
615
- :ok
616
-
617
- unknown_fields ->
618
- raise ArgumentError ,
619
- "unknown fields #{ Kernel . inspect ( unknown_fields ) } in #{ Kernel . inspect ( option ) } " <>
620
- "when deriving the Inspect protocol for #{ Kernel . inspect ( module ) } "
621
- end
622
- end
623
-
624
630
def inspect ( % module { } = struct , opts ) do
625
631
try do
626
632
{ module . __struct__ ( ) , module . __info__ ( :struct ) }
0 commit comments