1 module mir.bloomberg.blpapi;
2 
3 import mir.timestamp: Timestamp;
4 import mir.algebraic: Nullable;
5 
6 alias BloombergStreamWriter = extern(C) int function(const(char)* data, int length, void* stream);
7 
8 deprecated("Please use a local alias or IonAlgebraic instead .")
9 alias BloombergAlgebraic = Nullable!(
10     bool,
11     long,
12     double,
13     string,
14     Timestamp);
15 
16 enum DataType
17 {
18     null_,
19     /// Bool
20     bool_          = 1,
21     /// Char
22     char_          = 2,
23     /// Unsigned 8 bit value
24     byte_          = 3,
25     /// 32 bit Integer
26     int32          = 4,
27     /// 64 bit Integer
28     int64          = 5,
29     /// 32 bit Floating point - IEEE
30     float32        = 6,
31     /// 64 bit Floating point - IEEE
32     float64        = 7,
33     /// ASCIIZ string
34     string         = 8,
35     /// Opaque binary data
36     bytearray      = 9,
37     /// Date
38     date           = 10,
39     /// Timestamp
40     time           = 11,
41     decimal        = 12,
42     /// Date and time
43     datetime       = 13,
44     /// An opaque enumeration
45     enumeration    = 14,
46     /// Sequence type
47     sequence       = 15,
48     /// Choice type
49     choice         = 16,
50     /// Used for some internal messages
51     correlation_id = 17,
52 }
53 
54 enum DatetimeParts : ubyte
55 {
56     year         = 0x1,
57     month        = 0x2,
58     day          = 0x4,
59     offset       = 0x8,
60     hours        = 0x10,
61     minutes      = 0x20,
62     seconds      = 0x40,
63     fracseconds  = 0x80,
64 }
65 
66 struct ErrorInfo
67 {
68     int   exceptionClass;
69     char[256]  _description = '\0';
70 
71     inout(char)[] description() @trusted pure nothrow @nogc inout return scope
72     {
73         import core.stdc.string: strlen;
74         return _description[0 .. (&this._description[0]).strlen];
75     }
76 }
77 
78 enum DatePart = DatetimeParts.year | DatetimeParts.month | DatetimeParts.day;
79 
80 enum TimePart = DatetimeParts.hours | DatetimeParts.minutes | DatetimeParts.seconds;
81 
82 enum TimeFracsecondsPart = TimePart | DatetimeParts.fracseconds;
83 
84 alias Bool = int;
85 
86 struct Name;
87 
88 struct Element;
89 
90 struct Datetime
91 {
92     /// bitmask of date/time parts that are set
93     ubyte  parts;
94     ubyte  hours;
95     ubyte  minutes;
96     ubyte  seconds;
97     ushort milliseconds;
98     ubyte  month;
99     ubyte  day;
100     ushort year;
101     /// (signed) minutes ahead of UTC
102     short  offset;
103 
104     ///
105     this(
106         ubyte  parts,
107         ubyte  hours,
108         ubyte  minutes,
109         ubyte  seconds,
110         ushort milliseconds,
111         ubyte  month,
112         ubyte  day,
113         ushort year,
114         short  offset,
115     ) {
116         this.parts = parts;
117         this.hours = hours;
118         this.minutes = minutes;
119         this.seconds = seconds;
120         this.milliseconds = milliseconds;
121         this.month = month;
122         this.day = day;
123         this.year = year;
124         this.offset = offset;
125     }
126 
127     /// Construct from $(MREF mir,timestamp).
128     this(Timestamp timestamp) @safe pure nothrow @nogc
129     {
130         this = HighPrecisionDatetime(timestamp).datetime;
131     }
132 
133     /// Converts `Datetime` to $(MREF mir,timestamp).
134     Timestamp asTimestamp() @safe pure nothrow @nogc const @property
135     {
136         return HighPrecisionDatetime(this).asTimestamp;
137     }
138 
139     alias opCast(T : Timestamp) = asTimestamp;
140 
141     bool isOnlyTime() @safe pure nothrow @nogc const @property
142     {
143         return (parts & DatetimeParts.year) == 0;
144     }
145 }
146 
147 struct HighPrecisionDatetime {
148     Datetime datetime;
149 
150     alias datetime this;
151 
152     /++
153     picosecond offset into current
154     *millisecond* i.e. the picosecond offset
155     into the current full second is
156     '1000000000LL * milliseconds + picoseconds'
157     +/
158     uint picoseconds;
159 
160     this(Datetime datetime, uint picoseconds = 0) @safe pure nothrow @nogc
161     {
162         this.datetime = datetime;
163         this.picoseconds = picoseconds;
164     }
165 
166     /// Construct from $(MREF mir,timestamp).
167     this(Timestamp timestamp) @safe pure nothrow @nogc
168     {
169         if (timestamp.offset)
170         {
171             parts |= DatetimeParts.offset;
172             offset = timestamp.offset;
173             timestamp.addMinutes(timestamp.offset);
174         }
175         final switch (timestamp.precision)
176         {
177             case Timestamp.Precision.fraction: {
178                 parts |= DatetimeParts.fracseconds;
179                 auto exp = timestamp.fractionExponent;
180                 auto coeff = timestamp.fractionCoefficient;
181                 while(exp > -12)
182                 {
183                     exp--;
184                     coeff *= 10;
185                 }
186                 picoseconds = cast(uint) (coeff % 1000000000u);
187                 milliseconds = cast(ushort) (coeff / 1000000000u);
188                 goto case;
189             }
190             case Timestamp.Precision.second:
191                 parts |= DatetimeParts.seconds;
192                 seconds = timestamp.second;
193                 goto case;
194             case Timestamp.Precision.minute:
195                 parts |= DatetimeParts.minutes;
196                 parts |= DatetimeParts.hours;
197                 minutes = timestamp.minute;
198                 hours = timestamp.hour;
199                 if (timestamp.day == 0) //
200                     return;
201                 goto case;
202             case Timestamp.Precision.day:
203                 parts |= DatetimeParts.day;
204                 day = timestamp.day;
205                 goto case;
206             case Timestamp.Precision.month:
207                 parts |= DatetimeParts.month;
208                 month = timestamp.month;
209                 goto case;
210             case Timestamp.Precision.year:
211                 parts |= DatetimeParts.year;
212                 year = timestamp.year;
213         }
214     }
215 
216     /// Converts `Datetime` to $(MREF mir,timestamp).
217     Timestamp asTimestamp() @safe pure nothrow @nogc const @property
218     {
219         Timestamp ret;
220         if (parts & DatetimeParts.year)
221         {
222             ret.year = year;
223             ret.precision = Timestamp.Precision.year;
224         }
225         if (parts & DatetimeParts.month)
226         {
227             ret.month = month;
228             ret.precision = Timestamp.Precision.month;
229         }
230         if (parts & DatetimeParts.day)
231         {
232             ret.day = day;
233             ret.precision = Timestamp.Precision.day;
234         }
235         if (parts & DatetimeParts.hours)
236         {
237             ret.hour = hours;
238             ret.precision = Timestamp.Precision.minute;
239         }
240         if (parts & DatetimeParts.minutes)
241         {
242             ret.minute = minutes;
243             ret.precision = Timestamp.Precision.minute;
244         }
245         if (parts & DatetimeParts.seconds)
246         {
247             ret.second = seconds;
248             ret.precision = Timestamp.Precision.second;
249         }
250         if (parts & DatetimeParts.fracseconds)
251         {
252             ret.fractionExponent = -12;
253             ret.fractionCoefficient = 1000000000UL * milliseconds + picoseconds;
254             ret.precision = Timestamp.Precision.fraction;
255         }
256         if (parts & DatetimeParts.offset && offset && ret.precision >= Timestamp.Precision.minute)
257         {
258             ret.addMinutes(cast(short)-int(ret.offset));
259         }
260         return ret;
261     }
262 
263     alias opCast(T : Timestamp) = asTimestamp;
264 }
265 
266 unittest
267 {
268     auto tests = [
269         HighPrecisionDatetime(Datetime(7, 0, 0, 0, 0, 11, 1, 2021, 0), 0),
270         HighPrecisionDatetime(Datetime(7, 0, 0, 0, 0, 10, 29, 2021, 0), 0),
271         HighPrecisionDatetime(Datetime(7, 0, 0, 0, 0, 11, 2, 2020, 0), 0),
272         HighPrecisionDatetime(Datetime(7, 0, 0, 0, 0, 6, 2, 2021, 0), 0),
273         HighPrecisionDatetime(Datetime(7, 0, 0, 0, 0, 10, 29, 2021, 0), 0),
274         HighPrecisionDatetime(Datetime(7, 0, 0, 0, 0, 10, 29, 2021, 0), 0),
275         HighPrecisionDatetime(Datetime(7, 0, 0, 0, 0, 10, 29, 2021, 0), 0),
276         HighPrecisionDatetime(Datetime(112, 7, 0, 0, 0, 1, 1, 1, 0), 0),
277         HighPrecisionDatetime(Datetime(112, 6, 59, 59, 0, 1, 1, 1, 0), 0),
278         HighPrecisionDatetime(Datetime(112, 16, 59, 59, 0, 1, 1, 1, 0), 0),
279         HighPrecisionDatetime(Datetime(7, 0, 0, 0, 0, 10, 29, 2021, 0), 0),
280         HighPrecisionDatetime(Datetime(7, 0, 0, 0, 0, 11, 1, 2021, 0), 0),
281         HighPrecisionDatetime(Datetime(7, 0, 0, 0, 0, 10, 29, 2021, 0), 0),
282         HighPrecisionDatetime(Datetime(7, 0, 0, 0, 0, 3, 15, 2021, 0), 0),
283         HighPrecisionDatetime(Datetime(7, 0, 0, 0, 0, 11, 2, 2020, 0), 0),
284         HighPrecisionDatetime(Datetime(7, 0, 0, 0, 0, 3, 23, 2020, 0), 0),
285         HighPrecisionDatetime(Datetime(7, 0, 0, 0, 0, 3, 23, 2020, 0), 0),
286         HighPrecisionDatetime(Datetime(7, 0, 0, 0, 0, 10, 29, 2021, 0), 0),
287         HighPrecisionDatetime(Datetime(7, 0, 0, 0, 0, 10, 29, 2021, 0), 0),
288         HighPrecisionDatetime(Datetime(7, 0, 0, 0, 0, 10, 29, 2021, 0), 0),
289         HighPrecisionDatetime(Datetime(7, 0, 0, 0, 0, 10, 29, 2021, 0), 0),
290         HighPrecisionDatetime(Datetime(112, 9, 30, 0, 0, 1, 1, 1, 0), 0),
291         HighPrecisionDatetime(Datetime(112, 16, 30, 0, 0, 1, 1, 1, 0), 0),
292         HighPrecisionDatetime(Datetime(112, 20, 4, 0, 0, 1, 1, 1, 0), 0),
293         HighPrecisionDatetime(Datetime(240, 20, 4, 0, 0, 1, 1, 1, 0), 0),
294         HighPrecisionDatetime(Datetime(240, 12, 38, 48, 0, 1, 1, 1, 0), 0),
295         HighPrecisionDatetime(Datetime(240, 13, 5, 3, 0, 1, 1, 1, 0), 0),
296     ];
297 
298     foreach (test; tests)
299     {
300         import mir.ion.ser.ion;
301         import mir.ion.deser.ion;
302         auto ts = test.asTimestamp;
303         assert(ts.serializeIon.deserializeIon!Timestamp == ts);
304     }
305 }
306 
307 @safe pure // @nogc
308 validateBloombergErroCode()(
309     int errorCode,
310     string file = __FILE__,
311     size_t line = __LINE__)
312 {
313     import mir.ion.exception: IonException, IonMirException;
314     if (errorCode)
315     {
316         // static if (__traits(compiles, () @nogc { throw new Exception(""); }))
317         // {
318             ErrorInfo info;
319             getErrorInfo(info, errorCode);
320             throw new IonMirException(info.description, file, line);
321         // }
322         // else
323         // {
324         //     static immutable exc = new IonException("Exception thrown in bloomberg API: add DIP1008 for better error messages.");
325         //     throw exc;
326         // }
327     }
328 }
329 
330 @safe pure nothrow @nogc extern(System):
331 
332 alias getErrorInfo = blpapi_getErrorInfo;
333 int blpapi_getErrorInfo(scope ref ErrorInfo buffer, int errorCode);
334 
335 alias nameCreate = blpapi_Name_create;
336 Name* blpapi_Name_create(
337     scope const(char)* nameString);
338 
339 alias nameDestroy = blpapi_Name_destroy;
340 void blpapi_Name_destroy(
341     Name* name);
342 
343 alias nameDuplicate = blpapi_Name_duplicate;
344 Name* blpapi_Name_duplicate(
345     scope const Name* src);
346 
347 alias nameEqualsStr = blpapi_Name_equalsStr;
348 int blpapi_Name_equalsStr(
349     scope const Name* name,
350     const char *string);
351 
352 alias nameString = blpapi_Name_string;
353 const(char)* blpapi_Name_string(
354     scope const Name* name);
355 
356 alias nameLength = blpapi_Name_length;
357 size_t blpapi_Name_length(
358     scope const Name* name);
359 
360 alias nameFindName = blpapi_Name_findName;
361 Name* blpapi_Name_findName(
362     scope const(char)* nameString);
363 
364 int blpapi_Element_print(
365     const Element* element,
366     BloombergStreamWriter streamWriter,
367     void *stream,
368     int level,
369     int spacesPerLevel);
370 
371 alias print = blpapi_Element_print;
372 
373 alias name = blpapi_Element_name;
374 Name* blpapi_Element_name(const Element *element);
375 
376 alias nameString = blpapi_Element_nameString;
377 const(char)* blpapi_Element_nameString(const Element *element);
378 
379 alias datatype = blpapi_Element_datatype;
380 DataType blpapi_Element_datatype (
381     const(Element)* element);
382 
383 alias isComplexType = blpapi_Element_isComplexType;
384 int blpapi_Element_isComplexType(
385     const(Element)* element);
386 
387 alias isArray = blpapi_Element_isArray;
388 int blpapi_Element_isArray(
389     const(Element)* element);
390 
391 alias isReadOnly = blpapi_Element_isReadOnly;
392 int blpapi_Element_isReadOnly(
393     const(Element)* element);
394 
395 alias numValues = blpapi_Element_numValues;
396 size_t blpapi_Element_numValues(
397     const(Element)* element);
398 
399 alias numElements = blpapi_Element_numElements;
400 size_t blpapi_Element_numElements(
401     const(Element)* element);
402 
403 alias isNullValue = blpapi_Element_isNullValue;
404 int blpapi_Element_isNullValue(
405     const(Element)* element,
406     size_t position);
407 
408 alias isNull = blpapi_Element_isNull;
409 int blpapi_Element_isNull(
410     const(Element)* element);
411 
412 alias getElementAt = blpapi_Element_getElementAt;
413 int blpapi_Element_getElementAt(
414     const(Element)* element,
415     scope ref Element *result,
416     size_t position);
417 
418 alias getElement = blpapi_Element_getElement;
419 int blpapi_Element_getElement(
420     const Element *element,
421     scope ref Element *result,
422     const(char)* nameString,
423     const Name *name);
424 
425 alias hasElement = blpapi_Element_hasElement;
426 int blpapi_Element_hasElement(
427     const Element *element,
428     const(char)* nameString,
429     const Name *name);
430 
431 alias hasElementEx = blpapi_Element_hasElementEx;
432 int blpapi_Element_hasElementEx(
433     const Element *element,
434     const(char)* nameString,
435     const Name *name,
436     int excludeNullElements,
437     int reserved);
438 
439 alias getValueAsBool = blpapi_Element_getValueAsBool;
440 int blpapi_Element_getValueAsBool(
441     const Element *element,
442     scope ref Bool buffer,
443     size_t index);
444 
445 alias getValueAsChar = blpapi_Element_getValueAsChar;
446 int blpapi_Element_getValueAsChar(
447     const Element *element,
448     scope ref char buffer,
449     size_t index);
450 
451 alias getValueAsInt32 = blpapi_Element_getValueAsInt32;
452 int blpapi_Element_getValueAsInt32(
453     const Element *element,
454     scope ref int buffer,
455     size_t index);
456 
457 alias getValueAsInt64 = blpapi_Element_getValueAsInt64;
458 int blpapi_Element_getValueAsInt64(
459     const Element *element,
460     scope ref long buffer,
461     size_t index);
462 
463 alias getValueAsFloat32 = blpapi_Element_getValueAsFloat32;
464 int blpapi_Element_getValueAsFloat32(
465     const Element *element,
466     scope ref float buffer,
467     size_t index);
468 
469 alias getValueAsFloat64 = blpapi_Element_getValueAsFloat64;
470 int blpapi_Element_getValueAsFloat64(
471     const Element *element,
472     scope ref double buffer,
473     size_t index);
474 
475 alias getValueAsString = blpapi_Element_getValueAsString;
476 int blpapi_Element_getValueAsString(
477     const Element *element,
478     scope ref const char *buffer,
479     size_t index);
480 
481 alias getValueAsDatetime = blpapi_Element_getValueAsDatetime;
482 int blpapi_Element_getValueAsDatetime(
483     const Element *element,
484     scope ref Datetime buffer,
485     size_t index);
486 
487 alias getValueAsHighPrecisionDatetime = blpapi_Element_getValueAsHighPrecisionDatetime;
488 int blpapi_Element_getValueAsHighPrecisionDatetime(
489     const Element *element,
490     scope ref HighPrecisionDatetime buffer,
491     size_t index);
492 
493 alias getValueAsElement = blpapi_Element_getValueAsElement;
494 int blpapi_Element_getValueAsElement(
495     const Element *element,
496     scope ref Element *buffer,
497     size_t index);
498 
499 alias getValueAsName = blpapi_Element_getValueAsName;
500 int blpapi_Element_getValueAsName(
501     const Element *element,
502     scope Name* *buffer,
503     size_t index);
504 
505 alias getChoice = blpapi_Element_getChoice;
506 int blpapi_Element_getChoice(
507     const Element *element,
508     scope ref Element *result);
509 
510 alias setValueBool = blpapi_Element_setValueBool;
511 int blpapi_Element_setValueBool(
512     Element *element,
513     Bool value,
514     size_t index);
515 
516 alias setValueChar = blpapi_Element_setValueChar;
517 int blpapi_Element_setValueChar(
518     Element *element,
519     char value,
520     size_t index);
521 
522 alias setValueInt32 = blpapi_Element_setValueInt32;
523 int blpapi_Element_setValueInt32(
524     Element *element,
525     int value,
526     size_t index);
527 
528 alias setValueInt64 = blpapi_Element_setValueInt64;
529 int blpapi_Element_setValueInt64(
530     Element *element,
531     long value,
532     size_t index);
533 
534 alias setValueFloat32 = blpapi_Element_setValueFloat32;
535 int blpapi_Element_setValueFloat32(
536     Element *element,
537     float value,
538     size_t index);
539 
540 alias setValueFloat64 = blpapi_Element_setValueFloat64;
541 int blpapi_Element_setValueFloat64(
542     Element *element,
543     double value,
544     size_t index);
545 
546 alias setValueString = blpapi_Element_setValueString;
547 int blpapi_Element_setValueString(
548     Element *element,
549     const char *value,
550     size_t index);
551 
552 alias setValueDatetime = blpapi_Element_setValueDatetime;
553 int blpapi_Element_setValueDatetime(
554     Element *element,
555     scope ref const Datetime value,
556     size_t index);
557 
558 alias setValueHighPrecisionDatetime = blpapi_Element_setValueHighPrecisionDatetime;
559 int blpapi_Element_setValueHighPrecisionDatetime(
560     Element *element,
561     scope ref const HighPrecisionDatetime value,
562     size_t index);
563 
564 alias setValueFromElement = blpapi_Element_setValueFromElement;
565 int blpapi_Element_setValueFromElement(
566     Element *element,
567     Element *value,
568     size_t index);
569 
570 alias setValueFromName = blpapi_Element_setValueFromName;
571 int blpapi_Element_setValueFromName (
572     Element *element,
573     const Name *value,
574     size_t index);
575 
576 alias setElementBool = blpapi_Element_setElementBool;
577 int blpapi_Element_setElementBool(
578     Element *element,
579     const(char)* nameString,
580     const Name* name,
581     Bool value);
582 
583 alias setElementChar = blpapi_Element_setElementChar;
584 int blpapi_Element_setElementChar(
585     Element *element,
586     const(char)* nameString,
587     const Name* name,
588     char value);
589 
590 alias setElementInt32 = blpapi_Element_setElementInt32;
591 int blpapi_Element_setElementInt32(
592     Element *element,
593     const(char)* nameString,
594     const Name* name,
595     int value);
596 
597 alias setElementInt64 = blpapi_Element_setElementInt64;
598 int blpapi_Element_setElementInt64(
599     Element *element,
600     const(char)* nameString,
601     const Name* name,
602     long value);
603 
604 alias setElementFloat32 = blpapi_Element_setElementFloat32;
605 int blpapi_Element_setElementFloat32(
606     Element *element,
607     const(char)* nameString,
608     const Name* name,
609     float value);
610 
611 alias setElementFloat64 = blpapi_Element_setElementFloat64;
612 int blpapi_Element_setElementFloat64(
613     Element *element,
614     const(char)* nameString,
615     const Name* name,
616     double value);
617 
618 alias setElementString = blpapi_Element_setElementString;
619 int blpapi_Element_setElementString(
620     Element *element,
621     const char *nameString,
622     const Name* name,
623     const char *value);
624 
625 alias setElementDatetime = blpapi_Element_setElementDatetime;
626 int blpapi_Element_setElementDatetime(
627     Element *element,
628     const(char)* nameString,
629     const Name* name,
630     scope ref const Datetime value);
631 
632 alias setElementHighPrecisionDatetime = blpapi_Element_setElementHighPrecisionDatetime;
633 int blpapi_Element_setElementHighPrecisionDatetime(
634     Element *element,
635     const char *nameString,
636     const Name *name,
637     scope ref const HighPrecisionDatetime value);
638 
639 alias setElementFromField = blpapi_Element_setElementFromField;
640 int blpapi_Element_setElementFromField(
641     Element *element,
642     const(char)* nameString,
643     const Name* name,
644     Element *sourcebuffer);
645 
646 alias setElementFromName = blpapi_Element_setElementFromName;
647 int blpapi_Element_setElementFromName (
648     Element *element,
649     const(char)* elementName,
650     const Name* name,
651     const Name *buffer);
652 
653 alias appendElement = blpapi_Element_appendElement;
654 int blpapi_Element_appendElement (
655     Element *element,
656     scope ref Element *appendedElement);
657 
658 alias setChoice = blpapi_Element_setChoice;
659 int blpapi_Element_setChoice (
660     Element *element,
661     scope ref Element *resultElement,
662     const(char)* nameCstr,
663     const Name* name,
664     size_t index);