1 /**
2 License:
3     Boost Software License - Version 1.0 - August 17th, 2003
4 
5     Permission is hereby granted, free of charge, to any person or organization
6     obtaining a copy of the software and accompanying documentation covered by
7     this license (the "Software") to use, reproduce, display, distribute,
8     execute, and transmit the Software, and to prepare derivative works of the
9     Software, and to permit third-parties to whom the Software is furnished to
10     do so, all subject to the following:
11 
12     The copyright notices in the Software and this entire statement, including
13     the above license grant, this restriction and the following disclaimer,
14     must be included in all copies of the Software, in whole or in part, and
15     all derivative works of the Software, unless such copies or derivative
16     works are solely in the form of machine-executable object code generated by
17     a source language processor.
18 
19     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21     FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
22     SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
23     FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
24     ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25     DEALINGS IN THE SOFTWARE.
26 
27 Authors:
28     Alexandru Ermicioi
29 **/
30 module aermicioi.aedi_property_reader.convertor.placeholder;
31 
32 import aermicioi.aedi : Wrapper;
33 import aermicioi.aedi_property_reader.convertor.traits : n;
34 import aermicioi.aedi_property_reader.convertor.convertor : Convertor;
35 import std.experimental.allocator;
36 import std.conv;
37 import std.traits : Unqual;
38 import std.typecons : scoped;
39 
40 /**
41 Interface for objects that are aware of a type and can provide it.
42 **/
43 interface TypeAware {
44 
45     /**
46     Get the type that is stored in component.
47 
48     Returns:
49         TypeInfo stored in component.
50     **/
51     const(TypeInfo) type() const nothrow @property @nogc pure;
52 }
53 
54 /**
55 Interface for objects that are aware of original type from which containing value was created.
56 **/
57 interface OriginalTypeAware {
58 
59     /**
60     Get the type of original component from which contained one was created/converted.
61 
62     Returns:
63         TypeInfo of original component
64     **/
65     const(TypeInfo) original() const @property nothrow @nogc pure;
66 }
67 
68 /**
69 Interface for objects that are aware of convertor used to convert to destination type component stored in the implementor.
70 **/
71 interface ConvertorAware {
72 
73     /**
74     Get the convertor used to convert component stored in implementor of this interface.
75 
76     Returns:
77         Convertor used to convert component stored by implementor of this interface
78     **/
79     const(Convertor) convertor() const @property nothrow @nogc pure;
80 }
81 
82 /**
83 Interface for objects aware of allocator used in conversion of contained component.
84 **/
85 interface AllocatorAware {
86 
87     /**
88     Get allocator used in conversion of component stored in implementor.
89 
90     Returns:
91         Allocator used to convert component stored by implementor of this interface.
92     **/
93     inout(RCIAllocator) allocator() inout @property nothrow @nogc pure;
94 }
95 
96 /**
97 Interface for objects that can hold a value in.
98 **/
99 interface Placeholder(T) {
100 
101     @property {
102 
103         /**
104         Get stored value.
105 
106         Returns:
107             T value stored in component
108         **/
109         ref inout(T) value() nothrow @safe inout @nogc;
110 
111         /**
112         Store value in component.
113 
114         Params:
115             value = value that will be stored in.
116 
117         Returns:
118             Reference to stored value.
119         **/
120         ref T value(ref T value) nothrow @safe;
121 
122         /**
123         ditto
124         **/
125         final ref T value(T value) nothrow @safe {
126             return this.value(value);
127         }
128 
129     }
130 }
131 
132 /**
133 Interface for components that are able to destroy component contained in them using convertor, allocator, and original type converted from.
134 **/
135 interface Destroyable {
136 
137     /**
138     Destroy contained component using convertor and additional information available.
139 
140     Returns:
141         true if it was able to destroy, false otherwise.
142     **/
143     bool destruct() @safe nothrow;
144 }
145 
146 /**
147 Implementation of Placeholder!T.
148 **/
149 class PlaceholderImpl(T) : Placeholder!T, Wrapper!T, TypeAware, AllocatorAware {
150 
151     private {
152         T payload;
153         RCIAllocator allocator_;
154     }
155 
156     /**
157     Constructor for placeholder accepting stored value.
158 
159     Params:
160         value = value that will be stored in.
161     **/
162     this(ref T value, RCIAllocator allocator = theAllocator) nothrow {
163         this.payload = value;
164         this.allocator_ = allocator;
165     }
166 
167     this(ref const T value, RCIAllocator allocator = theAllocator) nothrow const {
168         this.payload = value;
169         this.allocator_ = allocator;
170     }
171 
172     this(ref immutable T value, immutable RCIAllocator allocator) nothrow immutable {
173         this.payload = value;
174         this.allocator_ = allocator;
175     }
176 
177     /**
178     ditto
179     **/
180     this(T value, RCIAllocator allocator = theAllocator) nothrow {
181         this(value, allocator);
182     }
183 
184     /**
185     ditto
186     **/
187     this(const T value, RCIAllocator allocator = theAllocator) nothrow const {
188         this(value, allocator);
189     }
190 
191     /**
192     ditto
193     **/
194     this(immutable T value, immutable RCIAllocator allocator) nothrow immutable {
195         this(value, allocator);
196     }
197 
198     @property {
199         /**
200         Get the type of component that is stored in.
201 
202         Returns:
203             TypeInfo of stored component.
204         **/
205         TypeInfo type() const nothrow @nogc pure {
206             return typeid(T);
207         }
208 
209         /**
210         Get allocator
211 
212         Returns:
213             RCIAllocator
214         **/
215         inout(RCIAllocator) allocator() @safe nothrow pure inout {
216             return this.allocator_;
217         }
218 
219         /**
220         Store value in component.
221 
222         Params:
223             value = value that will be stored in.
224 
225         Returns:
226             Reference to stored value.
227         **/
228         ref T value(ref T value) nothrow @safe {
229             static if (!is(T == const) && !is(T == immutable)) {
230                 import std.algorithm : move;
231 
232                 value.move(this.payload);
233             }
234 
235             return this.payload;
236         }
237 
238         /**
239         Get value
240 
241         Returns:
242             ref inout(T)
243         **/
244         ref inout(T) value() @safe nothrow inout @nogc {
245             return this.payload;
246         }
247     }
248 }
249 
250 /**
251 Implementation of Placeholder!T.
252 **/
253 class OriginalAwarePlaceholderImpl(T) : PlaceholderImpl!T, OriginalTypeAware {
254 
255     private {
256         const TypeInfo original_;
257     }
258 
259     /**
260     Constructor for placeholder accepting stored value.
261 
262     Params:
263         value = value that will be stored in.
264     **/
265     this(ref T value, const TypeInfo original, RCIAllocator allocator = theAllocator) nothrow
266     in (original !is null, "Placeholder expects original type to be provided, not null.") {
267         super(value, allocator);
268         this.original_ = original;
269     }
270 
271     this(ref const T value, const TypeInfo original, RCIAllocator allocator = theAllocator) nothrow const
272     in (original !is null, "Placeholder expects original type to be provided, not null.") {
273         super(value, allocator);
274         this.original_ = original;
275     }
276 
277     this(ref immutable T value, immutable TypeInfo original, immutable RCIAllocator allocator) nothrow immutable
278     in (original !is null, "Placeholder expects original type to be provided, not null.") {
279         super(value, allocator);
280         this.original_ = original_;
281     }
282 
283     /**
284     ditto
285     **/
286     this(T value, const TypeInfo original, RCIAllocator allocator = theAllocator) nothrow {
287         this(value, original, allocator);
288     }
289 
290     /**
291     ditto
292     **/
293     this(const T value, const TypeInfo original, RCIAllocator allocator = theAllocator) nothrow const {
294         this(value, original, allocator);
295     }
296 
297     /**
298     ditto
299     **/
300     this(immutable T value, immutable TypeInfo original, immutable RCIAllocator allocator) nothrow immutable {
301         this(value, original, allocator);
302     }
303 
304     @property {
305 
306         /**
307         Get the type of original component from which contained one was created/converted.
308 
309         Returns:
310             TypeInfo of original component
311         **/
312         const(TypeInfo) original() const nothrow @nogc pure {
313             return this.original_;
314         }
315     }
316 }
317 
318 /**
319 Implementation of Placeholder!T.
320 **/
321 class ConvertorAndOriginalAwarePlaceholderImpl(T) : OriginalAwarePlaceholderImpl!T, ConvertorAware {
322 
323     private {
324         const Convertor convertor_;
325     }
326 
327     /**
328     Constructor for placeholder accepting stored value.
329 
330     Params:
331         value = value that will be stored in.
332     **/
333     this(ref T value, const TypeInfo original, const Convertor convertor, RCIAllocator allocator = theAllocator) nothrow
334     in (convertor !is null, "Placeholder expects convertor of component to be provided, not null.") {
335         super(value, original, allocator);
336         this.convertor_ = convertor;
337     }
338 
339     this(ref const T value, const TypeInfo original, const Convertor convertor, RCIAllocator allocator = theAllocator) nothrow const
340     in (convertor !is null, "Placeholder expects convertor of component to be provided, not null.") {
341         super(value, original, allocator);
342         this.convertor_ = convertor;
343     }
344 
345     this(ref immutable T value, immutable TypeInfo original, immutable Convertor convertor, immutable RCIAllocator allocator) nothrow immutable
346     in (convertor !is null, "Placeholder expects convertor of component to be provided, not null.") {
347         super(value, original, allocator);
348         this.convertor_ = convertor_;
349     }
350 
351     /**
352     ditto
353     **/
354     this(T value, const TypeInfo original, const Convertor convertor, RCIAllocator allocator = theAllocator) nothrow {
355         this(value, original, convertor, allocator);
356     }
357 
358     /**
359     ditto
360     **/
361     this(const T value, const TypeInfo original, const Convertor convertor, RCIAllocator allocator = theAllocator) nothrow const {
362         this(value, original, convertor, allocator);
363     }
364 
365     /**
366     ditto
367     **/
368     this(immutable T value, immutable TypeInfo original, immutable Convertor convertor, immutable RCIAllocator allocator) nothrow immutable {
369         this(value, original, convertor, allocator);
370     }
371 
372     @property {
373 
374         /**
375         Get the type of original component from which contained one was created/converted.
376 
377         Returns:
378             TypeInfo of original component
379         **/
380         const(Convertor) convertor() const nothrow @nogc pure {
381             return this.convertor_;
382         }
383     }
384 }
385 
386 /**
387 Wrap up a value in a placeholding object.
388 
389 Params:
390     value = value that will be wrapped in placeholding object
391     from = original type from which value was converted
392     convertor = convertor used in converting value out of from
393     allocator = allocator used to allocate placeholding object
394 
395 Returns:
396     Placeholder!T with value as content.
397 **/
398 ConvertorAndOriginalAwarePlaceholderImpl!T pack(T, From)(auto ref T value, const From from, const Convertor convertor, RCIAllocator allocator = theAllocator) @trusted {
399     return allocator.make!(ConvertorAndOriginalAwarePlaceholderImpl!T)(value, from.identify, convertor, allocator);
400 }
401 
402 /**
403 ditto
404 **/
405 OriginalAwarePlaceholderImpl!T pack(T, From)(auto ref T value, const From from, RCIAllocator allocator = theAllocator) @trusted {
406     return allocator.make!(OriginalAwarePlaceholderImpl!T)(value, from.identify, allocator);
407 }
408 
409 /**
410 ditto
411 **/
412 PlaceholderImpl!T pack(T)(auto ref T value, RCIAllocator allocator = theAllocator) @trusted {
413     return allocator.make!(PlaceholderImpl!T)(value, allocator);
414 }
415 
416 /**
417 ditto
418 **/
419 auto packWithStorageClass(alias StorageType, T)(auto ref T value, const TypeInfo from, const Convertor convertor, RCIAllocator allocator = theAllocator) @trusted {
420 
421     return pack!(StorageType!T)(cast(StorageType!T) value, from, convertor, allocator);
422 }
423 
424 /**
425 ditto
426 **/
427 auto packWithStorageClass(alias StorageType, T)(auto ref T value, const TypeInfo from, RCIAllocator allocator = theAllocator) @trusted {
428 
429     return pack!(StorageType!T)(cast(StorageType!T) value, from, allocator);
430 }
431 
432 /**
433 ditto
434 **/
435 auto packWithStorageClass(alias StorageType, T)(auto ref T value, RCIAllocator allocator = theAllocator) @trusted {
436 
437     return pack!(StorageType!T)(cast(StorageType!T) value, allocator);
438 }
439 
440 /**
441 Wrap up a value in a placeholding object stored on stack instead of allocator.
442 
443 Params:
444     value = value that will be wrapped in placeholding object
445 
446 Returns:
447     scoped Placeholder!T with value as content.
448 **/
449 auto stored(T)(auto ref T value, const TypeInfo from, const Convertor convertor) {
450     import std.typecons : scoped;
451 
452     return scoped!(ConvertorAndOriginalAwarePlaceholderImpl!T)(value, from, convertor, RCIAllocator());
453 }
454 
455 /**
456 ditto
457 **/
458 auto stored(T)(auto ref T value, const TypeInfo from) {
459     import std.typecons : scoped;
460 
461     return scoped!(OriginalAwarePlaceholderImpl!T)(value, from, RCIAllocator());
462 }
463 
464 /**
465 ditto
466 **/
467 auto stored(T)(auto ref T value) {
468     import std.typecons : scoped;
469 
470     return scoped!(PlaceholderImpl!T)(value, RCIAllocator());
471 }
472 
473 /**
474 Downcast object to type T, or unwrap it from Placeholder!T.
475 
476 Downcast object to type T, or unwrap it from Placeholder!T.
477 If T is rooted in Object, downcast will be performed, otherwise
478 it is assumed that T is stored in Placeholder!T object, and therefore
479 object is downcast to Placeholder!T and then returned.
480 
481 Params:
482     object = object from which to unwrap value of type T
483 Returns:
484     T if it is rooted in Object, or Placeholder!T if it is not.
485 **/
486 auto ref T unwrap(T)(inout(Object) object) @trusted nothrow {
487     static if (is(T : Object) || is(T : const Object) || is(T : immutable Object) || is(T : inout(Object))) {
488         {
489             auto downcasted = cast(T) object;
490 
491             if (downcasted !is null) {
492                 return downcasted;
493             }
494         }
495     }
496 
497     {
498         auto downcasted = cast(Placeholder!T) object;
499 
500         if (downcasted !is null) {
501             return downcasted.value;
502         }
503     }
504 
505     assert(false, text(object.identify, " does not implement", typeid(T), ". inout(Object) cannot be extracted."));
506 }
507 
508 /**
509 ditto
510 **/
511 auto ref T unwrap(T : Placeholder!Z, Z)(T placeholder) @trusted nothrow {
512     return placeholder;
513 }
514 
515 auto ref T unwrap(T : typeof(null))(inout(Object) object) {
516     if (object is null) {
517         return null;
518     }
519 
520     Placeholder!T placeholder = cast(Placeholder!T) object;
521 
522     if (placeholder !is null) {
523         return placeholder.value;
524     }
525 
526     assert(false, text(object.identify, " is not of ", typeid(null)));
527 }
528 
529 /**
530 Downcast object to type T, or destructively unwrap it from Placeholder!T.
531 
532 Downcast object to type T, or destructively unwrap it from Placeholder!T.
533 If T is rooted in Object, downcast will be performed, otherwise
534 it is assumed that T is stored in Placeholder!T object, and therefore
535 object is downcast to Placeholder!T it's value extracted and placeholder itself is
536 disposed of.
537 
538 Params:
539     object = object from which to unwrap value of type T
540 Returns:
541     T if it is rooted in Object, or Placeholder!T if it is not.
542 **/
543 T unpack(T)(Object object, RCIAllocator allocator = theAllocator) @trusted {
544     import aermicioi.aedi_property_reader.convertor.traits : n;
545     static if (is(T : Object) || is(T : const Object) || is(T : immutable Object) || is(T : inout(Object))) {
546         {
547             auto downcasted = cast(T) object;
548 
549             if (downcasted !is null) {
550                 return downcasted;
551             }
552         }
553     }
554 
555     {
556         auto downcasted = cast(Placeholder!T) object;
557 
558         if (downcasted !is null) {
559             return downcasted.unpack;
560         }
561     }
562 
563     assert(false, text(object.identify, " does not implement", typeid(T), ". inout(Object) cannot be extracted."));
564 }
565 
566 T unpack(T : typeof(null))(Object object, RCIAllocator allocator = theAllocator) @trusted {
567     import aermicioi.aedi_property_reader.convertor.traits : n;
568     if (object is null) {
569         return null;
570     }
571 
572     {
573         auto downcasted = cast(Placeholder!T) object;
574 
575         if (downcasted !is null) {
576             return downcasted.unpack;
577         }
578     }
579 
580     assert(false, text(object.identify, " does not implement", typeid(T), ". inout(Object) cannot be extracted."));
581 }
582 
583 /**
584 ditto
585 **/
586 Z unpack(T : Placeholder!Z, Z)(T placeholder, RCIAllocator allocator = theAllocator) @trusted nothrow {
587     try {
588         scope(exit) allocator.dispose(placeholder);
589 
590         return placeholder.value;
591     } catch (Exception e) {
592         throw new Error("Failed to dispose placeholder for a value", e);
593     }
594 }
595 
596 /**
597 Identify the type of object.
598 
599 Identify the type of object.
600 The object will be downcasted to TypeAware first, in order
601 to test if object is holding information about some type.
602 If so, the type from TypeAware object will be returned,
603 otherwise classinfo of object itself.
604 
605 Params:
606     object = component to be identified
607 Returns:
608     TypeInfo of stored type of object implements TypeAware, or classinfo of object itself.
609 **/
610 const(TypeInfo) identify(T)(T object) @trusted nothrow @nogc
611     if (is(T : Object) || is(T : const Object) || is(T : immutable Object)) {
612 
613     if (object is null) {
614         return typeid(null);
615     }
616 
617     TypeAware p = cast(TypeAware) object;
618 
619     if (p !is null) {
620         return p.type;
621     }
622 
623     return object.classinfo;
624 }
625 
626 /**
627 ditto
628 **/
629 const(TypeInfo) identify(T)(auto ref T component) nothrow @nogc @safe
630     if (!(is(T : Object) || is(T : const Object) || is(T : immutable Object))) {
631     import std.stdio;
632 
633     return typeid(component);
634 }
635 
636 /**
637 ditto
638 **/
639 T identify(T : TypeInfo)(auto ref T typeinfo) nothrow @nogc @safe {
640     import std.stdio;
641 
642     return typeinfo;
643 }
644 
645 /**
646 ditto
647 **/
648 T identify(T : const TypeInfo)(auto ref T typeinfo) nothrow @nogc @safe {
649     import std.stdio;
650 
651     return typeinfo;
652 }
653 
654 /**
655 ditto
656 **/
657 T identify(T : immutable TypeInfo)(auto ref T typeinfo) nothrow @nogc @safe {
658     import std.stdio;
659 
660     return typeinfo;
661 }
662 
663 /**
664 Identify the original type of converted component.
665 
666 Identify the original type of converted component.
667 The object will be downcasted to OriginalTypeAware
668 interface and if it succeeded original type will be
669 returned. For non-object components typeid(void)
670 will be returned as no OriginalTypeAware they could implement.
671 
672 Params:
673     object = converted component for which original type would need to be identified.
674 Returns:
675     TypeInfo of original type from which current one was converted.
676 **/
677 const(TypeInfo) original(T)(T object) @trusted nothrow @nogc pure
678     if (is(T : Object) || is(T : const Object) || is(T : immutable Object)) {
679 
680     if (object is null) {
681         return typeid(void);
682     }
683 
684     OriginalTypeAware p = cast(OriginalTypeAware) object;
685 
686     if (p !is null) {
687         return p.original;
688     }
689 
690     return object.classinfo;
691 }
692 
693 /**
694 ditto
695 **/
696 TypeInfo original(T)(auto ref T component) nothrow @nogc @safe
697     if (!(is(T : Object) || is(T : const Object) || is(T : immutable Object))) {
698     import std.stdio;
699 
700     return typeid(void);
701 }
702 
703 /**
704 ditto
705 **/
706 TypeInfo original(T : TypeInfo)(auto ref T typeinfo) nothrow @nogc @safe {
707     import std.stdio;
708 
709     return typeid(void);
710 }
711 
712 /**
713 ditto
714 **/
715 const(TypeInfo) original(T : const TypeInfo)(auto ref T typeinfo) nothrow @nogc @safe {
716     import std.stdio;
717 
718     return typeid(void);
719 }
720 
721 /**
722 ditto
723 **/
724 immutable(TypeInfo) original(T : immutable TypeInfo)(auto ref T typeinfo) nothrow @nogc @safe {
725     import std.stdio;
726 
727     return typeid(void);
728 }
729 
730 /**
731 ditto
732 **/
733 const(TypeInfo) original(T)(T object, const TypeInfo from) @trusted nothrow @nogc pure {
734     auto result = object.original;
735 
736     if (result is typeid(void)) {
737         return from;
738     }
739 
740     return result;
741 }
742 
743 /**
744 Identify the convertor used to convert component.
745 
746 Identify the convertor used to convert component.
747 The object will be downcasted to ConvertorAware
748 interface and if it succeeded convertor used to
749 convert component will be returned. For non-object
750 components null will be returned as no convertor
751 can be extracted from them.
752 
753 Params:
754     object = converted component for which used convertor would need to be identified.
755 Returns:
756     Convertor used to convert to contained component.
757 **/
758 const(Convertor) convertorOf(T)(T object) @trusted nothrow @nogc pure
759     if (is(T : Object) || is(T : const Object) || is(T : immutable Object)) {
760 
761     if (object !is null) {
762         ConvertorAware p = cast(ConvertorAware) object;
763 
764         if (p !is null) {
765             return p.convertor;
766         }
767     }
768 
769     return null;
770 }
771 
772 /**
773 ditto
774 **/
775 Convertor convertorOf(T)(auto ref T component) nothrow @nogc @safe
776     if (!(is(T : Object) || is(T : const Object) || is(T : immutable Object))) {
777     import std.stdio;
778 
779     return null;
780 }
781 
782 /**
783 ditto
784 **/
785 Convertor convertorOf(T : Convertor)(auto ref T convertor) nothrow @nogc @safe {
786     import std.stdio;
787 
788     return convertor;
789 }
790 
791 /**
792 ditto
793 **/
794 const(Convertor) convertorOf(T : const Convertor)(auto ref T convertor) nothrow @nogc @safe {
795     import std.stdio;
796 
797     return convertor;
798 }
799 
800 /**
801 ditto
802 **/
803 immutable(Convertor) convertorOf(T : immutable Convertor)(auto ref T convertor) nothrow @nogc @safe {
804     import std.stdio;
805 
806     return convertor;
807 }
808 
809 /**
810 Identify the allocator used to convert component.
811 
812 Identify the allocator used to convert component.
813 The object will be downcasted to AllocatorAware
814 interface and if it succeeded convertor used to
815 convert component will be returned. For non-object
816 components empty allocator will be returned as no convertor
817 can be extracted from them.
818 
819 Params:
820     object = converted component for which used allocator would need to be identified.
821 Returns:
822     RCIAllocator used in conversion process.
823 **/
824 RCIAllocator allocatorOf(T)(T object) @trusted nothrow @nogc pure
825     if (is(T : Object) || is(T : const Object) || is(T : immutable Object)) {
826 
827     if (object !is null) {
828         AllocatorAware p = cast(AllocatorAware) object;
829 
830         if (p !is null) {
831             return p.allocator;
832         }
833     }
834 
835     return RCIAllocator(null);
836 }
837 
838 /**
839 ditto
840 **/
841 RCIAllocator allocatorOf(T)(auto ref T component) nothrow @nogc @safe
842     if (!(is(T : Object) || is(T : const Object) || is(T : immutable Object))) {
843     import std.stdio;
844 
845     return RCIAllocator(null);
846 }
847 
848 /**
849 ditto
850 **/
851 RCIAllocator allocatorOf(T : RCIAllocator)(auto ref T allocator) nothrow @nogc @safe {
852     import std.stdio;
853 
854     return allocator;
855 }
856 
857 /**
858 ditto
859 **/
860 const(RCIAllocator) allocatorOf(T : const Convertor)(auto ref T allocator) nothrow @nogc @safe {
861     import std.stdio;
862 
863     return allocator;
864 }
865 
866 /**
867 ditto
868 **/
869 immutable(RCIAllocator) allocatorOf(T : immutable Convertor)(auto ref T allocator) nothrow @nogc @safe {
870     import std.stdio;
871 
872     return allocator;
873 }
874 
875 /**
876 ditto
877 **/
878 RCIAllocator allocatorOf(T)(T object, RCIAllocator allocator) @trusted nothrow @nogc pure {
879     auto result = object.allocatorOf;
880 
881     if (result.isNull) {
882         return allocator;
883     }
884 
885     return result;
886 }