1 /*
2  * Hunt - A redis client library for D programming language.
3  *
4  * Copyright (C) 2018-2019 HuntLabs
5  *
6  * Website: https://www.huntlabs.net/
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11  
12 module hunt.redis.BuilderFactory;
13 
14 import hunt.redis.Builder;
15 import hunt.redis.GeoCoordinate;
16 import hunt.redis.GeoRadiusResponse;
17 import hunt.redis.Module;
18 import hunt.redis.StreamEntry;
19 import hunt.redis.StreamEntryID;
20 import hunt.redis.StreamPendingEntry;
21 import hunt.redis.Tuple;
22 
23 import hunt.collection;
24 import hunt.Boolean;
25 import hunt.Byte;
26 import hunt.Double;
27 import hunt.Exceptions;
28 import hunt.Integer;
29 import hunt.logging.ConsoleLogger;
30 import hunt.Long;
31 import hunt.String;
32 import hunt.redis.util.SafeEncoder;
33 
34 import std.conv;
35 import std.concurrency : initOnce;
36 import std.range;
37 
38 
39 /**
40  * TODO: 
41  */
42 class BuilderFactory {
43 
44     static Builder!(Double) DOUBLE() {
45         __gshared Builder!(Double) inst;
46 
47         return initOnce!inst(new class Builder!(Double) {
48             override
49             Double build(Object data) {
50                 string str = STRING.build(data);
51                 if (str is null) return null;
52                 try {
53                     return Double.valueOf(str.to!double);
54                 } catch (NumberFormatException e) {
55                     if (str == "inf" || str == "+inf") return new Double(Double.POSITIVE_INFINITY);
56                     if (str == "-inf") return new Double(Double.NEGATIVE_INFINITY);
57                     throw e;
58                 }
59             }
60 
61             override
62             string toString() {
63                     return "double";
64             }
65         });
66     } 
67 
68     static Builder!(Boolean) BOOLEAN() {
69         __gshared Builder!(Boolean) inst;
70 
71         return initOnce!inst(new class Builder!(Boolean) {
72             override
73             Boolean build(Object data) {
74                 return Boolean.valueOf((cast(Long) data) == 1);
75             }
76 
77             override
78             string toString() {
79                     return "bool";
80             }
81         });
82     }
83 
84     static Builder!(const(ubyte)[]) BYTE_ARRAY() {
85         __gshared Builder!(const(ubyte)[]) inst;
86 
87         return initOnce!inst(new class Builder!(const(ubyte)[]) {
88             override
89             const(ubyte)[] build(Object data) {
90                 if(data is null)
91                     return null;
92 
93                 warning(typeid(data));
94                 Bytes bytesObj = cast(Bytes)data;
95                 return cast(const(ubyte)[]) bytesObj.value(); // deleted == 1
96             }
97 
98             override string toString() {
99                 return "const(ubyte)[]";
100             }
101         });
102     }
103 
104     static Builder!(Long) LONG() {
105         __gshared Builder!(Long) inst;
106 
107         return initOnce!inst(new class Builder!(Long) {
108             override
109             Long build(Object data) {
110                 return cast(Long) data;
111             }
112 
113             override
114             string toString() {
115                     return "long";
116             }
117         });
118     }
119     
120     static Builder!(string) STRING() {
121         __gshared Builder!(string) inst;
122 
123         return initOnce!inst(new class Builder!(string) {
124             override
125             string build(Object data) {
126                 if(data is null) {
127                     version(HUNT_DEBUG) warning("data is null");
128                     return null;
129                 }
130 
131                 Bytes bytesObject = cast(Bytes)data;
132                 if(bytesObject !is null) {
133                     byte[] bytes = bytesObject.value();
134                     version(HUNT_REDIS_DEBUG) tracef("value: %s, %(0x%02X, %)", cast(string)bytes, bytes);
135                     return cast(string)bytes;
136                 } else {
137                     version(HUNT_DEBUG) warningf("value: %s, type: %s", data.toString(), typeid(data));
138                     return data.toString();
139                 }
140             }
141 
142             override
143             string toString() {
144                 return "string";
145             }
146         });
147     }
148 
149     static Builder!(List!(string)) STRING_LIST() {
150         __gshared Builder!(List!(string)) inst;
151 
152         return initOnce!inst(new class Builder!(List!(string)) {
153             override List!(string) build(Object data) {
154                 if (data is null) {
155                     return null;
156                 }
157                 version(HUNT_REDIS_DEBUG) warning(typeid(data));
158                 List!(Object) l = cast(List!(Object)) data;
159                 ArrayList!(string) result = new ArrayList!(string)(l.size());
160                 foreach(Object barray ; l) {
161                     Bytes bytes = cast(Bytes)barray;
162                     if (bytes is null) {
163                         result.add(cast(string)null);
164                     } else {
165                         result.add(SafeEncoder.encode(cast(ubyte[])bytes.value()));
166                     }
167                 }
168                 return result;
169             }
170 
171             override string toString() {
172                 return "List!(string)";
173             }
174 
175         });
176     }
177 
178     static Builder!(Map!(string, string)) STRING_MAP() {
179         __gshared Builder!(Map!(string, string)) inst;
180 
181         return initOnce!inst(new class Builder!(Map!(string, string)) {
182             override
183             Map!(string, string) build(Object data) {
184                 // warning(typeid(data));
185                 List!(const(ubyte)[]) flatHash = cast(List!(const(ubyte)[])) data;
186                 Map!(string, string) hash = new HashMap!(string, string)(flatHash.size()/2, 1);
187                 InputRange!(const(ubyte)[]) iterator = flatHash.iterator();
188                 while (!iterator.empty()) {
189                     const(ubyte)[] first = iterator.front(); iterator.popFront();
190                     const(ubyte)[] second = iterator.front(); iterator.popFront();
191                     hash.put(SafeEncoder.encode(first), SafeEncoder.encode(second));
192                 }
193 
194                 return hash;
195             }
196 
197             override
198             string toString() {
199                 return "Map!(string, string)";
200             }
201         });
202     }
203 
204     static Builder!(Map!(string, string)) PUBSUB_NUMSUB_MAP() {
205         __gshared Builder!(Map!(string, string)) inst;
206         
207         return initOnce!inst(new class Builder!(Map!(string, string)) {
208 
209             override
210             Map!(string, string) build(Object data) {
211                 // warning(typeid(data));
212                 List!(Object) flatHash = cast(List!(Object)) data;
213                 Map!(string, string) hash = new HashMap!(string, string)(flatHash.size()/2, 1);
214 
215                 InputRange!(Object) iterator = flatHash.iterator();
216                 while (!iterator.empty()) {
217 
218                     Object firstObj = iterator.front;
219                     iterator.popFront();
220 
221                     Object secondObj = iterator.front;
222                     iterator.popFront();
223 
224                     String stringObj = cast(String)firstObj;
225                     Long longObj = cast(Long)secondObj;
226 
227                     hash.put(cast(string)SafeEncoder.encode(stringObj.value),
228                         to!string(longObj.value));
229                 }
230 
231                 return hash;
232             }
233 
234             override
235             string toString() {
236                 return "PUBSUB_NUMSUB_MAP!(string, string)";
237             }
238         });
239     }
240 
241     static Builder!(Set!(string)) STRING_SET() {
242         __gshared Builder!(Set!(string)) inst;
243         
244         return initOnce!inst(new class Builder!(Set!(string)) {
245 
246             override
247             Set!(string) build(Object data) {
248                 if (data is null) {
249                     return null;
250                 }
251                 warning(typeid(data));
252                 implementationMissing();
253 
254                 // List!(const(ubyte)[]) l = cast(List!(const(ubyte)[])) data;
255                 // Set!(string) result = new HashSet!(string)(l.size(), 1);
256                 // foreach(const(ubyte)[] barray ; l) {
257                 //     if (barray is null) {
258                 //         result.add(null);
259                 //     } else {
260                 //         result.add(SafeEncoder.encode(barray));
261                 //     }
262                 // }
263                 // return result;
264                 return null;
265             }
266 
267             override
268             string toString() {
269                 return "Set!(string)";
270             }
271         });
272     }
273     
274     static Builder!(List!(const(ubyte)[])) BYTE_ARRAY_LIST() {
275         __gshared Builder!(List!(const(ubyte)[])) inst;
276         return initOnce!inst(new class Builder!(List!(const(ubyte)[])) {
277             override
278             
279             List!(const(ubyte)[]) build(Object data) {
280                 if (data is null) {
281                     return null;
282                 }
283 
284                 List!Object lst = cast(List!Object)data;
285                 if(lst is null) {
286                     version(HUNT_DEBUG) warning("lst is null");
287                     return null;
288                 } else {
289                      ArrayList!(const(ubyte)[]) result = new ArrayList!(const(ubyte)[])(lst.size());
290                      foreach(Object obj; lst) {
291                          Bytes bytes = cast(Bytes)obj;
292                          if(bytes is null) {
293                              result.add(null);
294                          } else {
295                             result.add(cast(ubyte[])bytes.value);
296                          }
297                      }
298                     return result;
299                 }                
300             }
301 
302             override
303             string toString() {
304                 return "List!(const(ubyte)[])";
305             }
306         });
307     }
308 
309     static Builder!(Set!(const(ubyte)[])) BYTE_ARRAY_ZSET() {
310         __gshared Builder!(Set!(const(ubyte)[])) inst;
311         
312         return initOnce!inst(new class Builder!(Set!(const(ubyte)[])) {
313 
314             override
315             Set!(const(ubyte)[]) build(Object data) {
316                 if (data is null) {
317                     return null;
318                 }
319                 warning(typeid(data));
320                 implementationMissing();
321                 return null;
322 
323                 // List!(const(ubyte)[]) l = cast(List!(const(ubyte)[])) data;
324                 // Set!(const(ubyte)[]) result = new LinkedHashSet!(const(ubyte)[])(l);
325                 // foreach(const(ubyte)[] barray ; l) {
326                 //     if (barray is null) {
327                 //         result.add(null);
328                 //     } else {
329                 //         result.add(barray);
330                 //     }
331                 // }
332                 // return result;
333             }
334 
335             override
336             string toString() {
337                 return "ZSet!(const(ubyte)[])";
338             }
339         });
340     }
341 
342     static Builder!(Map!(const(ubyte)[], const(ubyte)[])) BYTE_ARRAY_MAP() {
343         __gshared Builder!(Map!(const(ubyte)[], const(ubyte)[])) inst;
344         
345         return initOnce!inst(new class Builder!(Map!(const(ubyte)[], const(ubyte)[])) {
346 
347             override
348             Map!(const(ubyte)[], const(ubyte)[]) build(Object data) {
349                 if (data is null) {
350                     return null;
351                 }
352                 warning(typeid(data));
353                 implementationMissing();
354                 return null;
355 
356                 // Map!(const(ubyte)[], const(ubyte)[]) build(Object data) {
357                 // List!(const(ubyte)[]) flatHash = (List!(const(ubyte)[])) data;
358                 // Map!(const(ubyte)[], const(ubyte)[]) hash = new RedisByteHashMap();
359                 // Iterator!(const(ubyte)[]) iterator = flatHash.iterator();
360                 // while (iterator.hasNext()) {
361                 //     hash.put(iterator.next(), iterator.next());
362                 // }
363 
364                 // return hash;
365             }
366 
367             override
368             string toString() {
369                 return "Map!(const(ubyte)[], const(ubyte)[])";
370             }
371         });
372     }
373 
374 
375     static Builder!(Set!(string)) STRING_ZSET() {
376         __gshared Builder!(Set!(string)) inst;
377         
378         return initOnce!inst(new class Builder!(Set!(string)) {
379 
380             override
381             Set!(string) build(Object data) {
382                 if (data is null) {
383                     return null;
384                 }
385                 warning(typeid(data));
386                 implementationMissing();
387                 return null;
388 
389                 // List!(const(ubyte)[]) l = (List!(const(ubyte)[])) data;
390                 // Set!(string) result = new LinkedHashSet!(string)(l.size(), 1);
391                 // foreach(const(ubyte)[] barray ; l) {
392                 //     if (barray is null) {
393                 //         result.add(null);
394                 //     } else {
395                 //         result.add(SafeEncoder.encode(barray));
396                 //     }
397                 // }
398                 // return result;
399             }
400 
401             override
402             string toString() {
403                 return "ZSet!(string)";
404             }
405         });
406     }
407 
408 
409     static Builder!(Set!(Tuple)) TUPLE_ZSET() {
410         __gshared Builder!(Set!(Tuple)) inst;
411         
412         return initOnce!inst(new class Builder!(Set!(Tuple)) {
413 
414             override
415             Set!(Tuple) build(Object data) {
416                 if (data is null) {
417                     return null;
418                 }
419                 warning(typeid(data));
420                 implementationMissing();
421                 return null;
422 
423     //          List!(const(ubyte)[]) l = (List!(const(ubyte)[])) data;
424     //          Set!(Tuple) result = new LinkedHashSet!(Tuple)(l.size()/2, 1);
425     //          Iterator!(const(ubyte)[]) iterator = l.iterator();
426     //          while (iterator.hasNext()) {
427     //              result.add(new Tuple(iterator.next(), DOUBLE.build(iterator.next())));
428     //          }
429     //          return result;
430             }
431 
432             override
433             string toString() {
434                 return "ZSet!(Tuple)";
435             }
436         });
437     }
438 
439     static Builder!(Object) EVAL_RESULT() {
440         __gshared Builder!(Object) inst;
441         
442         return initOnce!inst(new class Builder!(Object) {
443 
444             override
445             Object build(Object data) {
446                 if (data is null) {
447                     return null;
448                 }
449                 warning(typeid(data));
450                 implementationMissing();
451                 return null;
452 
453     //          if (result instanceof const(ubyte)[]) return SafeEncoder.encode((const(ubyte)[]) result);
454 
455     //          if (result instanceof List<?>) {
456     //              List<?> list = (List<?>) result;
457     //              List!(Object) listResult = new ArrayList!(Object)(list.size());
458     //              foreach(Object bin ; list) {
459     //                  listResult.add(evalResult(bin));
460     //              }
461 
462     //              return listResult;
463     //          }
464 
465     //          return result;
466             }
467 
468 
469             override
470             string toString() {
471                 return "Eval!(Object)";
472             }
473         });
474     }
475 
476 
477     static Builder!(Object) EVAL_BINARY_RESULT() {
478         __gshared Builder!(Object) inst;
479         
480         return initOnce!inst(new class Builder!(Object) {
481 
482             override
483             Object build(Object data) {
484                 if (data is null) {
485                     return null;
486                 }
487                 warning(typeid(data));
488                 implementationMissing();
489                 return null;
490 
491     //          if (result instanceof List<?>) {
492     //              List<?> list = (List<?>) result;
493     //              List!(Object) listResult = new ArrayList!(Object)(list.size());
494     //              foreach(Object bin ; list) {
495     //                  listResult.add(evalResult(bin));
496     //              }
497 
498     //              return listResult;
499     //          }
500 
501     //          return result;
502             }
503 
504 
505             override
506             string toString() {
507                 return "Eval!(Object)";
508             }
509         });
510     }
511 
512     static Builder!(List!(GeoCoordinate)) GEO_COORDINATE_LIST() {
513         __gshared Builder!(List!(GeoCoordinate)) inst;
514         return initOnce!inst(new class Builder!(List!(GeoCoordinate)) {
515             override List!(GeoCoordinate) build(Object data) {
516                 if (data is null) {
517                         return null;
518                 }
519                 return interpretGeoposResult(cast(List!(Object)) data);
520             }
521 
522             override string toString() {
523                 return "List!(GeoCoordinate)";
524             }
525         });
526     } 
527 
528     private static List!(GeoCoordinate) interpretGeoposResult(List!(Object) responses) {
529         List!(GeoCoordinate) responseCoordinate = new ArrayList!(GeoCoordinate)(responses.size());
530         foreach(Object response ; responses) {
531             if (response is null) {
532                     responseCoordinate.add(null);
533             } else {
534                     List!(Object) respList = cast(List!(Object)) response;
535                     Double first = DOUBLE.build(respList.get(0));
536                     Double second = DOUBLE.build(respList.get(1));
537                     assert(first !is null && second !is null);
538                     GeoCoordinate coord = new GeoCoordinate(first.value(), second.value());
539                     responseCoordinate.add(coord);
540             }
541         }
542         return responseCoordinate;
543     }
544 
545     static Builder!(List!(GeoRadiusResponse)) GEORADIUS_WITH_PARAMS_RESULT() {
546         __gshared Builder!(List!(GeoRadiusResponse)) inst;
547 
548         return initOnce!inst(new class Builder!(List!(GeoRadiusResponse)) {
549 
550             override List!(GeoRadiusResponse) build(Object data) {
551                 if (data is null) {
552                     return null;
553                 }
554 
555                 List!(Object) objectList = cast(List!(Object)) data;
556 
557                 List!(GeoRadiusResponse) responses = new ArrayList!(GeoRadiusResponse)(objectList.size());
558                 if (objectList.isEmpty()) {
559                     return responses;
560                 }
561 
562                 List!Object tmp = cast(List!(Object)) objectList.get(0);
563                 if (tmp !is null) {
564                     // list of members with additional informations
565                     GeoRadiusResponse resp;
566                     foreach(Object obj ; objectList) {
567                         List!(Object) informations = cast(List!(Object)) obj;
568 
569                         Object tempObj = informations.get(0);
570                         Bytes tempData = cast(Bytes)tempObj;
571                         if(tempData is null) {
572                             warning(typeid(tempObj));
573                         }
574                         resp = new GeoRadiusResponse(cast(string)tempData.value());
575 
576                         int size = informations.size();
577                         for (int idx = 1; idx < size; idx++) {
578                             Object infoObj = informations.get(idx);
579                             List!(Object) coord = cast(List!(Object))infoObj;
580                             if (coord !is null) {
581                                 // coordinate
582                                 resp.setCoordinate(new GeoCoordinate(DOUBLE.build(coord.get(0)).value(),
583                                         DOUBLE.build(coord.get(1)).value()));
584                             } else {
585                                 // distance
586                                 resp.setDistance(DOUBLE.build(infoObj).value());
587                             }
588                         }
589 
590                         responses.add(resp);
591                     }
592                 } else {
593                     // list of members
594                     foreach(Object obj ; objectList) {
595                         Bytes tempObj = cast(Bytes)obj;
596                         if(tempObj is null) {
597                             warning(typeid(obj));
598                         }
599                         responses.add(new GeoRadiusResponse(cast(string)tempObj.value()));
600                     }
601                 }
602 
603                 return responses;
604             }
605 
606             override string toString() {
607                 return "GeoRadiusWithParamsResult";
608             }
609         });            
610     }
611 
612     static Builder!(List!(Module)) MODULE_LIST() {
613         __gshared Builder!(List!(Module)) inst;
614 
615         return initOnce!inst(new class Builder!(List!(Module)) {
616 
617             override
618             List!(Module) build(Object data) {
619                 if (data is null) {
620                     return null;
621                 }
622 
623                 List!(List!(Object)) objectList = cast(List!(List!(Object))) data;
624 
625                 List!(Module) responses = new ArrayList!(Module)(objectList.size());
626                 if (objectList.isEmpty()) {
627                     return responses;
628                 }
629 
630                 foreach(List!(Object) moduleResp; objectList) {
631                     Object tempObj1 = moduleResp.get(1);
632                     Object tempObj3 = moduleResp.get(3);
633 
634 
635                     String strObj = cast(String)tempObj1;
636                     if(strObj is null) {
637                         warning(typeid(tempObj1));
638                         implementationMissing();
639                     }
640 
641                     Long longObj = cast(Long)tempObj3;
642                     if(longObj is null) {
643                         warning(typeid(tempObj3));
644                         implementationMissing();
645                     }
646 
647                     Module m = new Module(cast(string)SafeEncoder.encode(strObj.value), 
648                             longObj.intValue());
649                     responses.add(m);
650                 }
651 
652                 return responses;
653             }
654 
655             override string toString() {
656                 return "List!(Module)";
657             }
658         });
659     }
660 
661     static Builder!(List!(Long)) LONG_LIST() {
662         __gshared Builder!(List!(Long)) inst;
663 
664         return initOnce!inst(new class Builder!(List!(Long)) {
665             override List!(Long) build(Object data) {
666                 if (data is null) {
667                     return null;
668                 }
669 
670                 version(HUNT_REDIS_DEBUG) warning(typeid(data));
671                 return cast(List!(Long)) data;
672             }
673 
674             override string toString() {
675                 return "List!(Long)";
676             }
677 
678         });
679     }
680 
681     static Builder!(StreamEntryID) STREAM_ENTRY_ID() {
682         __gshared Builder!(StreamEntryID) inst;
683 
684         return initOnce!inst(new class Builder!(StreamEntryID) {
685             override StreamEntryID build(Object data) {
686                 if (data is null) {
687                     return null;
688                 }
689 
690                 String strObj = cast(String)data;
691                 if(strObj is null) {
692                     warning(typeid(data));
693                     implementationMissing();
694                 }
695 
696                 string id = cast(string)SafeEncoder.encode(strObj.value);
697                 return new StreamEntryID(id);
698             }
699 
700             override string toString() {
701                 return "StreamEntryID";
702             }
703 
704         });
705     }
706 
707     static Builder!(List!(StreamEntry)) STREAM_ENTRY_LIST() {
708 
709         __gshared Builder!(List!(StreamEntry)) inst;
710         
711         return initOnce!inst(new class Builder!(List!(StreamEntry)) {
712 
713             override List!(StreamEntry) build(Object data) {
714 
715                 List!(Object) objectList = cast(ArrayList!(Object)) data;
716                 if(objectList is null) {
717                     warningf("mismatched type: %s", typeid(data));
718                     return new ArrayList!(StreamEntry)();
719                 }
720 
721                 List!(StreamEntry) responses = new ArrayList!(StreamEntry)(objectList.size()/2);
722                 if (objectList.isEmpty()) {
723                     return responses;
724                 }
725 
726                 foreach(Object obj0; objectList) {
727                     ArrayList!(Object) res = cast(ArrayList!(Object))obj0;
728 
729                     assert(res !is null);
730                     version(HUNT_REDIS_DEBUG_MORE) {
731                         warning(typeid(res.get(0)));
732                     }
733 
734                     Object obj = res.get(0);
735                     Bytes bytes = cast(Bytes)obj;
736                     if(bytes is null) {
737                         warningf("wrong type: %s", typeid(obj));
738                         continue;
739                     }
740 
741                     string entryIdString = SafeEncoder.encode(cast(ubyte[])bytes.value());
742                     StreamEntryID entryID = new StreamEntryID(entryIdString);
743 
744                     obj = res.get(1);
745                     version(HUNT_REDIS_DEBUG_MORE) {
746                         warningf("%s", typeid(obj));
747                     }
748 
749                     List!(Object) hash = cast(List!(Object))obj;
750                     if(hash is null) {
751                         warningf("wrong type: %s", typeid(obj));
752                         continue;
753                     }
754 
755                     Map!(string, string) map = new HashMap!(string, string)(hash.size()/2);
756 
757                     for(int i=0; i<hash.size(); i=i+2) {
758                         bytes = cast(Bytes)hash[i];
759                         string first = SafeEncoder.encode(cast(ubyte[])bytes.value());
760 
761                         bytes = cast(Bytes)hash[i+1];
762                         string second = SafeEncoder.encode(cast(ubyte[])bytes.value());
763 
764                         version(HUNT_REDIS_DEBUG_MORE) {
765                             warningf("first: %s, second: %s", first, second);
766                         }
767                         map.put(first, second);
768                     }
769  
770                     responses.add(new StreamEntry(entryID, map));
771                 }
772 
773                 return responses;
774             }
775 
776             override string toString() {
777                 return "List!(StreamEntry)";
778             }
779 
780         });
781     }
782     
783     static Builder!(List!(StreamPendingEntry)) STREAM_PENDING_ENTRY_LIST() {
784         __gshared Builder!(List!(StreamPendingEntry)) inst;
785 
786         return initOnce!inst(new class Builder!(List!(StreamPendingEntry)) {
787             override List!(StreamPendingEntry) build(Object data) {
788 
789                 List!(Object) streamsEntries = cast(List!(Object))data;
790                 if(streamsEntries is null) {
791                     warningf("mismatched type: %s", typeid(data));
792                     return new ArrayList!(StreamPendingEntry)();
793                 }
794 
795                 List!(StreamPendingEntry) result = new ArrayList!(StreamPendingEntry)(streamsEntries.size());
796                 
797                 foreach(Object streamObj ; streamsEntries) {
798                     List!(Object) stream = cast(List!(Object))streamObj;
799 
800                     //
801                     Object obj = stream.get(0);
802                     Bytes bytes = cast(Bytes)obj;
803                     if(bytes is null) {
804                         warningf("wrong type: %s", typeid(obj));
805                         continue;
806                     }
807                     string id = SafeEncoder.encode(cast(ubyte[])bytes.value());
808 
809                     //
810                     obj = stream.get(1);
811                     bytes = cast(Bytes)obj;
812                     if(bytes is null) {
813                         warningf("wrong type: %s", typeid(obj));
814                         continue;
815                     }
816                     string consumerName = SafeEncoder.encode(cast(ubyte[])bytes.value());
817 
818 
819                     long idleTime = BuilderFactory.LONG.build(stream.get(2)).value();
820                     long deliveredTimes = BuilderFactory.LONG.build(stream.get(3)).value();
821 
822                     result.add(new StreamPendingEntry(new StreamEntryID(id), consumerName, idleTime, deliveredTimes));
823                 }
824 
825                 return result;
826             }
827 
828             override string toString() {
829                 return "List!(StreamPendingEntry)";
830             }
831 
832         });
833     }
834 
835     static Builder!(Object) OBJECT() {
836         __gshared Builder!(Object) inst;
837         return initOnce!inst(new class Builder!(Object) {
838             override Object build(Object data) {
839                 return data;
840             }
841 
842             override string toString() {
843                 return "Object";
844             }
845         });
846     }
847 
848      private this() {
849          throw new InstantiationError( "Must not instantiate this class" );
850      }
851 
852 }